fix json export
This commit is contained in:
parent
01b30ccfb2
commit
b8eb3ce9ad
@ -6,12 +6,13 @@ Orchestrates the interaction between the GUI and the core processing logic.
|
|||||||
"""
|
"""
|
||||||
import multiprocessing as mp
|
import multiprocessing as mp
|
||||||
import csv
|
import csv
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Any, Dict, Tuple, Optional
|
from typing import List, Any, Dict, Tuple, Optional
|
||||||
from tkinter import filedialog
|
from tkinter import filedialog, messagebox
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
|
|
||||||
from ..utils.config_manager import ConfigManager
|
from ..utils.config_manager import ConfigManager
|
||||||
@ -46,10 +47,6 @@ def _get_value_from_path(batch: DataBatch, field: ExportField) -> Any:
|
|||||||
log.warning(f"Could not find attribute for path: {path}")
|
log.warning(f"Could not find attribute for path: {path}")
|
||||||
return "N/A"
|
return "N/A"
|
||||||
|
|
||||||
def _write_json_row(file_handle, row_dict: Dict[str, Any]):
|
|
||||||
# Helper to write a JSON object to a file, followed by a newline.
|
|
||||||
json.dump(row_dict, file_handle)
|
|
||||||
file_handle.write("\n")
|
|
||||||
|
|
||||||
class AppController:
|
class AppController:
|
||||||
"""The main controller of the application."""
|
"""The main controller of the application."""
|
||||||
@ -66,6 +63,9 @@ class AppController:
|
|||||||
self.output_file_handles: Dict[str, Any] = {}
|
self.output_file_handles: Dict[str, Any] = {}
|
||||||
self.csv_writers: Dict[str, Any] = {}
|
self.csv_writers: Dict[str, Any] = {}
|
||||||
|
|
||||||
|
# Buffer for JSON data
|
||||||
|
self.json_data_buffer: List[Dict[str, Any]] = []
|
||||||
|
|
||||||
self.last_generated_out_file: Optional[Path] = None
|
self.last_generated_out_file: Optional[Path] = None
|
||||||
|
|
||||||
def bind_view(self, view):
|
def bind_view(self, view):
|
||||||
@ -132,10 +132,13 @@ class AppController:
|
|||||||
self.output_file_handles.clear()
|
self.output_file_handles.clear()
|
||||||
self.csv_writers.clear()
|
self.csv_writers.clear()
|
||||||
self.active_export_profiles.clear()
|
self.active_export_profiles.clear()
|
||||||
|
self.json_data_buffer.clear() # Clear JSON buffer
|
||||||
|
|
||||||
try:
|
try:
|
||||||
output_dir = Path(self.view.out_output_dir_var.get())
|
output_dir = Path(self.view.out_output_dir_var.get())
|
||||||
basename = self.view.out_basename_var.get()
|
basename = self.view.out_basename_var.get()
|
||||||
profiles = self.config_manager.get_export_profiles()
|
profiles = self.config_manager.get_export_profiles()
|
||||||
|
|
||||||
if self.view.out_output_csv_var.get():
|
if self.view.out_output_csv_var.get():
|
||||||
profile = next((p for p in profiles if p.name == self.view.out_csv_profile_var.get()), None)
|
profile = next((p for p in profiles if p.name == self.view.out_csv_profile_var.get()), None)
|
||||||
if not profile: raise ValueError(f"CSV profile '{self.view.out_csv_profile_var.get()}' not found.")
|
if not profile: raise ValueError(f"CSV profile '{self.view.out_csv_profile_var.get()}' not found.")
|
||||||
@ -145,12 +148,13 @@ class AppController:
|
|||||||
self.output_file_handles["csv"] = fh
|
self.output_file_handles["csv"] = fh
|
||||||
self.csv_writers["csv"] = csv.writer(fh)
|
self.csv_writers["csv"] = csv.writer(fh)
|
||||||
self.csv_writers["csv"].writerow([f.column_name for f in profile.fields])
|
self.csv_writers["csv"].writerow([f.column_name for f in profile.fields])
|
||||||
|
|
||||||
if self.view.out_output_json_var.get():
|
if self.view.out_output_json_var.get():
|
||||||
profile = next((p for p in profiles if p.name == self.view.out_json_profile_var.get()), None)
|
profile = next((p for p in profiles if p.name == self.view.out_json_profile_var.get()), None)
|
||||||
if not profile: raise ValueError(f"JSON profile '{self.view.out_json_profile_var.get()}' not found.")
|
if not profile: raise ValueError(f"JSON profile '{self.view.out_json_profile_var.get()}' not found.")
|
||||||
self.active_export_profiles["json"] = profile
|
self.active_export_profiles["json"] = profile
|
||||||
path = (output_dir / basename).with_suffix(".json")
|
# JSON file is no longer opened here, it's written at the end.
|
||||||
self.output_file_handles["json"] = open(path, "w", encoding="utf-8")
|
|
||||||
return True
|
return True
|
||||||
except (IOError, ValueError) as e:
|
except (IOError, ValueError) as e:
|
||||||
log.error(f"Failed to prepare output files: {e}")
|
log.error(f"Failed to prepare output files: {e}")
|
||||||
@ -175,7 +179,6 @@ class AppController:
|
|||||||
self.config_manager.set("active_out_export_profile_name", self.view.out_csv_profile_var.get())
|
self.config_manager.set("active_out_export_profile_name", self.view.out_csv_profile_var.get())
|
||||||
self.config_manager.save_config()
|
self.config_manager.save_config()
|
||||||
|
|
||||||
# --- CORRECTED LINE ---
|
|
||||||
active_profile = self.active_export_profiles.get("csv") or self.active_export_profiles.get("json")
|
active_profile = self.active_export_profiles.get("csv") or self.active_export_profiles.get("json")
|
||||||
worker_args = (Path(filepath_str), self.command_queue, self.result_queue, active_profile)
|
worker_args = (Path(filepath_str), self.command_queue, self.result_queue, active_profile)
|
||||||
self._launch_worker(run_worker_process, worker_args)
|
self._launch_worker(run_worker_process, worker_args)
|
||||||
@ -213,7 +216,7 @@ class AppController:
|
|||||||
output_dir = self.view.rec_output_dir_var.get()
|
output_dir = self.view.rec_output_dir_var.get()
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
log.error(f"Configuration error: {e}")
|
log.error(f"Configuration error: {e}")
|
||||||
tk.messagebox.showerror("Configuration Error", str(e), parent=self.view)
|
messagebox.showerror("Configuration Error", str(e), parent=self.view)
|
||||||
return
|
return
|
||||||
|
|
||||||
self.is_processing = True
|
self.is_processing = True
|
||||||
@ -241,20 +244,42 @@ class AppController:
|
|||||||
self.csv_writers.clear()
|
self.csv_writers.clear()
|
||||||
|
|
||||||
def handle_data_batch(self, batch: DataBatch):
|
def handle_data_batch(self, batch: DataBatch):
|
||||||
"""Writes a data batch to the currently open output files (CSV/JSON)."""
|
"""Writes a data batch to CSV and buffers it for JSON."""
|
||||||
if self.csv_writers.get("csv"):
|
if self.csv_writers.get("csv"):
|
||||||
profile = self.active_export_profiles["csv"]
|
profile = self.active_export_profiles["csv"]
|
||||||
row_values = [_get_value_from_path(batch, field) for field in profile.fields]
|
row_values = [_get_value_from_path(batch, field) for field in profile.fields]
|
||||||
self.csv_writers["csv"].writerow(row_values)
|
self.csv_writers["csv"].writerow(row_values)
|
||||||
|
|
||||||
if self.output_file_handles.get("json"):
|
if "json" in self.active_export_profiles:
|
||||||
profile = self.active_export_profiles["json"]
|
profile = self.active_export_profiles["json"]
|
||||||
row_dict = {field.column_name: _get_value_from_path(batch, field) for field in profile.fields}
|
row_dict = {field.column_name: _get_value_from_path(batch, field) for field in profile.fields}
|
||||||
_write_json_row(self.output_file_handles["json"], row_dict)
|
self.json_data_buffer.append(row_dict)
|
||||||
|
|
||||||
if batch.batch_id % 20 == 0:
|
if batch.batch_id % 20 == 0:
|
||||||
for fh in self.output_file_handles.values():
|
if "csv" in self.output_file_handles:
|
||||||
fh.flush()
|
self.output_file_handles["csv"].flush()
|
||||||
|
|
||||||
|
def _write_json_buffer_to_file(self):
|
||||||
|
"""Writes the buffered JSON data to a file."""
|
||||||
|
if not self.json_data_buffer:
|
||||||
|
if "json" in self.active_export_profiles:
|
||||||
|
log.info("JSON export was enabled, but no data batches were generated. Skipping file creation.")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
output_dir = Path(self.view.out_output_dir_var.get())
|
||||||
|
basename = self.view.out_basename_var.get()
|
||||||
|
path = (output_dir / basename).with_suffix(".json")
|
||||||
|
|
||||||
|
log.info(f"Writing {len(self.json_data_buffer)} records to JSON file: {path}")
|
||||||
|
with open(path, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(self.json_data_buffer, f, indent=4)
|
||||||
|
log.info("JSON file written successfully.")
|
||||||
|
|
||||||
|
except (IOError, ValueError) as e:
|
||||||
|
log.error(f"Failed to write JSON output file: {e}")
|
||||||
|
finally:
|
||||||
|
self.json_data_buffer.clear()
|
||||||
|
|
||||||
def open_folder_from_path(self, folder_path_str: str):
|
def open_folder_from_path(self, folder_path_str: str):
|
||||||
if not folder_path_str: return
|
if not folder_path_str: return
|
||||||
@ -270,6 +295,11 @@ class AppController:
|
|||||||
def handle_worker_completion(self, msg: Dict[str, Any]):
|
def handle_worker_completion(self, msg: Dict[str, Any]):
|
||||||
status = "Interrupted" if msg.get("interrupted") else "Complete"
|
status = "Interrupted" if msg.get("interrupted") else "Complete"
|
||||||
log.info(f"--- Process {status}. ---")
|
log.info(f"--- Process {status}. ---")
|
||||||
|
|
||||||
|
# Write buffered JSON data before closing files
|
||||||
|
if self.view.out_output_json_var.get():
|
||||||
|
self._write_json_buffer_to_file()
|
||||||
|
|
||||||
self._close_all_files()
|
self._close_all_files()
|
||||||
self.is_processing = False
|
self.is_processing = False
|
||||||
self.worker_process = None
|
self.worker_process = None
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user