From aa8f67e27b9a33eef02280691a89633c16a19299 Mon Sep 17 00:00:00 2001 From: lertlmaier Date: Thu, 3 Jul 2025 11:31:12 +0200 Subject: [PATCH] =?UTF-8?q?Anpassen=20aller=20Funktionen=20sodass=20Doppel?= =?UTF-8?q?te=20nun=20nu=20einmal=20in=20tats=C3=A4chlicher=20Ausgabe=20er?= =?UTF-8?q?scheinen=20und=20doppelte=20ebenfalls=20nur=20einmal=20in=20daf?= =?UTF-8?q?=C3=BCr=20vorgesehener=20ausgabe=20erscheinen.=20Hinweis=20spal?= =?UTF-8?q?te=20erg=C3=A4nzt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/portalexport.py | 223 +++++++++++++++++++++++++++----------------- 1 file changed, 135 insertions(+), 88 deletions(-) diff --git a/lib/portalexport.py b/lib/portalexport.py index cd839d2..4e40fd1 100644 --- a/lib/portalexport.py +++ b/lib/portalexport.py @@ -19,7 +19,7 @@ class ExcelConverter: gesamt_pfad_ziel_datei = os.path.join(pfad_ziel_datei, eingestellter_name.replace("[Ursprungsdatei]", name_ursprungsdatei_kurz) + ".xlsx") return gesamt_pfad_ziel_datei - def _gleiche_finden(self, zu_ueberpruefen): + def _gleiche_finden_old(self, zu_ueberpruefen): """ Findet doppelte Einträge basierend auf dem 'Name'-Feld. Entspricht der PowerShell-Funktion GleicheFinden. @@ -35,6 +35,15 @@ class ExcelConverter: return gleiche + def _gleiche_finden(self, liste): + counter = {} + for eintrag in liste: + name = eintrag['Name'] + counter[name] = counter.get(name, 0) + 1 + doppelte = set(name for name, count in counter.items() if count > 1) + doppelte_eintraege = [eintrag for eintrag in liste if eintrag['Name'] in doppelte] + return doppelte_eintraege, doppelte + def _anschluesse_ergaenzen_old(self, anschluesse): """ Ergänzt fehlende Anschlüsse für Bauteile. @@ -109,6 +118,45 @@ class ExcelConverter: anschluesse.extend(added_entries) return sorted(anschluesse, key=lambda x: x['Name']) + def _verarbeite_io_liste(self, liste): + """ + Filtert doppelte Namen aus der Liste und markiert sie mit Hinweis; gibt separate Liste mit eindeutigen Duplikaten zurück. + """ + gleiche, doppelte_namen = self._gleiche_finden(liste) + + # Nur ein Eintrag pro doppeltem Namen in gleiche_liste + gesehen = set() + reduzierte_gleiche = [] + for eintrag in gleiche: + name = eintrag['Name'] + if name not in gesehen: + reduzierte_gleiche.append(eintrag) + gesehen.add(name) + + gefiltert = self._duplikate_markieren_und_filtern(liste, doppelte_namen) + return reduzierte_gleiche, gefiltert + + def _duplikate_markieren_und_filtern(self, liste, doppelte_namen): + """ + Behalte nur das erste Vorkommen jedes doppelten Namens in der Liste. + Markiere dieses Vorkommen mit 'Hinweis': 'Doppelt'. + """ + neue_liste = [] + gesehen = set() + + for eintrag in liste: + name = eintrag['Name'] + if name in doppelte_namen: + if name not in gesehen: + eintrag['Hinweis'] = "Duplikat!" + neue_liste.append(eintrag) + gesehen.add(name) + # sonst: ignorieren + else: + neue_liste.append(eintrag) + + return neue_liste + def excel_datei_beschreiben_simpel(self, ursprungdatei, prefix_eingang, prefix_ausgang): """ Konvertiert Daten aus der Ursprungsdatei und schreibt sie in eine einfache Excel-Datei. @@ -140,33 +188,26 @@ class ExcelConverter: name = bmk_formatted fehler.append({'Name': name, 'Kommentar': kommentar, 'Zeile': i}) - df_fehler = pd.DataFrame(fehler) - if not df_fehler.empty: - df_fehler.sort_values(by="Name") + # Fehler-Dataframe erzeugen + df_fehler = pd.DataFrame(fehler).sort_values(by="Name") if fehler else pd.DataFrame() - - gleiche_eingaenge = self._gleiche_finden(eingaenge) - gleiche_ausgaenge = self._gleiche_finden(ausgaenge) - - df_gleiche_eingaenge = pd.DataFrame(gleiche_eingaenge) - if not df_gleiche_eingaenge.empty: - df_gleiche_eingaenge.sort_values(by="Name") - - df_gleiche_ausgaenge = pd.DataFrame(gleiche_ausgaenge) - if not df_gleiche_ausgaenge.empty: - df_gleiche_ausgaenge.sort_values(by="Name") - + # Eingänge & Ausgänge verarbeiten (Duplikate markieren und filtern) + gleiche_eingaenge, eingaenge = self._verarbeite_io_liste(eingaenge) + gleiche_ausgaenge, ausgaenge = self._verarbeite_io_liste(ausgaenge) + # DataFrames erzeugen u. sortieren df_eingaenge = pd.DataFrame(eingaenge).sort_values(by="Name") df_ausgaenge = pd.DataFrame(ausgaenge).sort_values(by="Name") + df_gleiche_eingaenge = pd.DataFrame(gleiche_eingaenge).sort_values(by="Name") if gleiche_eingaenge else pd.DataFrame() + df_gleiche_ausgaenge = pd.DataFrame(gleiche_ausgaenge).sort_values(by="Name") if gleiche_ausgaenge else pd.DataFrame() return df_gleiche_eingaenge, df_gleiche_ausgaenge, df_fehler, df_eingaenge, df_ausgaenge def excel_datei_beschreiben_tia(self, ursprungdatei, prefix_eingang, prefix_ausgang): """ Konvertiert Daten für TIA Portal und schreibt sie in eine Excel-Datei mit zwei Blättern ("Constants" und "PLC Tags"). - Eingänge und Ausgänge gemeinsam jeweils in consts und tags; Fehler ebenfalls mit Prefix 'Err' enthalten. + Eingänge und Ausgänge gemeinsam jeweils in consts und tags (Prefix cIn, cOut); doppelte Namen markiert und ausgeschlossen; Fehler mit Prefix 'Err'. """ eingaenge = [] ausgaenge = [] @@ -218,24 +259,20 @@ class ExcelConverter: 'Zeile': i }) - df_fehler = pd.DataFrame(fehler) - if not df_fehler.empty: - df_fehler.sort_values(by="Zahl") + # Fehler-Dataframe erzeugen + df_fehler = pd.DataFrame(fehler).sort_values(by="Zahl") if fehler else pd.DataFrame() - gleiche_eingaenge = self._gleiche_finden(eingaenge) - gleiche_ausgaenge = self._gleiche_finden(ausgaenge) - - df_gleiche_eingaenge = pd.DataFrame(gleiche_eingaenge) - if not df_gleiche_eingaenge.empty: - df_gleiche_eingaenge.sort_values(by="Zahl") - - df_gleiche_ausgaenge = pd.DataFrame(gleiche_ausgaenge) - if not df_gleiche_ausgaenge.empty: - df_gleiche_ausgaenge.sort_values(by="Zahl") - + # Duplikate verarbeiten & markieren + gleiche_eingaenge, eingaenge = self._verarbeite_io_liste(eingaenge) + gleiche_ausgaenge, ausgaenge = self._verarbeite_io_liste(ausgaenge) + + # DataFrames erstellen u. sortieren df_eingaenge = pd.DataFrame(eingaenge).sort_values(by="Zahl") df_ausgaenge = pd.DataFrame(ausgaenge).sort_values(by="Zahl") + df_gleiche_eingaenge = pd.DataFrame(gleiche_eingaenge).sort_values(by="Zahl") if gleiche_eingaenge else pd.DataFrame() + df_gleiche_ausgaenge = pd.DataFrame(gleiche_ausgaenge).sort_values(by="Zahl") if gleiche_ausgaenge else pd.DataFrame() + df_consts, df_tags = self.create_tia_dataframes(df_fehler, df_eingaenge, df_ausgaenge) return df_gleiche_eingaenge, df_gleiche_ausgaenge, df_fehler, df_consts, df_tags @@ -365,24 +402,20 @@ class ExcelConverter: eingaenge = self._anschluesse_ergaenzen(eingaenge) ausgaenge = self._anschluesse_ergaenzen(ausgaenge) - df_fehler = pd.DataFrame(fehler) - if not df_fehler.empty: - df_fehler.sort_values(by="Name") + # Fehler-Dataframe erzeugen + df_fehler = pd.DataFrame(fehler).sort_values(by="Name") if fehler else pd.DataFrame() - gleiche_eingaenge = self._gleiche_finden(eingaenge) - gleiche_ausgaenge = self._gleiche_finden(ausgaenge) - - df_gleiche_eingaenge = pd.DataFrame(gleiche_eingaenge) - if not df_gleiche_eingaenge.empty: - df_gleiche_eingaenge.sort_values(by="Name") - - df_gleiche_ausgaenge = pd.DataFrame(gleiche_ausgaenge) - if not df_gleiche_ausgaenge.empty: - df_gleiche_ausgaenge.sort_values(by="Name") - + # Duplikate verarbeiten & markieren + gleiche_eingaenge, eingaenge = self._verarbeite_io_liste(eingaenge) + gleiche_ausgaenge, ausgaenge = self._verarbeite_io_liste(ausgaenge) + + # DataFrames erzeugen u. sortieren df_eingaenge = pd.DataFrame(eingaenge).sort_values(by="Name") df_ausgaenge = pd.DataFrame(ausgaenge).sort_values(by="Name") + df_gleiche_eingaenge = pd.DataFrame(gleiche_eingaenge).sort_values(by="Name") if gleiche_eingaenge else pd.DataFrame() + df_gleiche_ausgaenge = pd.DataFrame(gleiche_ausgaenge).sort_values(by="Name") if gleiche_ausgaenge else pd.DataFrame() + return df_gleiche_eingaenge, df_gleiche_ausgaenge, df_fehler, df_eingaenge, df_ausgaenge def excel_datei_beschreiben_wscad_bezug(self, ursprungdatei, prefix_eingang, prefix_ausgang): @@ -430,24 +463,20 @@ class ExcelConverter: eingaenge = self._anschluesse_ergaenzen(eingaenge) ausgaenge = self._anschluesse_ergaenzen(ausgaenge) - df_fehler = pd.DataFrame(fehler) - if not df_fehler.empty: - df_fehler.sort_values(by="Name") + # Fehler-Dataframe erzeugen + df_fehler = pd.DataFrame(fehler).sort_values(by="Name") if fehler else pd.DataFrame() - gleiche_eingaenge = self._gleiche_finden(eingaenge) - gleiche_ausgaenge = self._gleiche_finden(ausgaenge) - - df_gleiche_eingaenge = pd.DataFrame(gleiche_eingaenge) - if not df_gleiche_eingaenge.empty: - df_gleiche_eingaenge.sort_values(by="Name") - - df_gleiche_ausgaenge = pd.DataFrame(gleiche_ausgaenge) - if not df_gleiche_ausgaenge.empty: - df_gleiche_ausgaenge.sort_values(by="Name") - + # Duplikate verarbeiten & markieren + gleiche_eingaenge, eingaenge = self._verarbeite_io_liste(eingaenge) + gleiche_ausgaenge, ausgaenge = self._verarbeite_io_liste(ausgaenge) + + # DataFrames erzeugen u. sortieren df_eingaenge = pd.DataFrame(eingaenge).sort_values(by="Name") df_ausgaenge = pd.DataFrame(ausgaenge).sort_values(by="Name") + df_gleiche_eingaenge = pd.DataFrame(gleiche_eingaenge).sort_values(by="Name") if gleiche_eingaenge else pd.DataFrame() + df_gleiche_ausgaenge = pd.DataFrame(gleiche_ausgaenge).sort_values(by="Name") if gleiche_ausgaenge else pd.DataFrame() + return df_gleiche_eingaenge, df_gleiche_ausgaenge, df_fehler, df_eingaenge, df_ausgaenge class IOConverterApp: @@ -1023,18 +1052,24 @@ class TestPlant(unittest.TestCase): """ textarray = textlines.splitlines() + '''Testcase: 10 Zeilen mit I/O: Davon 4 Eingänge (1 Duplikat), 5 Ausgänge (1 Duplikat), 1 Fehlerhafte BMK''' + df_gleiche_eingaenge, df_gleiche_ausgaenge, df_fehler, df_eingaenge, df_ausgaenge = call_portal_to_excel(self, textarray, "Simpel") - #print(df_gleiche_eingaenge) - #print(df_ausgaenge) + # print("\n Eingänge:\n") + # print(df_eingaenge) + # print("\n Ausgänge:\n") + # print(df_ausgaenge) - #self.assertIn("DI0020", df_gleiche_eingaenge["Name"].values) # Püfen, ob doppelter Name in doppelteEingänge auftaucht - #self.assertIn("MA1020", df_gleiche_ausgaenge["Name"].values) # Püfen, ob doppelter Name in doppelteAusgänge auftaucht - self.assertEqual(len(df_fehler), 1) # Fehler anzeigen: Zeile 4 Prefix XY + # print("\n gleiche Eingänge:\n") + # print(df_gleiche_eingaenge) + # print("\n gleiche Ausgänge:\n") + # print(df_gleiche_ausgaenge) - self.assertEqual(len(df_eingaenge), 4) # Eigentlich 10 Zeilen lang, aber da Fehler nur 4 Eingänge - self.assertEqual(len(df_ausgaenge), 5) # 5 Ausgänge in Liste + self.assertEqual(len(df_fehler), 1) # Fehler anzeigen: Zeile 4 Prefix XY + self.assertEqual(len(df_eingaenge), 4 - len(df_gleiche_eingaenge)) # 4 Eingänge in Liste, einer davon als Duplikat + self.assertEqual(len(df_ausgaenge), 5 - len(df_gleiche_ausgaenge)) # 5 Ausgänge in Liste, einer davon Duplikat def test_TIA(self): textlines = """'DI0023','STEUERSPANNUNG 24V UC200 OK','24V OK','=A01+UH000-KF02i','STEUERSPANNUNG 24V UC200 OK','CONTROL VOLTAGE 24V UC200 OK','TENSION DE MANIOBRA 24V UC200 OK','' @@ -1049,16 +1084,29 @@ class TestPlant(unittest.TestCase): 'MA1020','ANTRIEB PUFFER F0101 FLYER 1','M-BI-LE','=A01+UC101-KF02Q','','','','' """ textarray = textlines.splitlines() - + + '''Testcase: 10 Zeilen mit I/O: Davon 4 Eingänge (1 Duplikat), 5 Ausgänge (1 Duplikat), 1 Fehlerhafte BMK''' + df_gleiche_eingaenge, df_gleiche_ausgaenge, df_fehler, df_consts, df_tags = call_portal_to_excel(self, textarray, "TIA") + # print("\n Consts:\n") + # print(df_consts) + # print("\n Tags:\n") + # print(df_tags) + + # print("\n gleiche Eingänge:\n") + # print(df_gleiche_eingaenge) + # print("\n gleiche Ausgänge:\n") + # print(df_gleiche_ausgaenge) + + self.assertIn("DI0020", df_gleiche_eingaenge["NameOriginal"].values) # Püfen, ob doppelter Name in doppelteEingänge auftaucht self.assertIn("MA1020", df_gleiche_ausgaenge["NameOriginal"].values) # Püfen, ob doppelter Name in doppelteAusgänge auftaucht self.assertEqual(len(df_fehler), 1) # Fehler anzeigen: Zeile 4 Prefix XY - self.assertEqual(len(df_consts), len(textarray)) # wird für jede Zeile ein consts bzw tags erstellt? - self.assertEqual(len(df_tags), len(textarray)) # VORSICHT: Fehler kommt auch in Ausgabe mit Prefix 'Err' - + # Test, ob länge passt. Eigentlich 10 Eingabezeilen, Fehler bleibt drin, aber 2x 1 Duplikat in Eingang und Ausgang abziehen + self.assertEqual(len(df_consts), len(textarray)-(len(df_gleiche_ausgaenge)+len(df_gleiche_eingaenge))) + self.assertEqual(len(df_tags), len(textarray)-(len(df_gleiche_ausgaenge)+len(df_gleiche_eingaenge))) def test_WSCAD(self): textlines = """'DI0023','STEUERSPANNUNG 24V UC200 OK','24V OK','=A01+UH000-KF02i','STEUERSPANNUNG 24V UC200 OK','CONTROL VOLTAGE 24V UC200 OK','TENSION DE MANIOBRA 24V UC200 OK','' @@ -1074,19 +1122,19 @@ class TestPlant(unittest.TestCase): """ textarray = textlines.splitlines() + '''Testcase: 10 Zeilen mit I/O: Davon 4 Eingänge (1 Duplikat), 5 Ausgänge (1 Duplikat), 1 Fehlerhafte BMK''' + df_gleiche_eingaenge, df_gleiche_ausgaenge, df_fehler, df_eingaenge, df_ausgaenge = call_portal_to_excel(self, textarray, "WSCAD") - print("\n Eingänge:\n") - print(df_eingaenge) - print("\n Ausgänge:\n") - print(df_ausgaenge) + # print("\n Eingänge:\n") + # print(df_eingaenge) + # print("\n Ausgänge:\n") + # print(df_ausgaenge) - #self.assertIn("DI0020", df_gleiche_eingaenge["Name"].values) # Püfen, ob doppelter Name in doppelteEingänge auftaucht - #self.assertIn("MA1020", df_gleiche_ausgaenge["Name"].values) # Püfen, ob doppelter Name in doppelteAusgänge auftaucht - #self.assertEqual(len(df_fehler), 1) # Fehler anzeigen: Zeile 4 Prefix XY - - #self.assertEqual(len(df_eingaenge), 4) # Eigentlich 10 Zeilen lang, aber da Fehler nur 4 Eingänge - #self.assertEqual(len(df_ausgaenge), 5) # 5 Ausgänge in Liste + # print("\n gleiche Eingänge:\n") + # print(df_gleiche_eingaenge) + # print("\n gleiche Ausgänge:\n") + # print(df_gleiche_ausgaenge) def test_WSCAD_bezug(self): textlines = """'DI0023','STEUERSPANNUNG 24V UC200 OK','24V OK','=A01+UH000-KF02i','STEUERSPANNUNG 24V UC200 OK','CONTROL VOLTAGE 24V UC200 OK','TENSION DE MANIOBRA 24V UC200 OK','' @@ -1101,6 +1149,8 @@ class TestPlant(unittest.TestCase): 'MA1020','ANTRIEB PUFFER F0101 FLYER 1','M-BI-LE','=A01+UC101-KF02Q','','','','' """ textarray = textlines.splitlines() + + '''Testcase: 10 Zeilen mit I/O: Davon 4 Eingänge (1 Duplikat), 5 Ausgänge (1 Duplikat), 1 Fehlerhafte BMK''' df_gleiche_eingaenge, df_gleiche_ausgaenge, df_fehler, df_eingaenge, df_ausgaenge = call_portal_to_excel(self, textarray, "WSCAD mit Bezug") @@ -1109,20 +1159,17 @@ class TestPlant(unittest.TestCase): print("\n Ausgänge:\n") print(df_ausgaenge) - #self.assertIn("DI0020", df_gleiche_eingaenge["Name"].values) # Püfen, ob doppelter Name in doppelteEingänge auftaucht - #self.assertIn("MA1020", df_gleiche_ausgaenge["Name"].values) # Püfen, ob doppelter Name in doppelteAusgänge auftaucht - #self.assertEqual(len(df_fehler), 1) # Fehler anzeigen: Zeile 4 Prefix XY - - #self.assertEqual(len(df_eingaenge), 4) # Eigentlich 10 Zeilen lang, aber da Fehler nur 4 Eingänge - #self.assertEqual(len(df_ausgaenge), 5) # 5 Ausgänge in Liste - + print("\n gleiche Eingänge:\n") + print(df_gleiche_eingaenge) + print("\n gleiche Ausgänge:\n") + print(df_gleiche_ausgaenge) if __name__ == "__main__": suite = unittest.TestSuite() - suite.addTest(TestPlant('test_TIA')) suite.addTest(TestPlant('test_Simpel')) + suite.addTest(TestPlant('test_TIA')) suite.addTest(TestPlant('test_WSCAD')) suite.addTest(TestPlant('test_WSCAD_bezug'))