from PyQt5.QtWidgets import QApplication, QDialog, QFileDialog from PyQt5.uic import loadUi import sys, os, re from pathlib import Path import pandas as pd from icecream import ic import numpy as np from PS import pruefe_und_setze_wert class MainUI(QDialog): # erbt von QDialog def __init__(self): # super (MainUI, self).__init__() #Aufrufen des Konstruktors von QDialog super().__init__() loadUi("Aufbaumaster2CSV.ui", self) self.filename = None self.path = None self.df_vte = None self.df_cmdb = None self.df_vte_gg = None self.df_vte_erw = None self.df_cmdb_gg = None self.df_cmdb_erw = None self.dfb_gg = None self.dfb_erw = None self.openBtn.clicked.connect(self.open_file_dialog) self.saveBtn.clicked.connect(self.save_file_dialog) self.filter = "Hostnamen" self.group = None self.typ = None pruefe_und_setze_wert = pruefe_und_setze_wert def open_file_dialog(self): self.filename, _ = QFileDialog.getOpenFileName( self, "Aufbaumaster", "\\Volumes\\Daten01\\Documents\\toCSV", "Images (*.xls *.xlsx *.xlsb)" ) # self.filename_edit.setPixmap(QPixmap(self.filename)) self.lblCMDBPath.setText(self.filename) if self.filename: self.path = Path(self.filename) self.collect_allgemein() self.collect_cmdb_daten_gg() self.collect_cmdb_daten_erw() def collect_cmdb_daten_gg(self): # Einlesen der Sheets allgemein # Nach relevanten Spalten filtern Grundgeraete # Sheet VTE self.df_vte_gg = self.df_vte[self.df_vte['Gruppierung'] == 'Grundgerät'] # Sheet CMDB self.df_cmdb_gg = self.df_cmdb[self.df_cmdb['Filter'] == 'Grundgerät'] # Führende Leerzeichen in allen Spalten entfernen self.df_vte_gg = self.df_vte_gg.apply(lambda x: x.str.lstrip() if x.dtype == "object" else x) self.df_cmdb_gg = self.df_cmdb_gg.apply(lambda x: x.str.lstrip() if x.dtype == "object" else x) # Teil Grundgeräte self.df_cmdb_gg = self.df_cmdb_gg.drop( columns=['WV-Start', 'WV-Ende', 'CMDB-Status', 'Aufgabe Schritt', 'Filter', 'Waermeabgabe [BTU/h]', 'kalk. Strom [A]']) # Einfügen von Spalten in die CMDB-Tabelle self.dfb_gg = self.df_vte_gg.merge(self.df_cmdb_gg, on=['Hostname'], how='left') # Spalte für Mandanten Kontaktzuweisung self.dfb_gg.insert(loc=7, column='Mandanten Kontaktzuweisung', value='Mandant') # Spalte für Segmente self.dfb_gg.insert(loc=8, column='Segment', value='') # Spalte für Domains self.dfb_gg.insert(loc=9, column='Domain', value='') # Spalte einfügen für HE self.dfb_gg.insert(loc=14, column='HE', value='') # Einschub self.dfb_gg.insert(loc=15, column='Einschub', value='') # Montage --> nur horizontal self.dfb_gg.insert(loc=16, column='Montage', value='horizontal') # Formfaktor self.dfb_gg.insert(loc=17, column='Formfaktor', value='19"') # Masseinheit self.dfb_gg.insert(loc=18, column='Masseinheit', value='Zoll') # Spaltenanmen mit Sonderzeichen anzeigen columns_with_special_chars = [col for col in self.dfb_gg.columns if self.has_special_characters(col)] print("Spaltenheader mit Sonderzeichen:", columns_with_special_chars) # Führende Leerzeichen in allen Spalten entfernen # Nach oben velegt #self.dfb_gg = self.dfb_gg.apply(lambda x: x.str.lstrip() if x.dtype == "object" else x) # Alle Floats in Strings umwandeln self.dfb_gg = self.dfb_gg.applymap(lambda x: str(x) if isinstance(x, float) else x) self.dfb_gg = self.dfb_gg.apply(self.suche_Einschub, axis=1) self.dfb_gg = self.dfb_gg.apply(self.montageort, axis=1) self.dfb_gg = self.dfb_gg.apply(self.pruefe_und_setze_wert, axis=1) self.df_gg = self.dfb_gg.apply(self.anpassung_Objekttyp, axis=1) # Setzen von int für HE und Anz. HE self.dfb_gg['HE'] = self.dfb_gg['HE'].apply(lambda x: x if pd.isnull(x) else str(int(x))) def has_special_characters(self, s): # Regex pattern für Sonderzeichen return bool(re.search(r'[^A-Za-z0-9]', s)) def suche_Einschub(self, einschub): if einschub['Montageort'][-1] in ('v','h'): if einschub['Montageort'][-1] == 'v': einschub['Einschub'] = 'Vorderseite' else: einschub['Einschub'] = 'Rückseite' return einschub def anpassung_sfp(self, sfp): sfp['Modell'] = sfp['Modell'].rstrip() if sfp['Modell'] == 'SFP+: 1x10 Gbit MM Rev. 4.0 mit LC Connector': sfp['Modell'] = 'SFP+ 10GBase-SR - LC' return sfp def anpassung_Objekttyp(self, objekttyp): if objekttyp['Objekttyp (CMDB)'] == 'Genucenter': objekttyp['Objekttyp (CMDB)'] = 'C__OBJTYPE__APPLIANCE' elif objekttyp['Objekttyp (CMDB)'] == 'HW Appliance': objekttyp['Objekttyp (CMDB)'] = 'C__OBJTYPE__APPLIANCE' elif objekttyp['Objekttyp (CMDB)'] == 'Paketfilter / ALG': objekttyp['Objekttyp (CMDB)'] = 'C__OBJTYPE__APPLIANCE' elif objekttyp['Objekttyp (CMDB)'] == 'Kryptierer': objekttyp['Objekttyp (CMDB)'] = 'C__OBJTYPE__SD_KRYPTIERER' elif objekttyp['Objekttyp (CMDB)'] == 'Server': objekttyp['Objekttyp (CMDB)'] = 'C__OBJTYPE__SERVER' elif objekttyp['Objekttyp (CMDB)'] == 'Switch': objekttyp['Objekttyp (CMDB)'] = 'C__OBJTYPE__SWITCH' elif objekttyp['Objekttyp (CMDB)'] == 'virtuelle Maschine': objekttyp['Objekttyp (CMDB)'] = 'C__OBJTYPE__VIRTUAL_SERVER' elif objekttyp['Objekttyp (CMDB)'] == 'Terminalserver': objekttyp['Objekttyp (CMDB)'] = 'C__OBJTYPE__TERMINALSERVER' elif objekttyp['Objekttyp (CMDB)'] == 'Storage': objekttyp['Objekttyp (CMDB)'] = 'C__OBJTYPE__SAN' elif objekttyp['Objekttyp (CMDB)'] == 'SFP': objekttyp['Objekttyp (CMDB)'] = 'C__OBJTYPE__SD_SFP' elif objekttyp['Objekttyp (CMDB)'] == 'Speichersystem': objekttyp['Objekttyp (CMDB)'] = 'C__OBJTYPE__SAN' elif objekttyp['Objekttyp (CMDB)'] == 'Router': objekttyp['Objekttyp (CMDB)'] = 'C__OBJTYPE__ROUTER' if objekttyp['Hostname'][1:3] == "vho": objekttyp['Objekttyp (CMDB)'] = 'C__OBJTYPE__VIRTUAL_HOST' return objekttyp def montageort(self, montage): # Fehlerbereinigung # ic("Montage: ", montage) if montage['ID\nStandort']not in ("Ber-PS", "Bon-BTW"): print("Kein Standort P40 oder BTW") sys.exit(0) else: if len((montage['Montageort'][8:13])) != 2: montage['HE'] = montage['Montageort'][8:10] montage['Montageort'] = montage['Montageort'][0:7] else: montage['HE'] = montage['Montageort'][8:10] montage['Montageort'] = montage['Montageort'][0:7] return montage def korrektur_hersteller(self, hersteller): if hersteller['Hersteller'].lower() == "cisco": hersteller['Hersteller'] = "Cisco Systems" elif hersteller['Hersteller'].lower() == "genua": hersteller['Hersteller'] = "genua GmbH" elif hersteller['Hersteller'].lower() == "digi": hersteller['Hersteller'] = "Digi International Inc." return hersteller def fake_seriennummer_sfp(self, sfp ): if sfp['Objekttyp (CMDB)'] == "C__OBJTYPE__SD_SFP" and sfp['Serien-Nr.'] in ('', 'bitte nachtragen'): ic("SFP serial", sfp['Serien-Nr.'] ) def collect_cmdb_daten_erw(self): ############## Erweiterung ################################################################################ # Kopieren self.df_vte_erw = self.df_vte self.df_cmdb_erw = self.df_cmdb # Führende Leerzeichen in allen Spalten entfernen self.df_vte_erw = self.df_vte_erw.apply(lambda x: x.str.lstrip() if x.dtype == "object" else x) self.df_cmdb_erw = self.df_cmdb_erw.apply(lambda x: x.str.lstrip() if x.dtype == "object" else x) # Auffüllen der Spalte Hostname self.df_vte_erw['Hostname']= self.df_vte_erw['Hostname'].replace('', np.nan) self.df_vte_erw['Hostname'] = self.df_vte_erw['Hostname'].fillna(method='ffill') # Nach relevanten Spalten filtern Erweiterung self.df_vte_erw = self.df_vte_erw[self.df_vte_erw['Gruppierung'] == 'Erweiterung'] # Füllen der leeren Zellen mit NaN, sonst git es Probleme bei ffill, so konnte ich fillna nutzen self.df_cmdb_erw['Hostname']= self.df_cmdb_erw['Hostname'].replace('', np.nan) self.df_cmdb_erw['Hostname'] = self.df_cmdb_erw['Hostname'].fillna(method='ffill') self.df_cmdb_erw = self.df_cmdb_erw[self.df_cmdb_erw['Filter'] == 'Erweiterung'] self.df_cmdb_erw = self.df_cmdb_erw.drop( columns=['WV-Start', 'WV-Ende', 'CMDB-Status', 'Aufgabe Schritt', 'Filter', 'Waermeabgabe [BTU/h]', 'kalk. Strom [A]']) self.dfb_erw = self.df_vte_erw.merge(self.df_cmdb_erw,left_index = True, right_index = True, how = 'left') # Das Merge bringt zwei Hostname-Spalten, daher Bereinigung und Korrektur self.dfb_erw = self.dfb_erw.drop(columns=['Hostname_y']) self.dfb_erw = self.dfb_erw.rename(columns={'Hostname_x': 'Hostname'}) # Suche nur nach SFP search = r'SFP' self.dfb_erw = self.dfb_erw[self.dfb_erw['Modell'].str.contains(search, regex=True, na=False)] self.dfb_erw = self.dfb_erw.apply(self.anpassung_sfp, axis=1) self.dfb_erw = self.dfb_erw.apply(self.korrektur_hersteller, axis=1) # Anapssung des Objekttypen self.dfb_erw = self.dfb_erw.apply(self.anpassung_Objekttyp, axis=1) self.dfb_erw = self.dfb_erw.apply(self.fake_seriennummer_sfp, axis=1) ic(self.dfb_erw) def save_file_dialog(self): # ic(self.dfb_gg) options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog self.savefilename, _ = QFileDialog.getSaveFileName(self, "Save File", "", "CSV(*.csv);;CSV Files(*.csv)", options=options) self.dfb_gg.to_csv(os.path.splitext(os.path.basename(self.savefilename))[0]+"_GG"+os.path.splitext(os.path.basename(self.savefilename))[1], index=None, header=True, encoding='utf-8') self.dfb_erw.to_csv(os.path.splitext(os.path.basename(self.savefilename))[0]+"_ERW"+os.path.splitext(os.path.basename(self.savefilename))[1], index=None, header=True, encoding='utf-8') # print("Datei wurde gespeichert:", self.savefilename) def collect_allgemein(self): self.df_vte = pd.read_excel(self.filename, header=7, na_filter=False, sheet_name='VTE-Input', usecols=['Hostname', 'Gruppierung', 'CONFIG-ID', 'CMDB Status'], engine='pyxlsb') self.df_cmdb = pd.read_excel(self.filename, header=2, sheet_name="CMDB", engine='pyxlsb') if __name__ == "__main__": app = QApplication(sys.argv) ui = MainUI() ui.show() app.exec_()