Fix: Code-Qualität und Effizienz verbessern (v1.5.1)
- main.py: print() durch logging ersetzt, cleanup nach Logger-Init verschoben - conf.py: funktionsloses global-Statement entfernt - database.py: unerreichbaren zweiten Projekt-Check entfernt - hash_calculation.py: deprecated _handle_xml_file_drop entfernt, nutzlosen _get_all_project_xml_files-Wrapper entfernt, seen_paths-Scope-Bug in rekursiver Traversierung behoben (O(N²) → O(N)), veraltete List[]-Syntax und ungenutzte Imports bereinigt - transform.py: TOCTOU-Muster (exists+stat) durch direktes stat() mit FileNotFoundError ersetzt; fop_conf.exists() gecacht Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -223,7 +223,6 @@ class AppSettings(BaseSettings):
|
||||
return (JsonConfigSettingsSource(settings_cls),)
|
||||
|
||||
def save(self):
|
||||
global config_path
|
||||
# Ordner existert nicht
|
||||
if not config_path.parent.exists():
|
||||
config_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
+5
-6
@@ -35,11 +35,10 @@ def cleanup_old_logs(log_dir, max_age_hours=24):
|
||||
log_file.unlink()
|
||||
deleted_count += 1
|
||||
except Exception as e:
|
||||
# Fehler beim Löschen ignorieren und fortfahren
|
||||
print(f"Fehler beim Löschen von {log_file}: {e}")
|
||||
logging.warning(f"Fehler beim Löschen von {log_file}: {e}")
|
||||
|
||||
if deleted_count > 0:
|
||||
print(f"{deleted_count} alte Log-Datei(en) gelöscht (älter als {max_age_hours} Stunden)")
|
||||
logging.info(f"{deleted_count} alte Log-Datei(en) gelöscht (älter als {max_age_hours} Stunden)")
|
||||
|
||||
|
||||
def main():
|
||||
@@ -53,9 +52,6 @@ def main():
|
||||
log_dir = config_path.parent / "logs"
|
||||
log_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Alte Log-Dateien aufräumen
|
||||
cleanup_old_logs(log_dir, max_age_hours=24)
|
||||
|
||||
# Log-Dateiname mit Timestamp
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
log_file = log_dir / f"documentor_{timestamp}.log"
|
||||
@@ -81,6 +77,9 @@ def main():
|
||||
|
||||
logging.info(f"Logging initialisiert: {log_file}")
|
||||
|
||||
# Alte Log-Dateien aufräumen (erst nach Logger-Init)
|
||||
cleanup_old_logs(log_dir, max_age_hours=24)
|
||||
|
||||
# QApplication-Instanz erstellen
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
|
||||
+6
-5
@@ -163,12 +163,12 @@ class TransformationJob:
|
||||
Returns:
|
||||
bool: True wenn New-PDF existiert und aktueller ist als alle Inputs
|
||||
"""
|
||||
if not self.new_pdf.exists():
|
||||
try:
|
||||
output_mtime = self.new_pdf.stat().st_mtime
|
||||
except FileNotFoundError:
|
||||
logger.debug(f"New-PDF existiert nicht: {self.new_pdf}")
|
||||
return False
|
||||
|
||||
output_mtime = self.new_pdf.stat().st_mtime
|
||||
|
||||
# Prüfe XML-Datei
|
||||
xml_abs = self.project_dir / self.xml_file
|
||||
if xml_abs.exists() and xml_abs.stat().st_mtime > output_mtime:
|
||||
@@ -384,10 +384,11 @@ class TransformationJob:
|
||||
# Fallback: Traditionelle subprocess-Methode (langsamer, aber robuster)
|
||||
|
||||
# Apache FOP Kommandozeile
|
||||
fop_conf_exists = self.fop_conf.exists()
|
||||
cmd_line = [
|
||||
str(self.fop_cmd),
|
||||
"-c",
|
||||
str(self.fop_conf) if self.fop_conf.exists() else "",
|
||||
str(self.fop_conf) if fop_conf_exists else "",
|
||||
"-r",
|
||||
"-fo",
|
||||
str(self.temp_fo),
|
||||
@@ -396,7 +397,7 @@ class TransformationJob:
|
||||
]
|
||||
|
||||
# Entferne leere Config-Parameter wenn fop.xconf nicht existiert
|
||||
if not self.fop_conf.exists():
|
||||
if not fop_conf_exists:
|
||||
cmd_line = [c for c in cmd_line if c not in ["-c", ""]]
|
||||
|
||||
logger.info(f"Starte Apache FOP PDF-Generierung: {self.xml_file.name}")
|
||||
|
||||
@@ -72,11 +72,6 @@ class DatabaseMixin:
|
||||
QMessageBox.warning(self, "Warnung", "Kein Projekt geladen. Bitte öffnen Sie zuerst ein Projekt.")
|
||||
return
|
||||
|
||||
# Hole das aktuelle Projekt aus app_settings
|
||||
if not self.project:
|
||||
QMessageBox.warning(self, "Warnung", "Aktuelles Projekt nicht in den Einstellungen gefunden.")
|
||||
return
|
||||
|
||||
# Hole die PostgreSQL-Datenbank-Konfiguration
|
||||
db_config = self._get_database_config(self.project.postgre_sql_db_id)
|
||||
if not db_config:
|
||||
|
||||
@@ -9,12 +9,8 @@ import shutil
|
||||
import time
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
from PySide6.QtWidgets import QMessageBox
|
||||
|
||||
from conf import TreeNode, XslFile, XmlFile
|
||||
from ui.XmlToXslAssignDialog import XmlToXslAssignDialog
|
||||
from ui.threads import XmlHashCalculatorThread
|
||||
from utils import calculate_blake2b_hash
|
||||
|
||||
@@ -33,49 +29,6 @@ class HashCalculationMixin:
|
||||
- self._load_nodes_to_tree(): Methode zum Laden der Nodes in den Tree
|
||||
"""
|
||||
|
||||
def _handle_xml_file_drop(self, xml_file_path: Path):
|
||||
"""
|
||||
Verarbeitet eine einzelne XML-Datei, die per Drag&Drop hinzugefügt wurde.
|
||||
DEPRECATED: Diese Methode wird durch _handle_multiple_xml_files_drop ersetzt.
|
||||
|
||||
Args:
|
||||
xml_file_path: Pfad zur XML-Datei
|
||||
"""
|
||||
try:
|
||||
logger.debug(f"Verarbeite XML-Datei: {xml_file_path}")
|
||||
|
||||
# Prüfe ob die Datei existiert
|
||||
if not xml_file_path.exists():
|
||||
QMessageBox.critical(self, "Fehler", f"Die XML-Datei existiert nicht:\n{xml_file_path}")
|
||||
return
|
||||
|
||||
# Prüfe ob Projekt-Nodes verfügbar sind
|
||||
if not self.pdf_project or not self.pdf_project.nodes:
|
||||
QMessageBox.warning(self, "Warnung", "Keine Projekt-Nodes verfügbar für die Zuordnung.")
|
||||
return
|
||||
|
||||
# Öffne den Dialog zur Zuordnung zu XSL-Knoten
|
||||
dialog = XmlToXslAssignDialog(
|
||||
parent=self, xml_file_path=xml_file_path, project_nodes=self.pdf_project.nodes
|
||||
)
|
||||
|
||||
if dialog.exec() == XmlToXslAssignDialog.DialogCode.Accepted:
|
||||
# Hole die ausgewählten XSL-Knoten
|
||||
selected_xsl_nodes = dialog.get_selected_xsl_nodes()
|
||||
|
||||
if selected_xsl_nodes:
|
||||
# Verarbeite die Zuordnung
|
||||
self._assign_xml_to_xsl_nodes(xml_file_path, selected_xsl_nodes)
|
||||
else:
|
||||
logger.warning("Keine XSL-Knoten ausgewählt")
|
||||
else:
|
||||
logger.debug("Dialog abgebrochen")
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Fehler beim Verarbeiten der XML-Datei '{xml_file_path}': {str(e)}"
|
||||
logger.error(error_msg)
|
||||
QMessageBox.critical(self, "Fehler", error_msg)
|
||||
|
||||
def _assign_xml_to_xsl_nodes(self, xml_file_path: Path, selected_xsl_nodes: list):
|
||||
"""
|
||||
Ordnet eine XML-Datei den ausgewählten XSL-Knoten zu.
|
||||
@@ -157,18 +110,19 @@ class HashCalculationMixin:
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler beim Starten der Hash-Berechnung: {e}")
|
||||
|
||||
def _collect_all_xml_files(self) -> List[XmlFile]:
|
||||
def _collect_all_xml_files(self) -> list[XmlFile]:
|
||||
"""
|
||||
Sammelt alle XmlFile-Objekte aus der Projektstruktur.
|
||||
|
||||
Returns:
|
||||
List[XmlFile]: Liste aller gefundenen XML-Dateien
|
||||
list[XmlFile]: Liste aller gefundenen XML-Dateien
|
||||
"""
|
||||
xml_files = []
|
||||
xml_files: list[XmlFile] = []
|
||||
seen_paths: set = set()
|
||||
|
||||
try:
|
||||
if self.pdf_project and self.pdf_project.nodes:
|
||||
self._collect_xml_files_recursive(self.pdf_project.nodes, xml_files)
|
||||
self._collect_xml_files_recursive(self.pdf_project.nodes, xml_files, seen_paths)
|
||||
|
||||
logger.debug(f"Gesammelt: {len(xml_files)} XML-Dateien")
|
||||
return xml_files
|
||||
@@ -177,15 +131,15 @@ class HashCalculationMixin:
|
||||
logger.error(f"Fehler beim Sammeln der XML-Dateien: {e}")
|
||||
return []
|
||||
|
||||
def _collect_xml_files_recursive(self, nodes, xml_files: List[XmlFile]):
|
||||
def _collect_xml_files_recursive(self, nodes, xml_files: list[XmlFile], seen_paths: set):
|
||||
"""
|
||||
Sammelt rekursiv alle XML-Dateien aus den Nodes.
|
||||
|
||||
Args:
|
||||
nodes: Liste der zu durchsuchenden Nodes
|
||||
xml_files: Liste zum Sammeln der XML-Dateien
|
||||
seen_paths: Set bereits gesehener Pfade (verhindert Duplikate)
|
||||
"""
|
||||
seen_paths = {xf.xml for xf in xml_files}
|
||||
for node in nodes:
|
||||
if isinstance(node, XslFile) and node.xmls:
|
||||
for xml_file in node.xmls:
|
||||
@@ -193,7 +147,7 @@ class HashCalculationMixin:
|
||||
xml_files.append(xml_file)
|
||||
seen_paths.add(xml_file.xml)
|
||||
elif isinstance(node, TreeNode) and node.children:
|
||||
self._collect_xml_files_recursive(node.children, xml_files)
|
||||
self._collect_xml_files_recursive(node.children, xml_files, seen_paths)
|
||||
|
||||
def _on_hash_calculated(self, xml_file: XmlFile, hash_value: str):
|
||||
"""
|
||||
@@ -266,10 +220,6 @@ class HashCalculationMixin:
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler beim Berechnen des Hash für {xml_file.xml}: {e}")
|
||||
|
||||
def _get_all_project_xml_files(self) -> List[XmlFile]:
|
||||
"""Sammelt alle XmlFile-Objekte aus dem gesamten Projekt."""
|
||||
return self._collect_all_xml_files()
|
||||
|
||||
def _find_xml_file_by_hash(self, target_hash: str) -> XmlFile | None:
|
||||
"""
|
||||
Sucht eine XML-Datei mit dem angegebenen Hash im gesamten Projekt.
|
||||
@@ -284,7 +234,7 @@ class HashCalculationMixin:
|
||||
if not target_hash:
|
||||
return None
|
||||
|
||||
all_xml_files = self._get_all_project_xml_files()
|
||||
all_xml_files = self._collect_all_xml_files()
|
||||
|
||||
for xml_file in all_xml_files:
|
||||
if xml_file.hashsum == target_hash:
|
||||
@@ -314,7 +264,7 @@ class HashCalculationMixin:
|
||||
extension = original_path.suffix # ".xml"
|
||||
|
||||
# Sammle einmalig alle verwendeten Dateinamen (Performance-Optimierung)
|
||||
all_xml_files = self._get_all_project_xml_files()
|
||||
all_xml_files = self._collect_all_xml_files()
|
||||
used_names = {xml_file.xml.name for xml_file in all_xml_files}
|
||||
|
||||
counter = 1
|
||||
@@ -351,7 +301,7 @@ class HashCalculationMixin:
|
||||
bool: True wenn der Dateiname bereits verwendet wird
|
||||
"""
|
||||
try:
|
||||
all_xml_files = self._get_all_project_xml_files()
|
||||
all_xml_files = self._collect_all_xml_files()
|
||||
|
||||
for xml_file in all_xml_files:
|
||||
if xml_file.xml == relative_xml_path:
|
||||
@@ -508,7 +458,7 @@ class HashCalculationMixin:
|
||||
logger.error(error_msg)
|
||||
return {"status": "error", "error_msg": error_msg}
|
||||
|
||||
def _show_filename_selection_dialog(self, original_name: str, alternative_paths: List[Path]) -> Path | None:
|
||||
def _show_filename_selection_dialog(self, original_name: str, alternative_paths: list[Path]) -> Path | None:
|
||||
"""
|
||||
Zeigt einen Dialog zur Auswahl eines alternativen Dateinamens.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user