From 9000164b6e52a912efcd2a6dcdd966f2e2207f3e Mon Sep 17 00:00:00 2001 From: lertlmaier Date: Thu, 24 Jul 2025 09:45:03 +0200 Subject: [PATCH] =?UTF-8?q?DocStrings=20bei=20"komplexeren"=20Methoden=20h?= =?UTF-8?q?inzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/drawdxf.py | 162 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 150 insertions(+), 12 deletions(-) diff --git a/lib/drawdxf.py b/lib/drawdxf.py index a623a8b..a20311a 100644 --- a/lib/drawdxf.py +++ b/lib/drawdxf.py @@ -75,7 +75,12 @@ def add_polyline(msp, points:Polyline, dxf_attribs): pline.rgb = (255, 128, 0) def new_dxf(plines, out_path): - """ creates a new dxf file with a polyline inside which is created by the given json file + """ + Erstellt eine neue DXF-Datei mit den gegebenen Polylinien und speichert sie unter dem angegebenen Pfad. + + Args: + plines (Polylines): Die Polylinien- und Geometriedaten, die gezeichnet werden sollen. + out_path (str): Der Pfad, unter dem die neue DXF-Datei gespeichert wird. """ doc = ezdxf.new('R2018', setup=True) draw_cables(plines, doc) @@ -87,7 +92,12 @@ def new_dxf(plines, out_path): print("Cable-Routes exported to new dxf-file") def modify_original_dxf(plines, originaldxf): - """ adds new layer to original .dxf-file that contains cables + """ + Fügt einer bestehenden DXF-Datei einen neuen Layer mit Kabeln hinzu und speichert das Ergebnis. + + Args: + plines (Polylines): Die Polylinien- und Geometriedaten, die gezeichnet werden sollen. + originaldxf (str): Pfad zur bestehenden DXF-Datei, die modifiziert werden soll. """ print("adding cables into original .dxf ..") @@ -99,6 +109,13 @@ def modify_original_dxf(plines, originaldxf): def draw_cables(plines, doc): + """ + Zeichnet alle Kabel-Polylinien in das DXF-Dokument auf einen eigenen Layer. + + Args: + plines (Polylines): Die Polylinien- und Geometriedaten. + doc (ezdxf.document.Drawing): Das zu bearbeitende DXF-Dokument. + """ msp = doc.modelspace() timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M") cable_layer = f"cables_{timestamp}" @@ -115,6 +132,13 @@ def draw_cables(plines, doc): add_polyline(msp, pl, dxfattribs_cable) def draw_racks(plines, doc): + """ + Zeichnet die Racks als 3D-Polylinien und platziert Rack-Namen als Text im DXF-Dokument. + + Args: + plines (Polylines): Die Polylinien- und Geometriedaten. + doc (ezdxf.document.Drawing): Das zu bearbeitende DXF-Dokument. + """ msp = doc.modelspace() timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M") rack_layer = f"racks_{timestamp}" @@ -185,6 +209,13 @@ def find_close_key(pos2sensors, x, y, tolerance=10): # !!! Toleranz nicht return None def draw_sensors(plines, doc): + """ + Zeichnet die Sensoren als Textobjekte an den Endpunkten der Kabel und gruppiert sie ggf. gestaffelt. + + Args: + plines (Polylines): Die Polylinien- und Geometriedaten. + doc (ezdxf.document.Drawing): Das zu bearbeitende DXF-Dokument. + """ msp = doc.modelspace() timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M") sensor_layer = f"sensors_{timestamp}" @@ -219,6 +250,13 @@ def draw_sensors(plines, doc): text.set_placement(placement_info["placement"]) def draw_subdists(plines, doc): + """ + Zeichnet die Unterverteiler (Subdistributoren) als Textobjekte an den Startpunkten der Kabel. + + Args: + plines (Polylines): Die Polylinien- und Geometriedaten. + doc (ezdxf.document.Drawing): Das zu bearbeitende DXF-Dokument. + """ msp = doc.modelspace() timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M") subdist_layer = f"subdists_{timestamp}" @@ -296,6 +334,15 @@ def _calculate_text_placement(pt1, pt2, text_type='sensor', item_index=0, total_ } def model_from_json(json_file): + """ + Lädt die Polylinien- und Geometriedaten aus einer JSON-Datei und gibt ein Polylines-Objekt zurück. + + Args: + json_file (str): Pfad zur JSON-Datei. + + Returns: + Polylines: Das geladene Polylinien-Objekt. + """ with open(json_file, encoding='utf-8') as fh: data = json.load(fh) @@ -306,6 +353,15 @@ def model_from_json(json_file): return plines def parse_sensors_from_json(positions_json): + """ + Liest Sensordaten aus einer JSON-Datei und gibt ein Dictionary mit Sensorobjekten zurück. + + Args: + positions_json (str): Pfad zur JSON-Datei mit Sensorpositionen. + + Returns: + dict: Dictionary mit Sensorname als Key und Sensorobjekt als Value. + """ with open(positions_json, encoding='utf-8') as fh: data = json.load(fh) @@ -320,6 +376,16 @@ def parse_sensors_from_json(positions_json): return sensors def get_all_artnrs(plines: Polylines, sens2cable: dict) -> set: + """ + Sammelt alle verwendeten Artikelnummern aus den Polylinien und der Sensor-Kabel-Zuordnung. + + Args: + plines (Polylines): Die Polylinien- und Geometriedaten. + sens2cable (dict): Mapping von Sensor-IDs zu Kabel-Artikelnummern. + + Returns: + set: Menge aller gefundenen Artikelnummern. + """ all_artnrs = set() for pl in plines.kabel: if pl.s_artinr: @@ -332,6 +398,12 @@ def get_all_artnrs(plines: Polylines, sens2cable: dict) -> set: return all_artnrs def mark_missings(all_artnrs): + """ + Markiert fehlende Artikelnummern im Bezeichner-Config, falls sie nicht vorhanden sind. + + Args: + all_artnrs (set): Menge aller verwendeten Artikelnummern. + """ if "Sivasnummern" not in bezeichner_cfg: bezeichner_cfg["Sivasnummern"] = {} if "Missing" not in bezeichner_cfg: @@ -343,7 +415,13 @@ def mark_missings(all_artnrs): def write_excel_from_json(plines: Polylines, sens2cable: dict, outpath: str, with_bom=True): """ - Steuert die Erstellung der Excel-Reports (Kabelübersicht und Stückliste). + Erstellt Excel-Reports (Kabelübersicht, Fehlerlisten, Stückliste) aus den Polylinien- und Zuordnungsdaten. + + Args: + plines (Polylines): Die Polylinien- und Geometriedaten. + sens2cable (dict): Mapping von Sensor-IDs zu Kabel-Artikelnummern. + outpath (str): Pfad zur Ausgabedatei. + with_bom (bool, optional): Ob zusätzlich eine Stückliste (BOM) erzeugt werden soll. Default: True. """ # 1. Daten aggregieren und für die Reports vorbereiten processed_data = _process_cable_data(plines, sens2cable) @@ -375,8 +453,14 @@ def _get_sivas_name(artnr, bezeichner_cfg): def _process_cable_data(plines: Polylines, sens2cable: dict): """ - Verarbeitet die Kabeldaten und aggregiert sie für die Excel-Ausgabe. - Gibt mehrere Dictionaries mit zusammengefassten Daten zurück. + Aggregiert und bereitet die Kabeldaten für die Excel-Ausgabe auf. + + Args: + plines (Polylines): Die Polylinien- und Geometriedaten. + sens2cable (dict): Mapping von Sensor-IDs zu Kabel-Artikelnummern. + + Returns: + dict: Verschiedene aggregierte Auswertungen für die Excel-Ausgabe. """ # Globale Zusammenfassungen artnr_to_stückware_count = defaultdict(int) @@ -430,7 +514,15 @@ def _process_cable_data(plines: Polylines, sens2cable: dict): } def _create_cable_list_sheet(ws, plines, sens2cable, bezeichner_cfg): - """Erstellt das Arbeitsblatt 'Length by ID'.""" + """ + Erstellt das Arbeitsblatt 'Length by ID' mit allen Kabeln und deren Längen. + + Args: + ws (Worksheet): Das Excel-Arbeitsblatt. + plines (Polylines): Die Polylinien- und Geometriedaten. + sens2cable (dict): Mapping von Sensor-IDs zu Kabel-Artikelnummern. + bezeichner_cfg (ConfigParser): Konfiguration mit Artikelnummern-Namen. + """ ws.title = "Length by ID" ws.append(["Cable-ID", "True Length (m)", "Cable-ArtNr", "Cable-Name (short)"]) ws.column_dimensions['A'].width = 18 @@ -445,7 +537,13 @@ def _create_cable_list_sheet(ws, plines, sens2cable, bezeichner_cfg): ws.append([pl.id, length, artnr, cable_name]) def _create_cable_summary_sheet(ws, processed_data): - """Erstellt das Arbeitsblatt 'Cables SIVAS'.""" + """ + Erstellt das Arbeitsblatt 'Cables SIVAS' mit einer Zusammenfassung der Kabel nach Artikelnummer. + + Args: + ws (Worksheet): Das Excel-Arbeitsblatt. + processed_data (dict): Aggregierte Kabeldaten. + """ ws.title = "Cables SIVAS" ws.append(["Cable-ArtNr", "Amount (pcs)", "Cumm. Length (m)"]) ws.column_dimensions['A'].width = 20 @@ -464,7 +562,13 @@ def _create_cable_summary_sheet(ws, processed_data): ]) def _create_rack_lengths_sheet(ws, plines): - """Erstellt das Arbeitsblatt 'Rack-Lengths'.""" + """ + Erstellt das Arbeitsblatt 'Rack-Lengths' mit den Längen der Racks. + + Args: + ws (Worksheet): Das Excel-Arbeitsblatt. + plines (Polylines): Die Polylinien- und Geometriedaten. + """ ws.title = "Rack-Lengths" ws.append(["Rack-ID", "Length (m)"]) ws.column_dimensions['A'].width = 18 @@ -478,7 +582,13 @@ def _create_rack_lengths_sheet(ws, plines): ws.append([rackname, rack_geom.length]) def _create_error_sheets(wb, plines): - """Erstellt die Arbeitsblätter für alle aufgetretenen Fehler.""" + """ + Erstellt die Arbeitsblätter für alle aufgetretenen Fehler (Equipment-Connection, Routing, Attribute). + + Args: + wb (Workbook): Das Excel-Workbook. + plines (Polylines): Die Polylinien- und Geometriedaten. + """ # Sheet: ERR-Equipment-Connection if plines.errors_sensors or plines.errors_dists: ws = wb.create_sheet("ERR-Equipment-Connection") @@ -519,7 +629,14 @@ def _create_error_sheets(wb, plines): ws.append([sname, err_msg]) def _create_bom_workbook(outpath, processed_data, bezeichner_cfg): - """Erstellt eine separate Excel-Arbeitsmappe für die Stückliste (BOM).""" + """ + Erstellt eine separate Excel-Arbeitsmappe für die Stückliste (BOM) und speichert sie ab. + + Args: + outpath (str): Basis-Pfad für die Ausgabedatei. + processed_data (dict): Aggregierte Kabel- und Sensor-Daten. + bezeichner_cfg (ConfigParser): Konfiguration mit Artikelnummern-Namen. + """ wb = Workbook() # Daten aus dem verarbeiteten Dictionary extrahieren @@ -599,6 +716,13 @@ def check_file_in_work(work_dir, filename): return (mypath, fexists) def copy_layers_into_dxf_by_filter(dxf_source: ezdxf.document.Drawing, dxf_target:ezdxf.document.Drawing): + """ + Kopiert bestimmte Layer (nach Filter) von einer Quell-DXF in eine Ziel-DXF. + + Args: + dxf_source (ezdxf.document.Drawing): Quell-DXF-Dokument. + dxf_target (ezdxf.document.Drawing): Ziel-DXF-Dokument. + """ msp_source = dxf_source.modelspace() msp_target = dxf_target.modelspace() @@ -658,8 +782,13 @@ def copy_layers_into_dxf_by_filter(dxf_source: ezdxf.document.Drawing, dxf_targe def get_cable_artnr(section, length): """ Sucht in der angegebenen Config-Section die passende Kabel-Artikelnr. für die gegebene Länge. - Übergibt bei Treffer True, artnr - bei Fehler: False, errmsg + + Args: + section (str): Name der Kabel-Section in der Config. + length (float): Kabellänge in Metern. + + Returns: + tuple: (True, artnr) bei Erfolg, (False, Fehlermeldung) bei Fehler. """ # Existiert über BMK vergebene Kabel-Kennzeichnung in kabel.cfg? if section not in cable_cfg: @@ -675,6 +804,15 @@ def get_cable_artnr(section, length): return False, f"Kabel länger als max. Kabellänge in Sektion '{section}'" def map_sensor_to_cable_cfg(plines): + """ + Ordnet jedem Sensor/Kabel die passende Kabel-Artikelnummer gemäß BMK-Config und Kabel-Config zu. + + Args: + plines (Polylines): Die Polylinien- und Geometriedaten. + + Returns: + dict: Mapping von Kabel-IDs zu Artikelnummern. + """ sens2cable = defaultdict(list) mapping = config_BMK["Cable-Mapping"]