def read_infotext(self, filename, sprache): """Lesen der Datei INFOTEXT INFOTEXT aus INFO+ ist sprachabhängig in dem Format INFOTEXT_XX """ if sprache.strip(): # wird keine Sprache übergeben, dann bleibt der Dateiname unverändert filename = filename + '_' + sprache else: sprache = '--' logger.info('lesen und verarbeiten der Datei '+filename) infotext_strIO = StringIO() for line in fileinput.input(filename, openhook=self.__hrdfzip.open): line = line.decode(self.__charset).replace('\r\n', '') infotext_strIO.write(self.__fkdict['fk_eckdatenid']+';' +line[:7]+';' +sprache.lower()+';' +line[8:].replace(';','\;') +'\n') infotext_strIO.seek(0) cur = self.__hrdfdb.connection.cursor() cur.copy_expert("COPY HRDF_INFOTEXT_TAB (fk_eckdatenid,infotextno,languagecode,infotext) FROM STDIN USING DELIMITERS ';' NULL AS ''", infotext_strIO) self.__hrdfdb.connection.commit() cur.close() infotext_strIO.close()
def read_bahnhof(self, filename): """Lesen der Datei BAHNHOF""" logger.info('lesen und verarbeiten der Datei BAHNHOF') bahnhof_strIO = StringIO() for line in fileinput.input(filename, openhook=self.__hrdfzip.open): line = line.decode(self.__charset).replace('\r\n', '') stopname = '' stopnamelong = '' stopnameshort = '' stopnamealias = '' # Die Analyse betrachtet noch keine Sprachangaben for tmpName in re.split(">", line[12:62].strip()): pos = tmpName.find("<"); typeinfo = tmpName[pos:] name = tmpName[:pos].replace("$", "") for c in typeinfo[1:]: if c == "1": stopname = name[:30] if c == "2": stopnamelong = name[:50] if c == "3": stopnameshort = name if c == "4": stopnamealias = name bahnhof_strIO.write(self.__fkdict['fk_eckdatenid']+';' +line[:7].strip()+';' +line[8:11].strip()+';' +stopname+';' +stopnamelong+';' +stopnameshort+';' +stopnamealias +'\n') bahnhof_strIO.seek(0) cur = self.__hrdfdb.connection.cursor() cur.copy_expert("COPY HRDF_BAHNHOF_TAB (fk_eckdatenid,stopno,transportUnion,stopname,stopnamelong,stopnameshort,stopnamealias) FROM STDIN USING DELIMITERS ';' NULL AS ''", bahnhof_strIO) self.__hrdfdb.connection.commit() cur.close() bahnhof_strIO.close()
def read_bitfeld(self, filename): """Lesen der Datei BITFELD""" logger.info('lesen und verarbeiten der Datei BITFELD') bitfeld_strIO = StringIO() for line in fileinput.input(filename, openhook=self.__hrdfzip.open): line = line.decode(self.__charset).replace('\r\n','') bitfield = str(Bits(hex=line[7:]).bin)[2:-2] daycnt = (self.__eckdaten_validTo - self.__eckdaten_validFrom).days # Aufbauen des Datums-Array auf Grund der gesetzen Bits validDays = [] i = 0 while i <= daycnt: if bitfield[i] == "1": validDays.append(str(self.__eckdaten_validFrom + timedelta(days=i))) i += 1 if len(validDays) == 0: validDaysString = "{}" else: validDaysString = "{'" + "','".join(map(str,validDays)) + "'}" bitfeld_strIO.write(self.__fkdict['fk_eckdatenid']+';' +line[:6]+';' +line[7:]+';' +bitfield+';' +validDaysString +'\n') bitfeld_strIO.seek(0) cur = self.__hrdfdb.connection.cursor() cur.copy_expert("COPY HRDF_BITFELD_TAB (fk_eckdatenid,bitfieldno,bitfield,bitfieldextend,bitfieldarray) FROM STDIN USING DELIMITERS ';' NULL AS ''",bitfeld_strIO) self.__hrdfdb.connection.commit() cur.close() bitfeld_strIO.close()
def generate_timetable_from_hrdf(eckdatenId, generateFrom, generateTo, dbname, host): """Generiert einen Tagesfahrplan aus den HRDF-Daten für die Betriebstage im angegebenen Zeitbereich eckdatenId -- ID aus der Tabelle HRDF_ECKDATEN_TAB generateFrom -- Beginn des Zeitbereichs, für den der Tagesfahrlan generiert wird (String-Format '%d.%m.%Y') generateTo -- Ende des Zeitbereichs, für den der Tagesfahrplan generiert wird (String-Format '%d.%m.%Y') dbname -- Datenbankname host -- Host auf dem die Datenbank läuft """ hrdf_db = HrdfDB(dbname, host, "hrdf", "bmHRDF") if hrdf_db.connect(): # Initialisierung des HRDF-TTGenerators ttGenerator = HrdfTTG(hrdf_db) dtGenerateFrom = datetime.strptime(generateFrom, '%d.%m.%Y').date() dtGenerateTo = datetime.strptime(generateTo, '%d.%m.%Y').date() logger.info("Generierung des Tagesfahrplan für den Zeitraum von {:%d.%m.%Y} bis {:%d.%m.%Y}:".format(dtGenerateFrom, dtGenerateTo)) if ( ttGenerator.setup(eckdatenId, dtGenerateFrom, dtGenerateTo) ): iErrorCnt = ttGenerator.generateTT() if ( iErrorCnt == 0): logger.info("Der Tagesfahrplan für den Zeitraum von {:%d.%m.%Y} bis {:%d.%m.%Y} wurde erfolgreich generiert".format(dtGenerateFrom, dtGenerateTo)) else: logger.warning("Der Tagesfahrplan für den Zeitraum von {:%d.%m.%Y} bis {:%d.%m.%Y} konnte nicht vollständig generiert werden. {} fehlerhafte Fahrten".format(dtGenerateFrom, dtGenerateTo, iErrorCnt)) else: logger.error("Der Tagesfahrplan-Generator konnte nicht initialisiert werden") else: logger.error("Es konnte keine Verbindung zur Datenbank aufgebaut werden")
def read_zugart(self, filename): """Lesen der Datei ZUGART""" logger.info('lesen und verarbeiten der Datei ZUGART') zugart_strIO = StringIO() zugartcategory_strIO = StringIO() zugartclass_strIO = StringIO() zugartoption_strIO = StringIO() languagecode = "--" bTextblock = False for line in fileinput.input(filename, openhook=self.__hrdfzip.open): line = line.decode(self.__charset).replace('\r\n', '') # Eine Zeile mit dem Inhalt "<text>" gibt an, dass nun nur noch die Textangaben in verschiedenen Sprachen folgen if not bTextblock: # solange das nicht der Fall ist, sollen die Daten als Zugarten weiter eingearbeitet werden if line != '<text>': # Der string setzt sich aus folgenden Elementen zusammen: code,produktklasse,tarifgruppe,ausgabesteuerung,gattungsbezeichnung,zuschlag,flag,gattungsbildernamen,kategorienummer zugart_strIO.write(self.__fkdict['fk_eckdatenid']+';' +line[:3].strip()+';' +line[4:6].strip()+';' +line[7:8]+';' +line[9:10]+';' +line[11:19].strip()+';' +line[20:21].strip()+';' +line[22:23]+';' +line[24:28].strip()+';' +line[30:33]+ '\n') # sobald die Textangaben beginnen, werden die Daten sprachspezifisch in das jeweilige dictionary geschrieben else: bTextblock = True elif line[0] == '<': languagecode = line[1:3].lower() elif line[:8] == 'category': zugartcategory_strIO.write(self.__fkdict['fk_eckdatenid']+';'+line[8:11]+';'+languagecode+';'+line[12:]+'\n') elif line[:6] == 'option': zugartoption_strIO.write(self.__fkdict['fk_eckdatenid']+';'+line[6:8]+';'+languagecode+';'+line[9:]+'\n') elif line[:5] == 'class': zugartclass_strIO.write(self.__fkdict['fk_eckdatenid']+';'+line[5:7]+';'+languagecode+';'+line[8:]+'\n') zugart_strIO.seek(0) zugartcategory_strIO.seek(0) zugartclass_strIO.seek(0) zugartoption_strIO.seek(0) cur = self.__hrdfdb.connection.cursor() cur.copy_expert("COPY HRDF_ZUGART_TAB (fk_eckdatenid,categorycode,classno,tariffgroup,outputcontrol,categorydesc,extracharge,flags,categoryimage,categoryno) FROM STDIN USING DELIMITERS ';' NULL AS ''", zugart_strIO) cur.copy_expert("COPY HRDF_ZUGARTKategorie_TAB (fk_eckdatenid,categoryno,languagecode,categorytext) FROM STDIN USING DELIMITERS ';' NULL AS ''",zugartcategory_strIO) cur.copy_expert("COPY HRDF_ZUGARTKlasse_TAB (fk_eckdatenid,classno,languagecode,classtext) FROM STDIN USING DELIMITERS ';' NULL AS ''",zugartclass_strIO) cur.copy_expert("COPY HRDF_ZUGARTOption_TAB (fk_eckdatenid,optionno,languagecode,optiontext) FROM STDIN USING DELIMITERS ';' NULL AS ''",zugartoption_strIO) self.__hrdfdb.connection.commit() cur.close() zugart_strIO.close() zugartcategory_strIO.close() zugartclass_strIO.close() zugartoption_strIO.close()
def determine_linesperstop(self): """Ermitteln und Schreiben der Linien, die in der aktuellen Fahrplanperiode an einem Halt vorkommen""" logger.info('ermitteln der Linien pro Halt') sql_stopsLookup = "INSERT INTO HRDF.HRDF_LINESPERSTOP_TAB (fk_eckdatenid, stopno, operationalno, lineno, categorycode) "\ "(SELECT DISTINCT fahrt.fk_eckdatenid, flw.stopno, fahrt.operationalno, line.lineno, cat.categorycode "\ "FROM hrdf.hrdf_fplanfahrtlaufweg_tab flw "\ "LEFT OUTER JOIN hrdf.hrdf_fplanfahrt_tab fahrt on flw.fk_fplanfahrtid = fahrt.id and flw.fk_eckdatenid = fahrt.fk_eckdatenid "\ "LEFT OUTER JOIN hrdf.hrdf_fplanfahrtl_tab line on line.fk_fplanfahrtid = fahrt.id and line.fk_eckdatenid = fahrt.fk_eckdatenid "\ "LEFT OUTER JOIN hrdf.hrdf_fplanfahrtg_tab cat on cat.fk_fplanfahrtid = fahrt.id and cat.fk_eckdatenid = fahrt.fk_eckdatenid "\ "WHERE fahrt.fk_eckdatenid = %s)" curLookup = self.__hrdfdb.connection.cursor() curLookup.execute(sql_stopsLookup, (self.__fkdict['fk_eckdatenid'],)) self.__hrdfdb.connection.commit() curLookup.close()
def read_richtung(self, filename): """Lesen der Datei RICHTUNG""" logger.info('lesen und verarbeiten der Datei RICHTUNG') richtung_strIO = StringIO() for line in fileinput.input(filename, openhook=self.__hrdfzip.open): line = line.decode(self.__charset).replace('\r\n', '') richtung_strIO.write(self.__fkdict['fk_eckdatenid']+';' +line[:7].strip()+';' +line[8:59].strip() +'\n') richtung_strIO.seek(0) cur = self.__hrdfdb.connection.cursor() cur.copy_expert("COPY HRDF_RICHTUNG_TAB (fk_eckdatenid,directioncode, directiontext) FROM STDIN USING DELIMITERS ';' NULL AS ''", richtung_strIO) self.__hrdfdb.connection.commit() cur.close() richtung_strIO.close()
def read_bfprios(self, filename): """Lesen der Datei BFPRIOS""" logger.info('lesen und verarbeiten der Datei BFPRIOS') bfprios_strIO = StringIO() for line in fileinput.input(filename, openhook=self.__hrdfzip.open): line = line.decode(self.__charset).replace('\r\n', '') bfprios_strIO.write(self.__fkdict['fk_eckdatenid']+';' +line[:7]+';' +line[8:10] +'\n') bfprios_strIO.seek(0) cur = self.__hrdfdb.connection.cursor() cur.copy_expert("COPY HRDF_BFPRIOS_TAB (fk_eckdatenid,stopno,transferprio) FROM STDIN USING DELIMITERS ';' NULL AS ''", bfprios_strIO) self.__hrdfdb.connection.commit() cur.close() bfprios_strIO.close()
def read_attribut(self, filename, sprache): """Lesen der Datei ATTRIBUT ATTRIBUT aus INFO+ ist sprachabhängig in dem Format ATTRIBUT_XX """ if sprache.strip(): # wird keine Sprache übergeben, dann bleibt der Dateiname unverändert filename = filename + '_' + sprache else: sprache = '--' logger.info('lesen und verarbeiten der Datei '+filename) # Erster Durchlauf um die Ausgabeattributcodes für Teil- und Vollstrecke zu ermitteln targetcodes = {} for line in fileinput.input(filename, openhook=self.__hrdfzip.open): line = line.decode(self.__charset).replace('\r\n', '') if line[:1] == '#': targetcodes[line[2:4].strip()] = [line[5:7].strip(), line[8:10].strip()] attribute_strIO = StringIO() for line in fileinput.input(filename, openhook=self.__hrdfzip.open): line = line.decode(self.__charset).replace('\r\n', '') if line[:1] != '#': attrcode = line[:2].strip() if attrcode in targetcodes: attrcode_section = targetcodes[attrcode][0] attrcode_complete = targetcodes[attrcode][1] else: attrcode_section = "" attrcode_complete = "" attribute_strIO.write(self.__fkdict['fk_eckdatenid']+';' +attrcode+';' +sprache.lower()+';' +line[3:4]+';' +line[5:8]+';' +line[9:11]+';' +line[12:-1].replace(';','\;')+';' +attrcode_section+';' +attrcode_complete +'\n') attribute_strIO.seek(0) cur = self.__hrdfdb.connection.cursor() cur.copy_expert("COPY HRDF_ATTRIBUT_TAB (fk_eckdatenid,attributecode,languagecode,stopcontext,outputprio,outputpriosort,attributetext,outputforsection,outputforcomplete) FROM STDIN USING DELIMITERS ';' NULL AS ''", attribute_strIO) self.__hrdfdb.connection.commit() cur.close() attribute_strIO.close()
def readfiles(self): """Liest die gewünschten HRDF-Dateien und schreibt sie in die Datenbank""" for filename in self.__hrdffiles: if filename == "ECKDATEN": self.read_eckdaten(filename) elif filename == "BITFELD": self.read_bitfeld(filename) elif filename == "RICHTUNG": self.read_richtung(filename) elif filename == "ZUGART": self.read_zugart(filename) elif filename == "ATTRIBUT": self.read_attribut(filename, "DE") self.read_attribut(filename, "EN") self.read_attribut(filename, "FR") self.read_attribut(filename, "IT") elif filename == "INFOTEXT": self.read_infotext(filename, "DE") self.read_infotext(filename, "EN") self.read_infotext(filename, "FR") self.read_infotext(filename, "IT") elif filename == "FPLAN": self.read_fplan(filename) elif filename == "BAHNHOF": self.read_bahnhof(filename) elif filename == "GLEIS": self.read_gleis(filename) elif filename == "DURCHBI": self.read_durchbi(filename) elif filename == "BFKOORD_GEO": self.read_bfkoordgeo(filename) elif filename == "UMSTEIGB": self.read_umsteigb(filename) elif filename == "BFPRIOS": self.read_bfprios(filename) elif filename == "METABHF": self.read_metabhf(filename) else: logger.error("Das Lesen der Datei ["+filename+"] wird nicht unterstützt") # Aufbereitung und Verdichtung der importierten Daten self.determine_linesperstop() self.determine_tripcount() logger.info("Der HRDF-Import <{}> wurde eingearbeitet".format(self.__hrdfzip.filename))
def read_bfkoordgeo(self, filename): """Lesen der Datei BFKOORD_GEO""" logger.info('lesen und verarbeiten der Datei BFKOORD_GEO') bfkoordgeo_strIO = StringIO() for line in fileinput.input(filename, openhook=self.__hrdfzip.open): line = line.decode(self.__charset).replace('\r\n', '') bfkoordgeo_strIO.write(self.__fkdict['fk_eckdatenid']+';' +line[:7]+';' +line[8:18]+';' +line[19:29]+';' +line[30:36] +'\n') bfkoordgeo_strIO.seek(0) cur = self.__hrdfdb.connection.cursor() cur.copy_expert("COPY HRDF_BFKOORD_TAB (fk_eckdatenid,stopno,longitude_geo,latitude_geo,altitude_geo) FROM STDIN USING DELIMITERS ';' NULL AS ''", bfkoordgeo_strIO) self.__hrdfdb.connection.commit() cur.close() bfkoordgeo_strIO.close()
def read_eckdaten(self, filename): """Lesen der Datei ECKDATEN""" logger.info('lesen und verarbeiten der Datei ECKDATEN') lines = self.__hrdfzip.read(filename).decode(self.__charset).split('\r\n')[:-1] # spezifisch für SBB-Version sind die Trenner in der Bezeichnung, die hier in separate Felder geschrieben werden bezeichnung,exportdatum,hrdfversion,lieferant = lines[2].split('$') cur = self.__hrdfdb.connection.cursor() sql_string = "INSERT INTO HRDF_ECKDATEN_TAB (importFileName, importDateTime, validFrom, validTo, descriptionhrdf, description, creationdatetime, hrdfversion, exportsystem) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s) RETURNING id;" importFileName = os.path.basename(self.__hrdfzip.filename) importDateTime = str(datetime.now()) validFrom = str(datetime.strptime(lines[0], '%d.%m.%Y').date()) validTo = str(datetime.strptime(lines[1], '%d.%m.%Y').date()) exportdatum = str(datetime.strptime(exportdatum, '%d.%m.%Y %H:%M:%S')) cur.execute(sql_string, (importFileName, importDateTime, validFrom, validTo, lines[2], bezeichnung, exportdatum, hrdfversion, lieferant)) self.__fkdict["fk_eckdatenid"] = str(cur.fetchone()[0]) self.__hrdfdb.connection.commit() self.__eckdaten_validFrom = datetime.strptime(lines[0], '%d.%m.%Y').date() self.__eckdaten_validTo = datetime.strptime(lines[1], '%d.%m.%Y').date() cur.close()
def determine_tripcount(self): """Ermitteln und Schreiben der Anzahl Fahrten (Linien/Kategorie) pro Verwaltungsnummer - Taktdefinitionen mit eingeschlossen""" logger.info('ermitteln der Anzahl Fahrten (Linien/Kategorie) pro Verwaltung') sql_tripsLookup = "INSERT INTO HRDF.HRDF_TripCount_Operator_TAB (fk_eckdatenid, operationalno, lineno, categorycode, tripcount) "\ "(SELECT fahrt.fk_eckdatenid, fahrt.operationalno, line.lineno, cat.categorycode, sum(coalesce(array_length(bit.bitfieldarray, 1), eckdaten.maxdays)*coalesce(cyclecount+1,1)) "\ " FROM hrdf.hrdf_fplanfahrt_tab fahrt "\ " inner join (SELECT id, validto + 1 - validfrom as maxdays FROM hrdf.hrdf_eckdaten_tab) eckdaten on fahrt.fk_eckdatenid = eckdaten.id "\ " LEFT OUTER JOIN hrdf.hrdf_fplanfahrtve_tab ve on fahrt.fk_eckdatenid = ve.fk_eckdatenid and fahrt.id = ve.fk_fplanfahrtid "\ " LEFT OUTER JOIN hrdf.hrdf_bitfeld_tab bit on ve.bitfieldno = bit.bitfieldno and ve.fk_eckdatenid = bit.fk_eckdatenid "\ " LEFT OUTER JOIN hrdf.hrdf_fplanfahrtl_tab line on line.fk_fplanfahrtid = fahrt.id and line.fk_eckdatenid = fahrt.fk_eckdatenid "\ " LEFT OUTER JOIN hrdf.hrdf_fplanfahrtg_tab cat on cat.fk_fplanfahrtid = fahrt.id and cat.fk_eckdatenid = fahrt.fk_eckdatenid "\ " WHERE fahrt.fk_eckdatenid = %s "\ " GROUP BY fahrt.fk_eckdatenid, fahrt.operationalno, line.lineno, cat.categorycode)" curLookup = self.__hrdfdb.connection.cursor() curLookup.execute(sql_tripsLookup, (self.__fkdict['fk_eckdatenid'],)) self.__hrdfdb.connection.commit() curLookup.close()
def read_gleis(self, filename): """Lesen der Datei GLEIS""" logger.info('lesen und verarbeiten der Datei GLEIS') gleis_strIO = StringIO() for line in fileinput.input(filename, openhook=self.__hrdfzip.open): line = line.decode(self.__charset).replace('\r\n', '') gleis_strIO.write(self.__fkdict['fk_eckdatenid']+';' +line[:7].strip()+';' +line[8:13].strip()+';' +line[14:20].strip()+';' +line[21:29].strip()+';' +line[30:34].strip()+';' +line[35:41].strip() +'\n') gleis_strIO.seek(0) cur = self.__hrdfdb.connection.cursor() cur.copy_expert("COPY HRDF_GLEIS_TAB (fk_eckdatenid,stopno,tripno,operationalno,stoppointtext,stoppointtime,bitfieldno) FROM STDIN USING DELIMITERS ';' NULL AS ''", gleis_strIO) self.__hrdfdb.connection.commit() cur.close() gleis_strIO.close()
def deleteDailyTimetable(self, eckdatenid, generationDay): """ Die Funktion löscht den gewünschten Tagesfahrplan eines Fahrplanimports Nach dem Löschen des Tagesfahrplan wird der entsprechende Eintrag in der Eckdaten-Tabelle angepasst """ # Löschen des Tagesfahrplans curDeleteDay = self.__hrdfdb.connection.cursor() sql_delDay = "DELETE FROM HRDF_DailyTimeTable_TAB WHERE fk_eckdatenid = %s AND operatingday = %s" curDeleteDay.execute(sql_delDay, (eckdatenid, str(generationDay))) deletedRows = curDeleteDay.rowcount logger.info( "{:%d.%m.%Y} => {} bestehende Einträge wurden geloescht".format( generationDay, deletedRows)) curDeleteDay.close() # Anpassen des Eintrags in der Eckdaten-Tabelle curUpdTTGenerated = self.__hrdfdb.connection.cursor() sql_updTTGenerated = "UPDATE HRDF.HRDF_Eckdaten_TAB SET ttgenerated = array_remove(ttgenerated, %s) WHERE id = %s" curUpdTTGenerated.execute(sql_updTTGenerated, (str(generationDay), eckdatenid)) curUpdTTGenerated.close() self.__hrdfdb.connection.commit()
def read_durchbi(self, filename): """Lesen der Datei DURCHBI""" logger.info('lesen und verarbeiten der Datei DURCHBI') durchbi_strIO = StringIO() for line in fileinput.input(filename, openhook=self.__hrdfzip.open): line = line.decode(self.__charset).replace('\r\n', '') durchbi_strIO.write(self.__fkdict['fk_eckdatenid']+';' +line[:5]+';' +line[6:12].strip()+';' +line[13:20]+';' +line[21:26]+';' +line[27:33].strip()+';' +line[34:40]+';' +line[41:48]+';' +line[49:51].strip()+';' +line[53:].strip() +'\n') durchbi_strIO.seek(0) cur = self.__hrdfdb.connection.cursor() cur.copy_expert("COPY HRDF_DURCHBI_TAB (fk_eckdatenid,tripno1,operationalno1,laststopno1,tripno2,operationalno2,bitfieldno,firststopno2,attribute,comment) FROM STDIN USING DELIMITERS ';' NULL AS ''", durchbi_strIO) self.__hrdfdb.connection.commit() cur.close() durchbi_strIO.close()
def createCacheData(self, eckdatenid, generateFrom, generateTo): """ Die Funktion erstellt die Daten des Fahrplan-Cache """ # Lookup der Verkehrstagesdefinitionen # für jeden erforderlichen Tag werden die Verkehrstagesdefinitionen geladen logger.info("Lookup der Verkehrstagesdefinitionen aufbauen") self.__bitfieldnumbersOfDay.clear() dayCnt = (generateTo - generateFrom).days i = 0 while (i <= dayCnt): # Laden der Verkehrstagesdefinitionen für den Generierungstag als set() für schnellen Zugriff/Abfrage auf Existenz generationDay = generateFrom + timedelta(days=i) sql_selBitfieldNos = "SELECT bitfieldno FROM HRDF_Bitfeld_TAB where bitfieldarray @> ARRAY[%s::date] AND fk_eckdatenid = %s" curBits = self.__hrdfdb.connection.cursor() curBits.execute(sql_selBitfieldNos, (str(generationDay), eckdatenid)) bitfieldNos = curBits.fetchall() bitfieldnumbers = set() for bitfield in bitfieldNos: bitfieldnumbers.add(bitfield[0]) curBits.close() self.__bitfieldnumbersOfDay[generationDay] = bitfieldnumbers # Tageszähler hochzählen und nächsten gewünschten Tag generieren i += 1 # Lookup für Zugarten der Fahrplanfahrten logger.info("Lookup für Zugarten aufbauen") self.__fahrtZugartLookup.clear() sql_zugartLookup = "SELECT a.fk_fplanfahrtid, a.categorycode, fromstop, tostop, deptimefrom, arrtimeto, b.classno, b.categoryno"\ " FROM HRDF_FPlanFahrtG_TAB a, "\ " HRDF_ZUGART_TAB b "\ " WHERE a.fk_eckdatenid = %s "\ " and a.fk_eckdatenid = b.fk_eckdatenid "\ " and a.categorycode = b.categorycode "\ " ORDER BY a.fk_fplanfahrtid, a.id" curFahrtZugart = self.__hrdfdb.connection.cursor() curFahrtZugart.execute(sql_zugartLookup, (eckdatenid, )) fahrtZugarten = curFahrtZugart.fetchall() curFahrtZugart.close() for fahrtZugart in fahrtZugarten: fahrtId = fahrtZugart[0] if (fahrtId in self.__fahrtZugartLookup): self.__fahrtZugartLookup[fahrtId].append(fahrtZugart) else: zugartList = list() zugartList.append(fahrtZugart) self.__fahrtZugartLookup[fahrtId] = zugartList fahrtZugarten.clear() # Lookup für Bahnhofsnamen, Übergangszeiten (mit Standardzeit aus erster Zeile stopno 9999999) und GEO-Koordinaten logger.info("Lookup für Bahnhofsinformation aufbauen") sql_bahnhofLookup = "SELECT a.stopno, a.stopname, a.stopnamelong, a.stopnameshort, a.stopnamealias,"\ " coalesce(c.transfertime1,b.transfertime1) as transfertime1, coalesce(c.transfertime2,b.transfertime2) as transfertime2,"\ " d.transferprio,"\ " e.longitude_geo, e.latitude_geo, e.altitude_geo"\ " FROM HRDF_bahnhof_TAB a"\ " INNER JOIN (SELECT transfertime1, transfertime2, fk_eckdatenid FROM HRDF_umsteigb_TAB WHERE stopno = 9999999) b ON b.fk_eckdatenid = a.fk_eckdatenid"\ " LEFT OUTER JOIN HRDF_umsteigb_TAB c ON c.stopno = a.stopno AND c.fk_eckdatenid = a.fk_eckdatenid"\ " LEFT OUTER JOIN HRDF_bfprios_TAB d ON d.stopno = a.stopno AND d.fk_eckdatenid = a.fk_eckdatenid"\ " LEFT OUTER JOIN HRDF_bfkoord_TAB e ON e.stopno = a.stopno AND e.fk_eckdatenid = a.fk_eckdatenid"\ " WHERE a.fk_eckdatenid = %s" curBahnhof = self.__hrdfdb.connection.cursor() curBahnhof.execute(sql_bahnhofLookup, (eckdatenid, )) bahnhoefe = curBahnhof.fetchall() curBahnhof.close() for bahnhof in bahnhoefe: self.__bahnhofLookup[bahnhof[0]] = bahnhof bahnhoefe.clear() # Lookup für Haltepositionstexte aufbauen (a.id zu beginn ist schneller als es wegzulassen oder am Ende zu stellen) # key => <FahrtId>-<StopNo>[-<StopPointTime>] logger.info("Lookup für Haltepositionstexte aufbauen") sql_selGleisData = "SELECT distinct a.id, a.id::varchar||'-'||stopno::varchar||coalesce('-'||stoppointtime::varchar,'') as key, stoppointtext, bitfieldno "\ " FROM HRDF_FPlanFahrt_TAB a, HRDF_GLEIS_TAB b "\ " WHERE a.fk_eckdatenid = %s "\ " AND a.fk_eckdatenid = b.fk_eckdatenid "\ " AND b.tripno = a.tripno "\ " AND b.operationalno = a.operationalno " curGleis = self.__hrdfdb.connection.cursor() curGleis.execute(sql_selGleisData, (eckdatenid, )) allGleise = curGleis.fetchall() curGleis.close() for gleis in allGleise: if (gleis[3] is None or gleis[3] == 0): self.__gleisLookup[gleis[1]] = gleis[2] else: # Gleisangabe ist nur für einen bestimmten Tag => gehört dieser zur Generierungszeitspanne? # Wenn ja dann baue eine Gleis-Tages-LookupTabelle auf i = 0 while (i <= dayCnt): generationDay = generateFrom + timedelta(days=i) if (generationDay in self.__bitfieldnumbersOfDay): if (gleis[3] in self.__bitfieldnumbersOfDay[generationDay]): if (generationDay in self.__gleisLookupDay): self.__gleisLookupDay[generationDay][ gleis[1]] = gleis[2] else: gleisLookup = dict() gleisLookup[gleis[1]] = gleis[2] self.__gleisLookupDay[ generationDay] = gleisLookup # Tageszähler hochzählen und nächsten gewünschten Tag generieren i += 1 allGleise.clear() # Lookup für allTripStops erstellen. allTripStops einer Fahrt enthält den kompletten Laufweg der Fahrt. logger.info("Lookup für Laufwege der Fahrten aufbauen") sql_selStops = "SELECT stopno, stopname, sequenceno, arrtime, deptime, tripno, operationalno, ontripsign, "\ " fk_fplanfahrtid||'-'||stopno as gleislookup, "\ " fk_fplanfahrtid||'-'||stopno||'-'||arrtime as gleislookupArr, "\ " fk_fplanfahrtid||'-'||stopno||'-'||deptime as gleislookupDep, "\ " fk_fplanfahrtid "\ " FROM HRDF_FPlanFahrtLaufweg_TAB WHERE fk_eckdatenid = %s ORDER BY fk_fplanfahrtid, sequenceno" curStop = self.__hrdfdb.connection.cursor() curStop.execute(sql_selStops, (eckdatenid, )) allTripStops = curStop.fetchall() curStop.close() for tripStop in allTripStops: if (tripStop[11] in self.__allTripStopsLookup): self.__allTripStopsLookup[tripStop[11]].append(tripStop) else: tripStopList = list() tripStopList.append(tripStop) self.__allTripStopsLookup[tripStop[11]] = tripStopList allTripStops.clear() # Lookup für allVEs erstellen. allVEs einer Fahrt enthält alle Verkehrstagesdefinitionen einer Fahrt logger.info("Lookup für Verkehrstagesinformation der Fahrten aufbauen") sql_selVEData = "SELECT bitfieldno, fromstop, tostop, deptimefrom, arrtimeto, fk_fplanfahrtid FROM HRDF_FPlanFahrtVE_TAB WHERE fk_eckdatenid = %s ORDER BY fk_fplanfahrtid, id" curVE = self.__hrdfdb.connection.cursor() curVE.execute(sql_selVEData, (eckdatenid, )) allVEs = curVE.fetchall() curVE.close() for fahrtVE in allVEs: if (fahrtVE[5] in self.__allVEsLookup): self.__allVEsLookup[fahrtVE[5]].append(fahrtVE) else: VEList = list() VEList.append(fahrtVE) self.__allVEsLookup[fahrtVE[5]] = VEList allVEs.clear() # Lookup für Linieninformationen der Fahrten logger.info("Lookup für Linieninformationen der Fahrten aufbauen") sql_selLData = "SELECT lineno, fromstop, tostop, deptimefrom, arrtimeto, fk_fplanfahrtid FROM HRDF_FPlanFahrtL_TAB WHERE fk_eckdatenid = %s ORDER BY fk_fplanfahrtid, id" curL = self.__hrdfdb.connection.cursor() curL.execute(sql_selLData, (eckdatenid, )) allLs = curL.fetchall() curL.close() for fahrtL in allLs: if (fahrtL[5] in self.__fahrtLinienLookup): self.__fahrtLinienLookup[fahrtL[5]].append(fahrtL) else: LList = list() LList.append(fahrtL) self.__fahrtLinienLookup[fahrtL[5]] = LList allLs.clear() # Lookup für Richtungstexte der Fahrten logger.info("Lookup für Richtungstexte der Fahrten aufbauen") sql_selRData = "SELECT a.directionshort, fromstop, tostop, deptimefrom, arrtimeto, b.directiontext, fk_fplanfahrtid "\ " FROM HRDF_FPlanFahrtR_TAB a, "\ " HRDF_Richtung_TAB b "\ " WHERE a.fk_eckdatenid = %s "\ " AND a.fk_eckdatenid = b.fk_eckdatenid "\ " AND b.directioncode = a.directioncode "\ " ORDER BY a.fk_fplanfahrtid, a.id" curR = self.__hrdfdb.connection.cursor() curR.execute(sql_selRData, (eckdatenid, )) allRs = curR.fetchall() curR.close() for fahrtR in allRs: if (fahrtR[6] in self.__fahrtRichtungLookup): self.__fahrtRichtungLookup[fahrtR[6]].append(fahrtR) else: RList = list() RList.append(fahrtR) self.__fahrtRichtungLookup[fahrtR[6]] = RList allRs.clear() # Lookup der Attribute einer Fahrt logger.info("Lookup für Attribute der Fahrten aufbauen") sql_selAData = "SELECT a.attributecode as attributecodeArray, fromstop, tostop, deptimefrom, arrtimeto, bitfieldno, "\ " b.attributetext as text_de, "\ " c.attributetext as text_fr, "\ " d.attributetext as text_en, "\ " e.attributetext as text_it, "\ " b.stopcontext as stopcontext, "\ " b.outputforsection as outputforsection, "\ " b.outputforcomplete as outputforcomplete, "\ " a.fk_fplanfahrtid "\ " FROM HRDF_FPlanFahrtA_TAB a "\ " LEFT OUTER JOIN HRDF_Attribut_TAB b ON b.attributecode = a.attributecode and a.fk_eckdatenid = b.fk_eckdatenid and b.languagecode = 'de' "\ " LEFT OUTER JOIN HRDF_Attribut_TAB c ON c.attributecode = a.attributecode and a.fk_eckdatenid = c.fk_eckdatenid and c.languagecode = 'fr' "\ " LEFT OUTER JOIN HRDF_Attribut_TAB d ON d.attributecode = a.attributecode and a.fk_eckdatenid = d.fk_eckdatenid and d.languagecode = 'en' "\ " LEFT OUTER JOIN HRDF_Attribut_TAB e ON e.attributecode = a.attributecode and a.fk_eckdatenid = e.fk_eckdatenid and e.languagecode = 'it' "\ " WHERE a.fk_eckdatenid = %s " curA = self.__hrdfdb.connection.cursor() curA.execute(sql_selAData, (eckdatenid, )) allAs = curA.fetchall() curA.close() for fahrtA in allAs: if (fahrtA[13] in self.__fahrtAttributLookup): self.__fahrtAttributLookup[fahrtA[13]].append(fahrtA) else: AList = list() AList.append(fahrtA) self.__fahrtAttributLookup[fahrtA[13]] = AList allAs.clear() # Lookup für die Infotext einer Fahrt logger.info("Lookup für Infotexte der Fahrten aufbauen") sql_selIData = "SELECT a.infotextcode, fromstop, tostop, deptimefrom, arrtimeto, bitfieldno, "\ " b.infotext as text_de, "\ " c.infotext as text_fr, "\ " d.infotext as text_en, "\ " e.infotext as text_it, "\ " a.fk_fplanfahrtid "\ " FROM HRDF_FPlanFahrtI_TAB a "\ " LEFT OUTER JOIN HRDF_Infotext_TAB b ON b.infotextno = a.infotextno and a.fk_eckdatenid = b.fk_eckdatenid and b.languagecode = 'de' "\ " LEFT OUTER JOIN HRDF_Infotext_TAB c ON c.infotextno = a.infotextno and a.fk_eckdatenid = c.fk_eckdatenid and c.languagecode = 'fr' "\ " LEFT OUTER JOIN HRDF_Infotext_TAB d ON d.infotextno = a.infotextno and a.fk_eckdatenid = d.fk_eckdatenid and d.languagecode = 'en' "\ " LEFT OUTER JOIN HRDF_Infotext_TAB e ON e.infotextno = a.infotextno and a.fk_eckdatenid = e.fk_eckdatenid and e.languagecode = 'it' "\ " WHERE a.fk_eckdatenid = %s " curI = self.__hrdfdb.connection.cursor() curI.execute(sql_selIData, (eckdatenid, )) allIs = curI.fetchall() curI.close() for fahrtI in allIs: if (fahrtI[10] in self.__fahrtInfoLookup): self.__fahrtInfoLookup[fahrtI[10]].append(fahrtI) else: IList = list() IList.append(fahrtI) self.__fahrtInfoLookup[fahrtI[10]] = IList allIs.clear() # Lookup für die DurchbindungsInformation zu einer Fahrt logger.info("Lookup für Durchbindungsinformation der Fahrten aufbauen") sql_selDurchBiData = "SELECT b.laststopno1, b.bitfieldno, b.tripno2, b.operationalno2, coalesce(b.firststopno2, b.laststopno1), b.comment, a.id "\ " FROM HRDF_FPlanFahrt_TAB a, "\ " HRDF_DURCHBI_TAB b "\ " WHERE b.tripno1 = a.tripno "\ " AND b.operationalno1 = a.operationalno "\ " AND b.fk_eckdatenid = a.fk_eckdatenid "\ " AND a.fk_eckdatenid = %s " curDurchBi = self.__hrdfdb.connection.cursor() curDurchBi.execute(sql_selDurchBiData, (eckdatenid, )) allDurchBi = curDurchBi.fetchall() curDurchBi.close() for fahrtDuBI in allDurchBi: if (fahrtDuBI[6] in self.__fahrtDurchbindungLookup): self.__fahrtDurchbindungLookup[fahrtDuBI[6]].append(fahrtDuBI) else: DuBiList = list() DuBiList.append(fahrtDuBI) self.__fahrtDurchbindungLookup[fahrtDuBI[6]] = DuBiList allDurchBi.clear()
def generateTT(self): """ Die Funktion generiert den gewünschten Tagesfahrplan bzgl. der Daten, die über setup() bestimmt wurden""" iErrorCnt = 0 logger.info("Anzahl der Worker: {}".format(self.__numberOfWorker)) logger.info("Arbeitspaketgröße: {}".format(self.__chunkSize)) # Aufbau/Erzeugen des TTG-Cache mit den Lookup-Tabellen self.__TTGCache.createCacheData(self.__eckdatenid, self.__generateFrom, self.__generateTo) sql_selDayTrips = "SELECT b.id, b.tripno, b.operationalno, b.tripversion, array_agg(a.bitfieldno) as bitfieldnos, b.cyclecount, b.cycletimemin "\ "FROM HRDF_FPlanFahrtVE_TAB a, "\ " HRDF_FPLanFahrt_TAB b "\ "WHERE (a.bitfieldno in (SELECT bitfieldno FROM HRDF_Bitfeld_TAB where bitfieldarray @> ARRAY[%s::date] AND fk_eckdatenid = %s) "\ " OR a.bitfieldno is NULL OR a.bitfieldno = 0) "\ " and a.fk_fplanfahrtid = b.id "\ " and b.fk_eckdatenid = a.fk_eckdatenid "\ " and a.fk_eckdatenid = %s "\ "GROUP BY b.id, b.tripno, b.operationalno, b.tripversion" # Worker anlegen und starten workerPool = [] for x in range(self.__numberOfWorker): worker = HrdfTTGWorker(self.__hrdfdb, x, "worker-" + str(x), self.__workQueue, self.__commQueue, self.__responseQueue, self.__TTGCache) workerPool.append(worker) dayCnt = (self.__generateTo - self.__generateFrom).days i = 0 while (i <= dayCnt): generationDay = self.__generateFrom + timedelta(days=i) # Löschen bestehender Tagesfahrten => Sicherstellen, dass bestehende Daten gelöscht werden bevor neue generiert werden logger.info( "{:%d.%m.%Y} => Löschen des bestehenden Tagesfahrplan".format( generationDay)) self.deleteDailyTimetable(self.__eckdatenid, generationDay) logger.info( "{:%d.%m.%Y} => Start der Generierung".format(generationDay)) # mit einer Schleife über den selDayTrip-Cursor, der in self.__chunkSize - Blöcken abgearbeitet wird curDayTrip = self.__hrdfdb.connection.cursor("cursor_selDayTrip") curDayTrip.execute( sql_selDayTrips, (str(generationDay), self.__eckdatenid, self.__eckdatenid)) currentRowCnt = 0 paketCnt = 0 while True: trips = curDayTrip.fetchmany(self.__chunkSize) if not trips: break paketCnt += 1 # Schiebe die zu generierenden Trips in die Workqueue, damit sie dort von den Workern abgeholt werden können dataItem = dict(eckdatenid=self.__eckdatenid, day=generationDay, trips=trips) self.__workQueue.put(dataItem.copy()) currentRowCnt += len(trips) # Aufbau einer tagesbezogenen Response-Datenstruktur zur Verarbeitung der Ergebnisse der Worker logger.info( "{:%d.%m.%Y} => {} Fahrten wurden in {} Arbeitspakete aufgeteilt" .format(generationDay, currentRowCnt, paketCnt)) self.__responseData[generationDay] = dict(paketCnt=paketCnt, receivedPakets=0) curDayTrip.close() # Nachdem der erste Tag aufgeteilt ist, können die Worker gestartet werden if (i == 0): for worker in workerPool: worker.start() # Tageszähler hochzählen und nächsten gewünschten Tag generieren i += 1 # Auf Responsedaten warten und dann verarbeiten moreResponseData = True while moreResponseData: responseData = self.__responseQueue.get() #self.__responseData[responseData["day"]]["dataItems"].add(responseData["data"]) self.__responseData[responseData["day"]]["receivedPakets"] += 1 logger.info( "{:%d.%m.%Y} => Tagesfahrplanpaket {} wird gesichert".format( responseData["day"], self.__responseData[ responseData["day"]]["receivedPakets"])) _start_new_thread(self.saveNewDailyTimetable, ( self.__eckdatenid, responseData["day"], responseData["data"], self.__responseData[responseData["day"]]["paketCnt"], self.__responseData[responseData["day"]]["receivedPakets"], )) # Prüfen ob alle Pakete aller Tage gespeichert wurden allComplete = True for day, resData in self.__responseData.items(): if (resData["paketCnt"] > resData["receivedPakets"]): allComplete = False break if (allComplete): moreResponseData = False # Mindestens ein DB-Thread sollte gestartet worden sein while not self.__DBThreadStarted: time.sleep(5) # Alle DB-Threads müssen sich beendet haben while self.__numOfCurrentDBThreads > 0: time.sleep(5) # Warten bis alle dataItem abgearbeitet sind self.__workQueue.join() # Kontrolliertes schließen der Threads self.__commQueue.put(True) # Warten auf Beenden der Worker for worker in workerPool: worker.join() return iErrorCnt
def saveNewDailyTimetable(self, eckdatenid, generationDay, ttChunk, paketCnt, receivedPackets): """ Die Funktion speichert den übergebenen TimeTable-Chunk in der Datenbank. Um konsistent zu bleiben wird der bestehende Tagesfahrplan zuerst gelöscht Die Funktion wird als Thread aufgerufen eckdatenid - id der Fahrplandaten generationDay - Generierungsdatum ttChunk - Chunk (csv-Sting) eines Tagesfahrplans paketCnt - Anzahl der Pakete für diesen Tag """ self.__lock.acquire() self.__numOfCurrentDBThreads += 1 self.__DBThreadStarted = True self.__lock.release() # Lokale DB-Verbindung erstellen hrdfDBSingle = HrdfDB(self.__hrdfdb.dbname, self.__hrdfdb.host, self.__hrdfdb.user, self.__hrdfdb.password) if (hrdfDBSingle.connect()): # Das Löschen des Tagesfahrplans erfolgt kontrolliert vor dem Starten der Threads, die den neuen Fahrplan sichern # Speichern des Chunks in der Datenbank curSaveTrip = hrdfDBSingle.connection.cursor() strCopy = "COPY HRDF_DailyTimeTable_TAB (fk_eckdatenid,tripident,tripno,operationalno,tripversion,"\ "operatingday,stopsequenceno,stopident,stopname,stoppointident,stoppointname,arrstoppointtext,depstoppointtext,arrdatetime,depdatetime,noentry,noexit,"\ "categorycode,classno,categoryno,lineno,directionshort,directiontext,"\ "attributecode,attributetext_de,attributetext_fr,attributetext_en,attributetext_it,"\ "infotextcode,infotext_de,infotext_fr,infotext_en,infotext_it,"\ "longitude_geo,latitude_geo,altitude_geo,transfertime1,transfertime2,transferprio,tripno_continued,operationalno_continued,stopno_continued)"\ " FROM STDIN USING DELIMITERS ';' NULL AS ''" #logger.info("Sichern Chunk {} von {} für Tag {:%d.%m.%Y}".format(receivedPackets, paketCnt, generationDay)) dailytimetable_strIO = StringIO() dailytimetable_strIO.write(ttChunk) dailytimetable_strIO.seek(0) curSaveTrip.copy_expert(strCopy, dailytimetable_strIO) dailytimetable_strIO.close() curSaveTrip.close() hrdfDBSingle.connection.commit() # Beim letzten Paket if (receivedPackets == paketCnt): logger.info( "{:%d.%m.%Y} => Neuer Tagesfahrplan wurde komplett gesichert" .format(generationDay)) # Aktualisieren der Eckdatentabelle mit dem neuen Tag curUpdTTGenerated = hrdfDBSingle.connection.cursor() sql_updTTGenerated = "UPDATE HRDF.HRDF_Eckdaten_TAB SET ttgenerated = array_append(ttgenerated, %s) WHERE id = %s" curUpdTTGenerated.execute(sql_updTTGenerated, (str(generationDay), eckdatenid)) curUpdTTGenerated.close() hrdfDBSingle.connection.commit() else: logger.error( "{:%d.%m.%Y} => DB-Thread konnte keine Verbindung zur Datenbank aufbauen" .format(generationDay)) # DB-Thread-Zähler wieder zurücksetzen self.__lock.acquire() self.__numOfCurrentDBThreads -= 1 self.__lock.release()
def processTrips(self, eckdatenid, generationDay, trips): """ Die Funktion generiert den Tagesfahrplan für die übergebenen Trips am gewünschten Tag""" if (len(trips) > 1): #logger.error("{}: bearbeitet {} Fahrten".format(self.__name, len(trips))) tripStops = dict() dailytimetable_strIO = StringIO() numberOfGeneratedTrips = 0 iErrorCnt = 0 for trip in trips: tripStops.clear() origtripident = "{}-{}-{}".format(trip[1], trip[2], trip[3]) try: self.generateTrip(trip, tripStops, generationDay) # Ein Trip kann Taktdefinitionen enthalten, dann muss diese Fahrt mit ihren Stops x mal mit versetzten Zeiten eingetragen werden # Um die Einträge eindeutig der gleichen Fahrt zuordnen zu können wird bei Taktdefinitionen der TripIdentifier erweitert cycletimemin = 0 cyclecount = 0 cycledefs = False if (trip[5] is not None): cycledefs = True cyclecount = trip[5] cycletimemin = trip[6] i = 0 while i <= cyclecount: additionalCycletimeMin = cycletimemin * i # Erweiterung des TripIdentifiers um eine 4-stellige Zahl mit führenden Nullen # 1440 Minuten = 24 Std bei minütlicher Taktung if (cycledefs == True): tripident = "{}-{:04d}".format(origtripident, i) else: tripident = origtripident # Schreibe Fahrtinformation in Tabellenformat for tripStop in tripStops.values(): arrival = tripStop["stop"][3] departure = tripStop["stop"][4] noentry = False noexit = False arrdatetime = "" if (arrival is not None): if (arrival < 0): noexit = True arrival = abs(arrival) arrMins = (int(arrival / 100) * 60) + ( arrival % 100) + additionalCycletimeMin arrdatetime = str( datetime.combine(generationDay, time(0, 0)) + timedelta(minutes=arrMins)) depdatetime = "" if (departure is not None): if (departure < 0): noenty = True departure = abs(departure) depMins = (int(departure / 100) * 60) + ( departure % 100) + additionalCycletimeMin depdatetime = str( datetime.combine(generationDay, time(0, 0)) + timedelta(minutes=depMins)) # Attribute strAttributecode = "" strAttributetextDE = "" strAttributetextFR = "" strAttributetextEN = "" strAttributetextIT = "" if (len(tripStop["attributecode"]) > 0): strAttributecode = "{'" + "','".join( map(str, tripStop["attributecode"])) + "'}" if (len(tripStop["attributetext_de"]) > 0): strAttributetextDE = "{'" + "','".join( map(str, tripStop["attributetext_de"])) + "'}" if (len(tripStop["attributetext_fr"]) > 0): strAttributetextFR = "{'" + "','".join( map(str, tripStop["attributetext_fr"])) + "'}" if (len(tripStop["attributetext_en"]) > 0): strAttributetextEN = "{'" + "','".join( map(str, tripStop["attributetext_en"])) + "'}" if (len(tripStop["attributetext_it"]) > 0): strAttributetextIT = "{'" + "','".join( map(str, tripStop["attributetext_it"])) + "'}" # Infotexte strInfotextcode = "" strInfotextDE = "" strInfotextFR = "" strInfotextEN = "" strInfotextIT = "" if (len(tripStop["infotextcode"]) > 0): strInfotextcode = '{"' + '","'.join( map(self.infohelp, tripStop["infotextcode"])) + '"}' if (len(tripStop["infotext_de"]) > 0): strInfotextDE = '{"' + '","'.join( map(self.infohelp, tripStop["infotext_de"])) + '"}' if (len(tripStop["infotext_fr"]) > 0): strInfotextFR = '{"' + '","'.join( map(self.infohelp, tripStop["infotext_fr"])) + '"}' if (len(tripStop["infotext_en"]) > 0): strInfotextEN = '{"' + '","'.join( map(self.infohelp, tripStop["infotext_en"])) + '"}' if (len(tripStop["infotext_it"]) > 0): strInfotextIT = '{"' + '","'.join( map(self.infohelp, tripStop["infotext_it"])) + '"}' # Angaben zur Haltestelle strLongitudeGeo = "" strLatitudeGeo = "" strAltitudeGeo = "" strTransferTime1 = "" strTransferTime2 = "" strTransferPrio = "" strTripNoContinued = "" strOperationalNoContinued = "" strStopNoContinued = "" if (tripStop["longitude_geo"] is not None): strLongitudeGeo = str( tripStop["longitude_geo"]) if (tripStop["latitude_geo"] is not None): strLatitudeGeo = str(tripStop["latitude_geo"]) if (tripStop["altitude_geo"] is not None): strAltitudeGeo = str(tripStop["altitude_geo"]) if (tripStop["transfertime1"] is not None): strTransferTime1 = str( tripStop["transfertime1"]) if (tripStop["transfertime2"] is not None): strTransferTime2 = str( tripStop["transfertime2"]) if (tripStop["transferprio"] is not None): strTransferPrio = str(tripStop["transferprio"]) if (tripStop["tripno_continued"] is not None): strTripNoContinued = str( tripStop["tripno_continued"]) if (tripStop["operationalno_continued"] is not None): strOperationalNoContinued = str( tripStop["operationalno_continued"]) if (tripStop["stopno_continued"] is not None): strStopNoContinued = str( tripStop["stopno_continued"]) # Schreiben des Datensatzes dailytimetable_strIO.write(eckdatenid) dailytimetable_strIO.write(';') dailytimetable_strIO.write(tripident) dailytimetable_strIO.write(';') dailytimetable_strIO.write(str(trip[1])) dailytimetable_strIO.write(';') dailytimetable_strIO.write(trip[2]) dailytimetable_strIO.write(';') dailytimetable_strIO.write(str(trip[3])) dailytimetable_strIO.write(';') dailytimetable_strIO.write(str(generationDay)) dailytimetable_strIO.write(';') dailytimetable_strIO.write(str( tripStop["stop"][2])) dailytimetable_strIO.write(';') dailytimetable_strIO.write(str( tripStop["stop"][0])) dailytimetable_strIO.write(';') dailytimetable_strIO.write(tripStop["stop"][1]) dailytimetable_strIO.write(';') dailytimetable_strIO.write(str( tripStop["stop"][0])) dailytimetable_strIO.write(';') dailytimetable_strIO.write(tripStop["stop"][1]) dailytimetable_strIO.write(';') dailytimetable_strIO.write( tripStop["arrstoppointtext"]) dailytimetable_strIO.write(';') dailytimetable_strIO.write( tripStop["depstoppointtext"]) dailytimetable_strIO.write(';') dailytimetable_strIO.write(arrdatetime) dailytimetable_strIO.write(';') dailytimetable_strIO.write(depdatetime) dailytimetable_strIO.write(';') dailytimetable_strIO.write(str(noentry)) dailytimetable_strIO.write(';') dailytimetable_strIO.write(str(noexit)) dailytimetable_strIO.write(';') dailytimetable_strIO.write( tripStop["categorycode"]) dailytimetable_strIO.write(';') dailytimetable_strIO.write(str( tripStop["classno"])) dailytimetable_strIO.write(';') dailytimetable_strIO.write( str(tripStop["categoryno"])) dailytimetable_strIO.write(';') dailytimetable_strIO.write(tripStop["lineno"]) dailytimetable_strIO.write(';') dailytimetable_strIO.write( tripStop["directionshort"]) dailytimetable_strIO.write(';') dailytimetable_strIO.write( tripStop["directiontext"]) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strAttributecode) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strAttributetextDE) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strAttributetextFR) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strAttributetextEN) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strAttributetextIT) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strInfotextcode) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strInfotextDE) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strInfotextFR) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strInfotextEN) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strInfotextIT) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strLongitudeGeo) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strLatitudeGeo) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strAltitudeGeo) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strTransferTime1) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strTransferTime2) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strTransferPrio) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strTripNoContinued) dailytimetable_strIO.write(';') dailytimetable_strIO.write( strOperationalNoContinued) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strStopNoContinued) dailytimetable_strIO.write('\n') numberOfGeneratedTrips += 1 i += 1 except Exception as err: iErrorCnt += 1 logger.error( "Die Fahrt {} konnte nicht generiert werden. Error:\n{}" .format(tripident, err)) # Alle Fahrten des Sets im IO abgelegt => Zurückgabe an den Main-Thread logger.info( "\t{}: {:%d.%m.%Y} => {} Tagesfahrplaneinträge erstellt ...". format(self.__name, generationDay, numberOfGeneratedTrips)) # Ergebnis liefern dailytimetable_strIO.seek(0) self.__responseQueue.put( dict(day=generationDay, data=dailytimetable_strIO.getvalue())) dailytimetable_strIO.close() tripStops.clear()
def read_fplan(self, filename): """Lesen der Datei FPLAN""" logger.info('lesen und verarbeiten der Datei FPLAN') curIns = self.__hrdfdb.connection.cursor() bDataLinesRead = False iSequenceCnt = 0 for line in fileinput.input(filename, openhook=self.__hrdfzip.open): line = line.decode(self.__charset).replace('\r\n','') if line[:1] == '*': if bDataLinesRead: # Datenzeilen wurden gelesen, wir sind jetzt wieder beim nächsten Zug und schreiben den Vorgänger erstmal in die DB self.save_currentFplanFahrt() bDataLinesRead = False iSequenceCnt = 0 # Attribut-Zeilen (!! längste Attribut-Kennung zuerst abfragen, dann weiter absteigend !!) if line[:5] == "*A VE": if self.__AVE_type == "*Z" or self.__AVE_type == "*T": self.__fplanFahrtAVE_strIO.write(self.__fkdict["fk_eckdatenid"]+';' +self.__fkdict["fk_fplanfahrtid"]+';' +line[6:13].strip()+';' +line[14:21].strip()+';' +line[22:28].strip()+';' +line[29:35].strip()+';' +line[36:42].strip()+ '\n') else: logger.warning("*A VE-Zeile gehört zu nicht unterstützter "+self.__AVE_type+"-Zeile und wird nicht verarbeitet") elif line[:4] == "*KWZ": self.__AVE_type = line[:4] logger.warning("Zeile "+line[:4]+" wird derzeit nicht unterstützt") elif line[:3] == "*KW" or line[:3] == "*TT": self.__AVE_type = line[:3] logger.warning("Zeile "+line[:3]+" wird derzeit nicht unterstützt") elif line[:3] == "*SH": self.__fplanFahrtSH_strIO.write(self.__fkdict["fk_eckdatenid"]+';' +self.__fkdict["fk_fplanfahrtid"]+';' +line[4:11].strip()+';' +line[12:18].strip()+';' +line[19:25].strip()+ '\n') elif line[:3] == "*GR": self.__fplanFahrtGR_strIO.write(self.__fkdict["fk_eckdatenid"]+';' +self.__fkdict["fk_fplanfahrtid"]+';' +line[4:11].strip()+';' +line[12:19].strip()+';' +line[20:27].strip()+';' +line[28:34].strip()+';' +line[35:41].strip()+ '\n') elif line[:2] == "*B" or line[:2] == "*E": logger.warning("Zeile "+line[:2]+" wird derzeit nicht unterstützt") elif line[:2] == "*Z": self.__AVE_type = line[:2] sql_string = "INSERT INTO HRDF_FPLANFahrt_TAB (fk_eckdatenid,triptype,tripno,operationalno,tripversion,cyclecount,cycletimemin) VALUES (%s,%s,%s,%s,%s,%s,%s) RETURNING id;" cyclecount = line[22:25].strip() cycletimemin = line[26:29].strip() if not cyclecount: cyclecount = None if not cycletimemin: cycletimemin = None curIns.execute(sql_string, (self.__fkdict['fk_eckdatenid'], line[1:2], line[3:8], line[9:15], line[18:21], cyclecount, cycletimemin)) self.__fkdict["fk_fplanfahrtid"] = str(curIns.fetchone()[0]) elif line[:2] == "*T": self.__AVE_type = line[:2] sql_string = "INSERT INTO HRDF_FPLANFahrt_TAB (fk_eckdatenid,triptype,tripno,operationalno,triptimemin,cycletimesec) VALUES (%s,%s,%s,%s,%s,%s,%s) RETURNING id;" triptimemin = line[16:20].strip() cycletimesec = line[21:25].strip() if not triptimemin: triptimemin = None if not cycletimesec: cycletimesec = None curIns.execute(sql_string, (self.__fkdict['fk_eckdatenid'], line[1:2], line[3:8], line[9:15], triptimemin, cycletimesec)) self.__fkdict["fk_fplanfahrtid"] = str(curIns.fetchone()[0]) elif line[:2] == "*C": checkinTime = ''; checkoutTime = ''; if line[:3] == "*CI": checkinTime = line[4:8].strip(); if line[:3] == "*CO": checkoutTime = line[4:8].strip(); self.__fplanFahrtC_strIO.write(self.__fkdict["fk_eckdatenid"]+';' +self.__fkdict["fk_fplanfahrtid"]+';' +checkinTime+';' +checkoutTime+';' +line[9:16].strip()+';' +line[17:24].strip()+';' +line[25:31].strip()+';' +line[32:38].strip()+ '\n') elif line[:2] == "*G": self.__fplanFahrtG_strIO.write(self.__fkdict["fk_eckdatenid"]+';' +self.__fkdict["fk_fplanfahrtid"]+';' +line[3:6].strip()+';' +line[7:14].strip()+';' +line[15:22].strip()+';' +line[23:29].strip()+';' +line[30:36].strip()+ '\n') elif line[:2] == "*A": self.__fplanFahrtA_strIO.write(self.__fkdict["fk_eckdatenid"]+';' +self.__fkdict["fk_fplanfahrtid"]+';' +line[3:5].strip()+';' +line[6:13].strip()+';' +line[14:21].strip()+';' +line[22:28].strip()+';' +line[29:35].strip()+';' +line[36:42].strip()+ '\n') elif line[:2] == "*R": self.__fplanFahrtR_strIO.write(self.__fkdict["fk_eckdatenid"]+';' +self.__fkdict["fk_fplanfahrtid"]+';' +line[3:4].strip()+';' +line[5:12].strip()+';' +line[13:20].strip()+';' +line[21:28].strip()+';' +line[29:35].strip()+';' +line[36:42].strip()+ '\n') elif line[:2] == "*I": self.__fplanFahrtI_strIO.write(self.__fkdict["fk_eckdatenid"]+';' +self.__fkdict["fk_fplanfahrtid"]+';' +line[3:5].strip()+';' +line[29:36].strip()+';' +line[6:13].strip()+';' +line[14:21].strip()+';' +line[22:28].strip()+';' +line[37:43].strip()+';' +line[44:50].strip()+ '\n') elif line[:2] == "*L": self.__fplanFahrtL_strIO.write(self.__fkdict["fk_eckdatenid"]+';' +self.__fkdict["fk_fplanfahrtid"]+';' +line[3:11].strip()+';' +line[12:19].strip()+';' +line[20:27].strip()+';' +line[28:34].strip()+';' +line[35:41].strip()+ '\n') else: # Laufwegszeilen bDataLinesRead = True if (line[:1] == "+"): logger.warning("Laufwegsdaten mit Regionen werden nicht unterstützt") else: self.__fplanFahrtLauf_strIO.write(self.__fkdict["fk_eckdatenid"]+';' +self.__fkdict["fk_fplanfahrtid"]+';' +line[:7].strip()+';' +line[8:29].strip()+';' +str(iSequenceCnt)+';' +line[29:35].strip()+';' +line[36:42].strip()+';' +line[43:48].strip()+';' +line[49:55].strip()+';' +line[56:57].strip()+ '\n') iSequenceCnt += 1 # Nach dem Durchlauf der Schleife muss der letzte Zug noch gespeichert werden if bDataLinesRead: self.save_currentFplanFahrt() bDataLinesRead = False iSequenceCnt = 0 curIns.close()
def read_metabhf(self, filename): """Lesen der Datei METABHF""" logger.info('lesen und verarbeiten der Datei METABHF') metabhfUB_strIO = StringIO() metabhfHG_strIO = StringIO() previousUB = False strStopNoFrom = None; strStopNoTo = None; strTransferTimeMin = None; strTransferTimeSec = None; strAttributeCodes = ""; attributeCodeList = list(); stopMemberList = list(); for line in fileinput.input(filename, openhook=self.__hrdfzip.open): line = line.decode(self.__charset).replace('\r\n', '') if line[:1] == '*': # Attributszeile der Übergangsbeziehung if line[1:2] == 'A': # Uns interessieren momentan nur die A-Zeilen (Attributecode) attributeCodeList.append(line[3:5].strip()) elif line[7:8] == ':': # Haltestellengruppen-Zeile # Ist noch eine offene Übergangsbeziehung vorhanden? Die muss noch gespeichert werden if (previousUB): if (len(attributeCodeList) > 0): strAttributeCodes = "{'" + "','".join(map(str,attributeCodeList)) + "'}" metabhfUB_strIO.write(self.__fkdict['fk_eckdatenid']+';' +strStopNoFrom+';' +strStopNoTo+';' +strTransferTimeMin+';' +strTransferTimeSec+';' +strAttributeCodes +'\n') # Zurücksetzen der Attributcodes-Liste attributeCodeList.clear(); strAttributeCodes = ""; previousUB = False; # Behandlung der Haltestellengruppen-Zeile # Erster Stop beginnt bei Zeichen 10, danach beliebig viele Stops in der Länge von 7 Zeichen stopMemberList.clear() strStopMember = "" nextMemberStart = 10 while (nextMemberStart < len(line)): stopMemberList.append(line[nextMemberStart:nextMemberStart+7]) nextMemberStart = nextMemberStart+9 if (len(stopMemberList) > 0): strStopMember = "{" + ",".join(map(str,stopMemberList)) + "}" metabhfHG_strIO.write(self.__fkdict['fk_eckdatenid']+';' +line[10:17]+';' +strStopMember +'\n') else: # 1. Zeile einer Übergangsbeziehung if (previousUB): # Sichern der Übergangsbeziehung if (len(attributeCodeList) > 0): strAttributeCodes = "{'" + "','".join(map(str,attributeCodeList)) + "'}" metabhfUB_strIO.write(self.__fkdict['fk_eckdatenid']+';' +strStopNoFrom+';' +strStopNoTo+';' +strTransferTimeMin+';' +strTransferTimeSec+';' +strAttributeCodes +'\n') # Zurücksetzen der Attributcodes-Liste attributeCodeList.clear(); strAttributeCodes = ""; strStopNoFrom = line[:7] strStopNoTo = line[8:15] strTransferTimeMin = line[16:19] strTransferTimeSec = line[20:22] previousUB = True metabhfUB_strIO.seek(0) curUB = self.__hrdfdb.connection.cursor() curUB.copy_expert("COPY HRDF_METABHF_TAB (fk_eckdatenid,stopnofrom,stopnoto,transfertimemin,transfertimesec,attributecode) FROM STDIN USING DELIMITERS ';' NULL AS ''", metabhfUB_strIO) self.__hrdfdb.connection.commit() curUB.close() metabhfUB_strIO.close() metabhfHG_strIO.seek(0) curHG = self.__hrdfdb.connection.cursor() curHG.copy_expert("COPY HRDF_METABHFGRUPPE_TAB (fk_eckdatenid,stopgroupno,stopmember) FROM STDIN USING DELIMITERS ';' NULL AS ''", metabhfHG_strIO) self.__hrdfdb.connection.commit() curHG.close() metabhfHG_strIO.close()