From 80bbeeabbf29058770db03aaa2154b0e15b4339d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20Ha=C3=9Fel?= Date: Mon, 29 Sep 2025 16:16:26 +0200 Subject: [PATCH] docstring FIX --- pegelonline_dockwidget_graph.py | 17 +- po_modules/po_graph_reader.py | 13 +- po_modules/po_station.py | 12 + po_modules/po_station_reader.py | 12 +- po_modules/po_stations_reader_qgs.py | 9 + po_modules/po_waterlevel.py | 14 +- po_modules/po_waterlevel_reader.py | 27 +- po_modules/po_waterlevels_reader_qgs.py | 9 + po_modules/urlreader.py | 79 ++-- po_runner.py | 503 +++++++++++------------- 10 files changed, 364 insertions(+), 331 deletions(-) diff --git a/pegelonline_dockwidget_graph.py b/pegelonline_dockwidget_graph.py index 7bd8711..1dc7efd 100644 --- a/pegelonline_dockwidget_graph.py +++ b/pegelonline_dockwidget_graph.py @@ -43,15 +43,14 @@ class PegelonlineDockWidgetGraph(QtWidgets.QDockWidget, FORM_CLASS): self.closingPlugin.emit() event.accept() - """ - Versucht den aktuell gewünschten Pegelstandsverlauf herunterzuladen und im GraphWidget anzuzeigen. - :param station: Der 'Kurzname' der gewünschten Station - :type station: str - :param days: Anzahl der gewünschten vergangenen Tage - :type days: int - """ - def load(self, station, days): + """ + Versucht den aktuell gewünschten Pegelstandsverlauf herunterzuladen und im GraphWidget anzuzeigen. + :param station: Der 'Kurzname' der gewünschten Station + :type station: str + :param days: Anzahl der gewünschten vergangenen Tage + :type days: int + """ print("PegelonlineDockWidgetGraph::load: station=%s days=%s" % (station, days)) self.lbGraph.clear() @@ -84,4 +83,4 @@ class PegelonlineDockWidgetGraph(QtWidgets.QDockWidget, FORM_CLASS): self.lbGraph.setPixmap(pixmap) self.lbGraph.resize(pixmap.width(), pixmap.height()) - print("PegelonlineDockWidgetGraph::load: Bild erfolgreich geladen") \ No newline at end of file + print("PegelonlineDockWidgetGraph::load: Bild erfolgreich geladen") diff --git a/po_modules/po_graph_reader.py b/po_modules/po_graph_reader.py index 056c205..5ca5a50 100644 --- a/po_modules/po_graph_reader.py +++ b/po_modules/po_graph_reader.py @@ -7,13 +7,24 @@ from .urlreader import UrlReader class PoGraphReader(UrlReader): def __init__(self, station: str, days: int): + """ + Initialisiert die Super-Klasse mit einer URL aus gegebener Station und Anzahl Tage + :param station: Kurzname der gewünschten Station + :type station: str + :param days: gewünschte Anzahl an Tagen + :type days: int + """ super().__init__(poBaseURL + 'stations/%s/W/measurements.png?start=P%dD' % (quote(station), days)) def download(self): + """ + Versucht die Grafik über die super.get_data_response Methode herunterzuladen + """ print("PoGraphReader::download: Lade Bild herunter...") - image_data = self.getDataResponse() + image_data = self.get_data_response() if image_data is None or len(image_data) == 0: + # Keine Daten erhalten → Abbruch print("PoGraphReader::download: Fehler: Keine Daten erhalten") return None diff --git a/po_modules/po_station.py b/po_modules/po_station.py index 561beb8..c09542d 100644 --- a/po_modules/po_station.py +++ b/po_modules/po_station.py @@ -4,6 +4,11 @@ from qgis._core import QgsFeature, QgsGeometry, QgsPointXY class PoStation(object): def __init__(self, json): + """ + Nimmt JSON-Daten einer Pegelonline-Station entgegen und füllt die entsprechenden Felder + :param json: Json-Daten einer Station + :type json: dict + """ self.longitude = json['longitude'] if 'longitude' in json else None self.latitude = json['latitude'] if 'latitude' in json else None self.uuid = json['uuid'] @@ -15,7 +20,14 @@ class PoStation(object): self.water = json['water']['longname'] def new_feature(self, fields) -> None | QgsFeature: + """ + Erzeugt ein QgsFeature mit Attributen dieser Station oder None im Fehlerfall + :param fields: QgsField-Liste um das Feature zu befüllen + :type fields: list[QgsField] + :return: None | QgsFeature + """ if self.longitude is None or self.latitude is None: + # Keine Koordinaten → Abbruch print("PoStation::new_feature: WARN: Station hat fehlende Koordinaten: %s" % (self.shortname,)) return None diff --git a/po_modules/po_station_reader.py b/po_modules/po_station_reader.py index 397c52e..4ca37e0 100644 --- a/po_modules/po_station_reader.py +++ b/po_modules/po_station_reader.py @@ -6,21 +6,31 @@ from .urlreader import UrlReader class PoStationReader(UrlReader): def __init__(self): + """ + Initialisiert die Super-Klasse mit URL für die Stationen + """ super().__init__(poBaseURL + 'stations.json') def get_stations(self): + """ + Fragt die Liste aller Stationen via UrlReader.get_json_response ab und macht PoStation daraus oder None im Fehlerfall + :return: list[PoStation] | None + """ print("PoStationReader::get_stations: Lade Stationen herunter...") - stations_json = self.getJsonResponse() + stations_json = self.get_json_response() if stations_json is None or len(stations_json) == 0: + # Keine Stationen erhalten → Abbruch print("PoStationReader::get_stations: Keine Stationen erhalten") return None stations = [] for station_json in stations_json: try: + # Versuche eine Station zu erstellen stations.append(PoStation(station_json)) except Exception as e: + # Fehler → Überspringe diese Station print("PoStationReader::get_stations: Fehler: error=%s, json=%s" % (e, station_json)) print("PoStationReader::get_stations: %d Stationen erhalten" % (len(stations),)) diff --git a/po_modules/po_stations_reader_qgs.py b/po_modules/po_stations_reader_qgs.py index e9c0359..48cedf1 100644 --- a/po_modules/po_stations_reader_qgs.py +++ b/po_modules/po_stations_reader_qgs.py @@ -8,11 +8,18 @@ from .po_station_reader import PoStationReader class PoStationReaderQgs(PoStationReader): def __init__(self): + """ + Initialisiert die Super-Klasse und das Koordinaten-System der Features + """ super().__init__() self.fields = None self.crs = QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId) def get_features(self): + """ + Erzeugt Features aus allen Stationen von super.get_stations() oder None im Fehlerfall + :return: list[QgsFeature] | None + """ print("PoStationReaderQgs::get_features: Erzeuge Features...") self.fields = QgsFields() @@ -28,12 +35,14 @@ class PoStationReaderQgs(PoStationReader): stations = self.get_stations() if stations is None or len(stations) == 0: + # Keine Stationen erhalten → Abbruch print("PoStationReaderQgs::get_features: Fehler: Keine Stationen erhalten") return None for station in stations: feature = station.new_feature(self.fields) if feature is not None: + # Feature-Erzeugung erfolgreich, füge zu Liste hinzu features.append(feature) print("PoStationReaderQgs::get_features: %d Features erzeugt" % (len(features),)) diff --git a/po_modules/po_waterlevel.py b/po_modules/po_waterlevel.py index e04d29c..c21c199 100644 --- a/po_modules/po_waterlevel.py +++ b/po_modules/po_waterlevel.py @@ -4,6 +4,11 @@ from qgis._core import QgsFeature, QgsGeometry, QgsPointXY class PoWaterlevel(object): def __init__(self, json): + """ + Nimmt JSON-Daten eines Pegelonline-Waterlevels entgegen und füllt die entsprechenden Felder + :param json: Json-Daten einer Waterlevel + :type json: dict + """ self.longitude = json['longitude'] if 'longitude' in json else None self.latitude = json['latitude'] if 'latitude' in json else None self.uuid = json['uuid'] @@ -18,8 +23,15 @@ class PoWaterlevel(object): self.water = json['water']['longname'] def new_feature(self, fields): + """ + Erzeugt ein QgsFeature mit Attributen dieses Waterlevels oder None im Fehlerfall + :param fields: QgsField-Liste um das Feature zu befüllen + :type fields: list[QgsField] + :return: None | QgsFeature + """ if self.longitude is None or self.latitude is None: - print("PoWaterlevel::new_feature: WARN: Station hat fehlende Koordinaten: %s" % (self.shortname,)) + # Keine Koordinaten → Abbruch + print("PoWaterlevel::new_feature: WARN: Waterlevel hat fehlende Koordinaten: %s" % (self.shortname,)) return None feature = QgsFeature(fields) diff --git a/po_modules/po_waterlevel_reader.py b/po_modules/po_waterlevel_reader.py index 7fff012..e885ee5 100644 --- a/po_modules/po_waterlevel_reader.py +++ b/po_modules/po_waterlevel_reader.py @@ -6,20 +6,33 @@ from .urlreader import UrlReader class PoWaterlevelReader(UrlReader): def __init__(self): + """ + Initialisiert die Super-Klasse mit URL für die Waterlevel + """ super().__init__(poBaseURL + 'stations.json?timeseries=W&includeTimeseries=true&includeCurrentMeasurement=true') def get_waterlevels(self): + """ + Fragt die Liste aller Waterlevels via UrlReader.get_json_response ab und macht PoWaterlevel daraus oder None im Fehlerfall + :return: list[PoWaterlevel] | None + """ print("PoWaterlevelReader::get_waterlevels: Lade Pegelstände herunter...") - stations_json = self.getJsonResponse() - if stations_json is None or len(stations_json) == 0: + waterlevels_json = self.get_json_response() + if waterlevels_json is None or len(waterlevels_json) == 0: + # Keine Waterlevels erhalten → Abbruch print("PoWaterlevelReader::get_waterlevels: FEHLER: Keine Pegelstände erhalten") return None - stations = [] - for station_json in stations_json: - stations.append(PoWaterlevel(station_json)) + waterlevels = [] + for waterlevel_json in waterlevels_json: + try: + # Versuche eine Waterlevel zu erstellen + waterlevels.append(PoWaterlevel(waterlevel_json)) + except Exception as e: + # Fehler → Überspringe diesen Waterlevel + print("PoWaterlevelReader::get_waterlevels: Fehler: error=%s, json=%s" % (e, waterlevel_json)) - print("PoWaterlevelReader::get_waterlevels: %d Pegelstände erhalten" % (len(stations),)) + print("PoWaterlevelReader::get_waterlevels: %d Pegelstände erhalten" % (len(waterlevels),)) - return stations + return waterlevels diff --git a/po_modules/po_waterlevels_reader_qgs.py b/po_modules/po_waterlevels_reader_qgs.py index 905f8eb..1d05d55 100644 --- a/po_modules/po_waterlevels_reader_qgs.py +++ b/po_modules/po_waterlevels_reader_qgs.py @@ -8,11 +8,18 @@ from .po_waterlevel_reader import PoWaterlevelReader class PoWaterlevelReaderQgs(PoWaterlevelReader): def __init__(self): + """ + Initialisiert die Super-Klasse und das Koordinaten-System der Features + """ super().__init__() self.fields = None self.crs = QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId) def get_features(self): + """ + Erzeugt Features aus allen Waterlevels von super.get_waterlevels() oder None im Fehlerfall + :return: list[QgsFeature] | None + """ print("PoWaterlevelReaderQgs::get_features: Erzeuge Features...") self.fields = QgsFields() @@ -29,12 +36,14 @@ class PoWaterlevelReaderQgs(PoWaterlevelReader): features = [] waterlevels = self.get_waterlevels() if waterlevels is None or len(waterlevels) == 0: + # Kein Waterlevel erhalten → Abbruch print("PoWaterlevelReaderQgs::get_features: Fehler: Keine Pegelstände erhalten") return None for waterlevel in waterlevels: feature = waterlevel.new_feature(self.fields) if feature is not None: + # Feature-Erzeugung erfolgreich, füge zu Liste hinzu features.append(feature) print("PoWaterlevelReaderQgs::get_features: %d Features erzeugt" % (len(features),)) diff --git a/po_modules/urlreader.py b/po_modules/urlreader.py index b8b0957..1e894d6 100644 --- a/po_modules/urlreader.py +++ b/po_modules/urlreader.py @@ -15,105 +15,114 @@ class UrlReader(object): """ self.url = _url - def openUrl(self): + def open_url(self): """ Öffnet eine URL-Verbindung, fragt GZIP-Kompression an und gibt das Response-Objekt zurück :return: Response-Objekt oder None im Fehlerfall """ - print("openURL: url: \"%s\"" % (self.url,)) + print("open_url: url: \"%s\"" % (self.url,)) try: + # Versuche Verbindung zu öffnen request = Request(self.url) request.add_header('Accept-Encoding', 'gzip') response = urlopen(request) - print("openURL: Verbindung hergestellt") + print("open_url: Verbindung hergestellt") return response except URLError as e: # auch HTTPError - print("openURL: FEHLER: " + str(e)) + print("open_url: FEHLER: " + str(e)) - return None # Fehler + return None - def getDataResponse(self): + def get_data_response(self): """ - Benutzt openUrl und gibt die (entpackten) Daten zurück. + Benutzt open_url und gibt die (entpackten) Daten zurück. :return: (entpackte) Daten oder None im Fehlerfall """ - print("getDataResponse: url: \"%s\"" % (self.url,)) - response = self.openUrl() + print("get_data_response: url: \"%s\"" % (self.url,)) + response = self.open_url() if response is None: - print("getDataResponse: FEHLER: Kein Response-Objekt erhalten") + #FEHLER: Kein Response-Objekt erhalten + print("get_data_response: FEHLER: Kein Response-Objekt erhalten") return None try: if response.headers['Content-Encoding'] == 'gzip': - print("getDataResponse: Empfange GZIP Daten...") + # Empfange GZIP Daten... + print("get_data_response: Empfange GZIP Daten...") daten = GzipFile(fileobj=response).read() else: - print("getDataResponse: Empfange unkomprimierte Daten...") + # Empfange unkomprimierte Daten... + print("get_data_response: Empfange unkomprimierte Daten...") daten = response.read() - print("getDataResponse: Daten empfangen") + print("get_data_response: Daten empfangen") return daten except OSError as e: - print("getDataResponse: FEHLER: " + str(e)) + print("get_data_response: FEHLER: " + str(e)) - return None # Kein Erfolg + return None - def getJsonResponse(self): + def get_json_response(self): """ - Benutzt getDataResponse zum Herunterladen, interpretiert die Daten als JSON und gibt das Ergebnis zurück. + Benutzt get_data_response zum Herunterladen, interpretiert die Daten als JSON und gibt das Ergebnis zurück. :return: Geparste JSON Daten oder None im Fehlerfall """ - print("getJsonResponse: url=" + self.url) - daten = self.getDataResponse() + print("get_json_response: url=" + self.url) + daten = self.get_data_response() if daten is None: - print("getJsonResponse: FEHLER: Keine Daten erhalten") + # FEHLER: Keine Daten erhalten + print("get_json_response: FEHLER: Keine Daten erhalten") return None try: - print("getJsonResponse: Lese JSON...") + # Versuche JSON zu lesen + print("get_json_response: Lese JSON...") parsed = json.loads(daten) - print("getJsonResponse: JSON gelesen") + print("get_json_response: JSON gelesen") return parsed except ValueError as e: # JSONDecodeError - print("getJsonResponse: ValueError: " + str(e)) + print("get_json_response: ValueError: " + str(e)) except TypeError as e: # JSONDecodeError - print("getJsonResponse: TypeError: " + str(e)) + print("get_json_response: TypeError: " + str(e)) return None # Kein Erfolg def _dateiname_von_url(self): + """ + Extrahiert den Dateinamen aus einer der URL + """ result = urlparse(self.url) dateiname = basename(result.path) return dateiname - def getFileResponse(self, pfad): + def get_file_response(self, pfad): """ - Benutzt getDataResponse zum Herunterladen, schreibt die Daten in eine Datei und gibt ihren Pfad zurück (gegebenes Verzeichnis + basename des URL-Pfades). + Benutzt get_data_response zum Herunterladen, schreibt die Daten in eine Datei und gibt ihren Pfad zurück (gegebenes Verzeichnis + basename des URL-Pfades). :param pfad: Verzeichnis in dem die Datei gespeichert werden soll. :return: Pfad der erzeugten Datei oder None im Fehlerfall """ - print("getFileResponse: url: \"%s\"" % (self.url,)) - print("getFileResponse: pfad: \"%s\"" % (pfad,)) + print("get_file_response: url: \"%s\"" % (self.url,)) + print("get_file_response: pfad: \"%s\"" % (pfad,)) - daten = self.getDataResponse() + daten = self.get_data_response() if daten is None: - print("getFileResponse: FEHLER: Keine Daten erhalten") + print("get_file_response: FEHLER: Keine Daten erhalten") return None dateiname = self._dateiname_von_url() - print("getFileResponse: dateiname: \"%s\"" % (dateiname,)) + print("get_file_response: dateiname: \"%s\"" % (dateiname,)) dateipfad = join(pfad, dateiname) - print("getFileResponse: dateipfad: \"%s\"" % (dateipfad,)) + print("get_file_response: dateipfad: \"%s\"" % (dateipfad,)) try: - print("getFileResponse: Schreibe Datei...") + print("get_file_response: Schreibe Datei...") with open(dateipfad, 'wb') as datei: datei.write(daten) - print("getFileResponse: Datei geschrieben") + print("get_file_response: Datei geschrieben") return dateipfad except OSError as e: @@ -124,4 +133,4 @@ class UrlReader(object): if __name__ == '__main__': url = "https://ia800302.us.archive.org/8/items/BennyGoodmanQuartetAndTrio/BodySoul-BennyGoodmanGeneKrupaTeddyWilsoncarnegieHall1938_64kb.mp3" - print(UrlReader(url).getFileResponse("")) + print(UrlReader(url).get_file_response("")) diff --git a/po_runner.py b/po_runner.py index 6d60e7e..6730ca4 100644 --- a/po_runner.py +++ b/po_runner.py @@ -17,20 +17,20 @@ WATERLEVELS_QML = "styles/waterlevels.qml" class PoRunner(object): - """ - Initialisiert ein neues PoRunner-Objekt: - - Initialisiert Objekt-Variablen - - Verbindet UI-Actions - - Verbindet UI-Signale - :param ui: Haupt-Widget - :type ui: PegelonlineDockWidget - :param graph: Pegelverlauf-Widget - :type graph: PegelonlineDockWidgetGraph - :param iface: QGIS-Interface - :type iface: QgisInterface - """ def __init__(self, ui: PegelonlineDockWidget, graph: PegelonlineDockWidgetGraph, iface): + """ + Initialisiert ein neues PoRunner-Objekt: + - Initialisiert Objekt-Variablen + - Verbindet UI-Actions + - Verbindet UI-Signale + :param ui: Haupt-Widget + :type ui: PegelonlineDockWidget + :param graph: Pegelverlauf-Widget + :type graph: PegelonlineDockWidgetGraph + :param iface: QGIS-Interface + :type iface: QgisInterface + """ # Widget-Referenzen self.ui = ui self.graph = graph @@ -66,20 +66,19 @@ class PoRunner(object): # basemap ----------------------------------------------------------------- - """ - Erzeugt einen neuen Basemap-Layer (ogr), - verbindet UI Signale damit und fügt den erzeugten Layer - ans untere Ende der Layer-Liste an. - :param path: Pfad zu dem Layer-Daten - :type path: str - :param disconnect: Methode die Aufgerufen wird, wenn der Layer gelöscht wird - :type disconnect: Callable[[], None] - :param map_tips: HTML Code für die QGIS-Map-Tips - :param checkbox: Sichtbarkeit-Checkbox um sie via Signal upzudaten - :type checkbox: QCheckBox - """ - def _basemap_create(self, path, name, disconnect: Callable[[], None], map_tips, checkbox) -> None | QgsVectorLayer: + """ + Erzeugt einen neuen Basemap-Layer (ogr), + verbindet UI Signale damit und fügt den erzeugten Layer + ans untere Ende der Layer-Liste an. + :param path: Pfad zu den Layer-Daten + :type path: str + :param disconnect: Methode die Aufgerufen wird, wenn der Layer gelöscht wird + :type disconnect: Callable[[], None] + :param map_tips: HTML Code für die QGIS-Map-Tipps + :param checkbox: Sichtbarkeit-Checkbox um sie via Signal upzudaten + :type checkbox: QCheckBox + """ print("_basemap_create: %s" % (name,)) path = os.path.join(self.local_dir, "basemap", path) basemap = QgsVectorLayer(path, name, "ogr") @@ -107,20 +106,18 @@ class PoRunner(object): return basemap - """ - Verbindet alle Basemap-Signale mit der UI - """ - def _basemap_connect_signals(self): + """ + Verbindet alle Basemap-Signale mit der UI + """ print("_connect_basemap_signals") self.ui.cbBasemapLines.toggled.connect(self._cbBasemapLines_toggled) self.ui.cbBasemapAreas.toggled.connect(self._cbBasemapAreas_toggled) - """ - Behandelt die Sichbarkeitsänderung der Flüsse durch die UI-Checkbox - """ - def _cbBasemapLines_toggled(self): + """ + Behandelt die Sichbarkeitsänderung der Flüsse durch die UI-Checkbox + """ checked = self.ui.cbBasemapLines.isChecked() print("_cbBasemapLines_toggled: %s" % (checked,)) @@ -139,11 +136,10 @@ class PoRunner(object): self._layer_set_visible(self.lines, checked) self._layer_refresh(self.lines) - """ - Behandelt die Sichtbarkeitsänderung der Flächen durch die UI-Checkbox - """ - def _cbBasemapAreas_toggled(self): + """ + Behandelt die Sichtbarkeitsänderung der Flächen durch die UI-Checkbox + """ checked = self.ui.cbBasemapAreas.isChecked() print("_cbBasemapAreas_toggled: %s" % (checked,)) @@ -162,31 +158,28 @@ class PoRunner(object): self._layer_set_visible(self.areas, checked) self._layer_refresh(self.areas) - """ - Löscht die Flüsse-Layer-Referenz nachdem der Layer aus QGIS gelöscht wurde und passt die Checkbox an - """ - def _basemap_disconnect_lines(self): + """ + Löscht die Flüsse-Layer-Referenz, nachdem der Layer aus QGIS gelöscht wurde und passt die Checkbox an + """ print("_basemap_disconnect_lines") self.lines = None self.ui.cbBasemapLines.setChecked(False) - """ - Löscht die Flächen-Layer-Referenz nachdem der Layer aus QGIS gelöscht wurde und passt die Checkbox an - """ - def _basemap_disconnect_areas(self): + """ + Löscht die Flächen-Layer-Referenz, nachdem der Layer aus QGIS gelöscht wurde und passt die Checkbox an + """ print("_basemap_disconnect_areas") self.areas = None self.ui.cbBasemapAreas.setChecked(False) # stations ---------------------------------------------------------------- - """ - Verbindet alle Stations-Signale mit der UI - """ - def _stations_connect_signals(self): + """ + Verbindet alle Stations-Signale mit der UI + """ print("_connect_stations_signals") self.ui.cbStationsVisible.toggled.connect(self._cbStationsVisible_toggled) self.ui.cbStationsName.toggled.connect(self._cbStationsName_toggled) @@ -196,22 +189,20 @@ class PoRunner(object): self.ui.cbStationsWater.toggled.connect(self._cbStationsWater_toggled) self.ui.bgStationsStyle.buttonClicked.connect(self._bgStationsStyle_clicked) - """ - Wendet eingestellte Styles auf den Stations-Layer an - """ - def _stations_apply_style(self): + """ + Wendet eingestellte Styles auf den Stations-Layer an + """ button = self.ui.bgStationsStyle.checkedButton() self._bgStationsStyle_clicked(button) - """ - Behandlung eines Klicks auf einen der Stations-Style-Radio-Buttons - → Wendet Styles auf Stations-Layer an - :param button: Geklickter Radio-Button - :type button: QRadioButton - """ - def _bgStationsStyle_clicked(self, button): + """ + Behandlung eines Klicks auf einen der Stations-Style-Radio-Buttons + → Wendet Styles auf Stations-Layer an + :param button: geklickter Radio-Button + :type button: QRadioButton + """ print("_bgStationsStyle_clicked: %s" % (button.objectName(),)) if self.stations is None: @@ -239,11 +230,10 @@ class PoRunner(object): self.stations.setMapTipTemplate(STATIONS_MAP_TIPS) self._layer_apply_style_per_category(self.stations, field, STATIONS_QML) - """ - Schaltet Sichtbarkeit des Stations-Layers um (und erstellt ihn, falls nötig) - """ - def _cbStationsVisible_toggled(self): + """ + Schaltet Sichtbarkeit des Stations-Layers um (und erstellt ihn, falls nötig) + """ visible = self.ui.cbStationsVisible.isChecked() print("_cbStationsVisible_toggled: %s" % (visible,)) @@ -260,65 +250,58 @@ class PoRunner(object): if visible: self._stations_apply_style() - """ - Sichtbarkeit des Stations-Attributs 'Name' umschalten und Labels updaten - """ - def _cbStationsName_toggled(self): + """ + Sichtbarkeit des Stations-Attributs 'Name' umschalten und Labels updaten + """ checked = self.ui.cbStationsName.isChecked() print("_cbStationsName_toggled: %s" % (checked,)) self._stations_update_labels() - """ - Sichtbarkeit des Stations-Attributs 'Number' umschalten und Labels updaten - """ - def _cbStationsNumber_toggled(self): + """ + Sichtbarkeit des Stations-Attributs 'Number' umschalten und Labels updaten + """ checked = self.ui.cbStationsNumber.isChecked() print("_cbStationsNumber_toggled: %s" % (checked,)) self._stations_update_labels() - """ - Sichtbarkeit des Stations-Attributs 'Agency' umschalten und Labels updaten - """ - def _cbStationsAgency_toggled(self): + """ + Sichtbarkeit des Stations-Attributs 'Agency' umschalten und Labels updaten + """ checked = self.ui.cbStationsAgency.isChecked() print("_cbStationsAgency_toggled: %s" % (checked,)) self._stations_update_labels() - """ - Sichtbarkeit des Stations-Attributs 'Km' umschalten und Labels updaten - """ - def _cbStationsKm_toggled(self): + """ + Sichtbarkeit des Stations-Attributs 'Km' umschalten und Labels updaten + """ checked = self.ui.cbStationsKm.isChecked() print("_cbStationsKm_toggled: %s" % (checked,)) self._stations_update_labels() - """ - Sichtbarkeit des Stations-Attributs 'Water' umschalten und Labels updaten - """ - def _cbStationsWater_toggled(self): + """ + Sichtbarkeit des Stations-Attributs 'Water' umschalten und Labels updaten + """ checked = self.ui.cbStationsWater.isChecked() print("_cbStationsWater_toggled: %s" % (checked,)) self._stations_update_labels() - """ - Löscht die Stations-Layer-Referenz nachdem der Layer aus QGIS gelöscht wurde und passt die Checkbox an - """ - def _stations_disconnect(self): + """ + Löscht die Stations-Layer-Referenz, nachdem der Layer aus QGIS gelöscht wurde und passt die Checkbox an + """ print("_stations_disconnect") self.stations = None self.ui.cbStationsVisible.setChecked(False) - """ - Führt Änderungen an Stations-Labels durch - """ - def _stations_update_labels(self): + """ + Führt Änderungen an Stations-Labels durch + """ print("_stations_update_labels") if self.stations is None: return @@ -344,11 +327,10 @@ class PoRunner(object): # waterlevels ------------------------------------------------------------- - """ - Verbindet alle Pegelstand-Signale mit der UI - """ - def _waterlevels_connect_signals(self): + """ + Verbindet alle Pegelstand-Signale mit der UI + """ print("_waterlevels_connect_signals") self.ui.cbWaterlevelsVisible.toggled.connect(self._cbWaterlevelsVisible_toggled) self.ui.cbWaterlevelsName.toggled.connect(self._cbWaterlevelsName_toggled) @@ -361,22 +343,20 @@ class PoRunner(object): self.ui.cbWaterlevelsWater.toggled.connect(self._cbWaterlevelsWater_toggled) self.ui.bgWaterlevelsStyle.buttonClicked.connect(self._bgWaterlevelsStyle_clicked) - """ - Wendet eingestellte Styles auf den Pegelstand-Layer an - """ - def _waterlevels_apply_style(self): + """ + Wendet eingestellte Styles auf den Pegelstand-Layer an + """ button = self.ui.bgWaterlevelsStyle.checkedButton() self._bgWaterlevelsStyle_clicked(button) - """ - Behandlung eines Klicks auf einen der Pegelstand-Style-Radio-Buttons - → Wendet Styles auf Pegelstand-Layer an - :param button: Geklickter Radio-Button - :type button: QRadioButton - """ - def _bgWaterlevelsStyle_clicked(self, button): + """ + Behandlung eines Klicks auf einen der Pegelstand-Style-Radio-Buttons + → Wendet Styles auf Pegelstand-Layer an + :param button: geklickter Radio-Button + :type button: QRadioButton + """ print("_bgWaterlevelsStyle_clicked: %s" % (button.objectName(),)) if self.waterlevels is None: @@ -410,11 +390,10 @@ class PoRunner(object): self.waterlevels.setMapTipTemplate(WATERLEVELS_MAP_TIPS) self._layer_apply_style_per_category(self.waterlevels, field, WATERLEVELS_QML) - """ - Schaltet Sichtbarkeit des Pegelstand-Layers um (und erstellt ihn, falls nötig) - """ - def _cbWaterlevelsVisible_toggled(self): + """ + Schaltet Sichtbarkeit des Pegelstand-Layers um (und erstellt ihn, falls nötig) + """ visible = self.ui.cbWaterlevelsVisible.isChecked() print("_cbWaterlevelsVisible_toggled: %s" % (visible,)) @@ -431,92 +410,82 @@ class PoRunner(object): if visible: self._waterlevels_apply_style() - """ - Sichtbarkeit des Pegelstand-Attributs 'Name' umschalten und Labels updaten - """ - def _cbWaterlevelsName_toggled(self): + """ + Sichtbarkeit des Pegelstand-Attributs 'Name' umschalten und Labels updaten + """ checked = self.ui.cbWaterlevelsName.isChecked() print("_cbWaterlevelsName_toggled: %s" % (checked,)) self._waterlevels_update_labels() - """ - Sichtbarkeit des Pegelstand-Attributs 'Number' umschalten und Labels updaten - """ - def _cbWaterlevelsNumber_toggled(self): + """ + Sichtbarkeit des Pegelstand-Attributs 'Number' umschalten und Labels updaten + """ checked = self.ui.cbWaterlevelsNumber.isChecked() print("_cbWaterlevelsNumber_toggled: %s" % (checked,)) self._waterlevels_update_labels() - """ - Sichtbarkeit des Pegelstand-Attributs 'Agency' umschalten und Labels updaten - """ - def _cbWaterlevelsAgency_toggled(self): + """ + Sichtbarkeit des Pegelstand-Attributs 'Agency' umschalten und Labels updaten + """ checked = self.ui.cbWaterlevelsAgency.isChecked() print("_cbWaterlevelsAgency_toggled: %s" % (checked,)) self._waterlevels_update_labels() - """ - Sichtbarkeit des Pegelstand-Attributs 'Timestamp' umschalten und Labels updaten - """ - def _cbWaterlevelsTimestamp_toggled(self): + """ + Sichtbarkeit des Pegelstand-Attributs 'Timestamp' umschalten und Labels updaten + """ checked = self.ui.cbWaterlevelsTimestamp.isChecked() print("_cbWaterlevelsTimestamp_toggled: %s" % (checked,)) self._waterlevels_update_labels() - """ - Sichtbarkeit des Pegelstand-Attributs 'Value' umschalten und Labels updaten - """ - def _cbWaterlevelsValue_toggled(self): + """ + Sichtbarkeit des Pegelstand-Attributs 'Value' umschalten und Labels updaten + """ checked = self.ui.cbWaterlevelsValue.isChecked() print("_cbWaterlevelsValue_toggled: %s" % (checked,)) self._waterlevels_update_labels() - """ - Sichtbarkeit des Pegelstand-Attributs 'Mean' umschalten und Labels updaten - """ - def _cbWaterlevelsMean_toggled(self): + """ + Sichtbarkeit des Pegelstand-Attributs 'Mean' umschalten und Labels updaten + """ checked = self.ui.cbWaterlevelsMean.isChecked() print("_cbWaterlevelsMean_toggled: %s" % (checked,)) self._waterlevels_update_labels() - """ - Sichtbarkeit des Pegelstand-Attributs 'Absolute' umschalten und Labels updaten - """ - def _cbWaterlevelsAbsolute_toggled(self): + """ + Sichtbarkeit des Pegelstand-Attributs 'Absolute' umschalten und Labels updaten + """ checked = self.ui.cbWaterlevelsAbsolute.isChecked() print("_cbWaterlevelsAbsolute_toggled: %s" % (checked,)) self._waterlevels_update_labels() - """ - Sichtbarkeit des Pegelstand-Attributs 'Water' umschalten und Labels updaten - """ - def _cbWaterlevelsWater_toggled(self): + """ + Sichtbarkeit des Pegelstand-Attributs 'Water' umschalten und Labels updaten + """ checked = self.ui.cbWaterlevelsWater.isChecked() print("_cbWaterlevelsWater_toggled: %s" % (checked,)) self._waterlevels_update_labels() - """ - Löscht die Pegelstand-Layer-Referenz nachdem der Layer aus QGIS gelöscht wurde und passt die Checkbox an - """ - def waterlevels_disconnect(self): + """ + Löscht die Pegelstand-Layer-Referenz, nachdem der Layer aus QGIS gelöscht wurde und passt die Checkbox an + """ print("waterlevels_disconnect") self.waterlevels = None self.ui.cbWaterlevelsVisible.setChecked(False) - """ - Führt Änderungen an Pegelstand-Labels durch - """ - def _waterlevels_update_labels(self): + """ + Führt Änderungen an Pegelstand-Labels durch + """ print("_waterlevels_update_labels") if self.waterlevels is None: return @@ -551,19 +520,16 @@ class PoRunner(object): # layers ------------------------------------------------------------------ - """ - Erzeugt einen neuen Layer aus QGIS-Features - :param fields: Anzulegende QGIS-Felder - :type fields: list[QgsField] - :param crs: Bezugs-Koordinaten-System - :type crs: QgsCoordinateReferenceSystem - :param features: Hinzuzufügende QGIS-Features - :type features: list[QgsFeature] - :param map_tips: HTML für QGIS-Map-Tips - :type map_tips: str - """ - def _layer_create_from_features(self, fields, crs, features, title) -> None | QgsVectorLayer: + """ + Erzeugt einen neuen Layer aus QGIS-Features + :param fields: Anzulegende QGIS-Felder + :type fields: list[QgsField] + :param crs: Bezugs-Koordinaten-System + :type crs: QgsCoordinateReferenceSystem + :param features: Hinzuzufügende QGIS-Features + :type features: list[QgsFeature] + """ print("_layer_create_from_features") if features is None: @@ -598,30 +564,28 @@ class PoRunner(object): return layer - """ - Setzt die Sichtbarkeit des gegebenen Layers - :param layer: Zu behandelnder Layer - :type layer: QgsVectorLayer - :param visible: Sichtbarkeit - :type visible: bool - """ - def _layer_set_visible(self, layer: QgsVectorLayer, visible): + """ + Setzt die Sichtbarkeit des gegebenen Layers + :param layer: zu behandelnder Layer + :type layer: QgsVectorLayer + :param visible: Sichtbarkeit + :type visible: bool + """ print("_layer_set_visible: %s" % (visible,)) layer_tree = QgsProject.instance().layerTreeRoot().findLayer(layer.id()) layer_tree.setItemVisibilityChecked(visible) - """ - Fügt einen Layer der QGIS-Instanz hinzu und verbindet dessen Signale - :param layer: Zu behandelnder Layer - :type layer: QgsVectorLayer - :param disconnect: Methode die Aufgerufen wird, wenn der Layer gelöscht wird - :type disconnect: Callable[[], None] - :param checkbox: Sichtbarkeit-Checkbox um sie via Signal upzudaten - :type checkbox: QCheckBox - """ - def _layer_add_to_instance(self, layer: QgsVectorLayer, disconnect: Callable[[], None], checkbox: QCheckBox): + """ + Fügt einen Layer der QGIS-Instanz hinzu und verbindet dessen Signale + :param layer: zu behandelnder Layer + :type layer: QgsVectorLayer + :param disconnect: Methode die Aufgerufen wird, wenn der Layer gelöscht wird + :type disconnect: Callable[[], None] + :param checkbox: Sichtbarkeit-Checkbox um sie via Signal upzudaten + :type checkbox: QCheckBox + """ print("_layer_add_to_instance") if layer is None: # Kein Layer mitgegeben → Abbruch @@ -642,48 +606,45 @@ class PoRunner(object): # Signal zur Erkennung von Sichtbarkeitsänderungen verbinden self._connect_layer_list_visibility_signal(layer, checkbox) - """ - Verbinde das Layer-Sichtbarkeit-Signal der QGIS-Layer-Liste mit unserer Layer-Referenz und unserer Checkbox - :param layer: Zu behandelnder Layer - :type layer: QgsVectorLayer - :param checkbox: Sichtbarkeit-Checkbox um sie via Signal upzudaten - :type checkbox: QCheckBox - """ - def _connect_layer_list_visibility_signal(self, layer, checkbox): + """ + Verbinde das Layer-Sichtbarkeit-Signal der QGIS-Layer-Liste mit unserer Layer-Referenz und unserer Checkbox + :param layer: zu behandelnder Layer + :type layer: QgsVectorLayer + :param checkbox: Sichtbarkeit-Checkbox um sie via Signal upzudaten + :type checkbox: QCheckBox + """ root = QgsProject.instance().layerTreeRoot() node = root.findLayer(layer.id()) if node: # Node existiert → Signal verbinden node.visibilityChanged.connect(lambda: self._layer_set_visible_includingCheckbox(layer, node.isVisible(), checkbox)) - print("_layer_add_to_instance: Layer-Sichtbarkeits-Signal verbunden!") + print("_layer_add_to_instance: Layer-Sichtbarkeit-Signal verbunden!") else: # Node nicht gefunden → ignorieren (Programmierfehler) print("_layer_add_to_instance: Fehler: Node im Tree nicht gefunden!") - """ - Setzt die Sichtbarkeit des gegebenen Layers (inklusive gegebener Checkbox) - :param layer: Zu behandelnder Layer - :type layer: QgsVectorLayer - :param visible: Sichtbarkeit - :type visible: bool - :param checkbox: Sichtbarkeit-Checkbox um sie via Signal upzudaten - :type checkbox: QCheckBox - """ - def _layer_set_visible_includingCheckbox(self, layer, visible: bool, checkbox: QCheckBox): + """ + Setzt die Sichtbarkeit des gegebenen Layers (inklusive gegebener Checkbox) + :param layer: zu behandelnder Layer + :type layer: QgsVectorLayer + :param visible: Sichtbarkeit + :type visible: bool + :param checkbox: Sichtbarkeit-Checkbox um sie via Signal upzudaten + :type checkbox: QCheckBox + """ checkbox.setChecked(visible) self._layer_set_visible(layer, visible) - """ - Aktualisiert die Labels eines Layers - :param layer: Zu behandelnder Layer - :type layer: QgsVectorLayer - :param fields: Anzuzeigende Felder (QGIS-Label-Expressions) - :type fields: list[str] - """ - def _layer_update_labels(self, layer, fields): + """ + Aktualisiert die Labels eines Layers + :param layer: zu behandelnder Layer + :type layer: QgsVectorLayer + :param fields: Anzuzeigende Felder (QGIS-Label-Expressions) + :type fields: list[str] + """ print("_layer_update_labels") labeling = QgsVectorLayerSimpleLabeling(QgsPalLayerSettings()) @@ -699,13 +660,12 @@ class PoRunner(object): self._layer_refresh(layer) - """ - Kümmert sich um das neuzeichnen eines Layers - :param layer: Zu behandelnder Layer - :type layer: QgsVectorLayer - """ - def _layer_refresh(self, layer): + """ + Kümmert sich um das neuzeichnen eines Layers + :param layer: zu behandelnder Layer + :type layer: QgsVectorLayer + """ print("_layerRefresh") if self.iface.mapCanvas().isCachingEnabled(): layer.triggerRepaint() @@ -714,13 +674,12 @@ class PoRunner(object): # layer selection --------------------------------------------------------- - """ - Wird aufgerufen wenn sich eine Feature-Markierung auf einem Layer geändert hat. - Öffnet das Graph-Widget mit gewünschtem Pegelverlauf, - falls nur ein Feature vom Pegelstand-Layer markiert ist. - """ - def _layer_selection_changed(self): + """ + Wird aufgerufen, wenn sich eine Feature-Markierung auf einem Layer geändert hat. + Öffnet das Graf-Widget mit gewünschtem Pegelverlauf, + falls nur ein Feature vom Pegelstand-Layer markiert ist. + """ print("_layer_selection_changed") if self.waterlevels is None or self.waterlevels != self.iface.activeLayer(): @@ -745,17 +704,16 @@ class PoRunner(object): # layer styles ------------------------------------------------------------ - """ - Färbt die Features des gegebenen Layers kategorisch nach einem Attribut ein. - :param layer: Zu behandelnder Layer - :type layer: QgsVectorLayer - :param attribute_name: Name des Attributes nach dem kategorisiert werden soll - :type attribute_name: str - :param preset_fallback_file: Preset- bzw Fallback-Style-Datei (.qml) - :type preset_fallback_file: str - """ - def _layer_apply_style_per_category(self, layer, attribute_name, preset_fallback_file): + """ + Färbt die Features des gegebenen Layers kategorisch nach einem Attribut ein. + :param layer: zu behandelnder Layer + :type layer: QgsVectorLayer + :param attribute_name: Name des Attributes nach dem kategorisiert werden soll + :type attribute_name: str + :param preset_fallback_file: Preset- bzw Fallback-Style-Datei (.qml) + :type preset_fallback_file: str + """ print("_layer_apply_style_per_category: Erzeuge kategorisierte Farben...") ramp = QgsStyle().defaultStyle().colorRamp("Turbo") @@ -788,15 +746,14 @@ class PoRunner(object): layer.setRenderer(renderer) self._layer_refresh(layer) - """ - Wendet die gegebene Style-Datei (.qml) auf den gegebenen Layer an - :param layer: Zu behandelnder Layer - :type layer: QgsVectorLayer - :param preset_fallback_file: Style-Datei (.qml) - :type preset_fallback_file: str - """ - def _layer_apply_style_from_file(self, layer, preset_fallback_file): + """ + Wendet die gegebene Style-Datei (.qml) auf den gegebenen Layer an + :param layer: zu behandelnder Layer + :type layer: QgsVectorLayer + :param preset_fallback_file: Style-Datei (.qml) + :type preset_fallback_file: str + """ path = os.path.join(self.local_dir, preset_fallback_file) print("_layer_apply_style_from_file: Lade Style Datei: %s" % (path,)) @@ -807,46 +764,41 @@ class PoRunner(object): # graph signals --------------------------------------------------------- - """ - Verbindet alle GraphWidget-Signale mit der UI - """ - def _graph_connect_signals(self): + """ + Verbindet alle GrafWidget-Signale mit der UI + """ print("_graph_connect_signals") self.ui.slGraphStation.currentTextChanged.connect(self._slGraphStation_changed) self.ui.btnGraphStationsRefresh.clicked.connect(self._btnGraphStationsRefresh_clicked) self.ui.numGraphDays.valueChanged.connect(self._numGraphDays_changed) self.ui.btnGraphLoad.clicked.connect(self._graph_load_graph) - """ - Behandelt die Stations-Änderung und Lädt den Pegelstandsverlauf-Graph neu - """ - def _slGraphStation_changed(self): + """ + Behandelt die Stations-Änderung und lädt den Pegelstandsverlauf-Graf neu + """ print("_slGraphStation_changed: %s" % (self.ui.slGraphStation.currentText(),)) self._graph_load_graph() - """ - Klick auf Graph-Stations-Liste-Refresh: - Lässt die Stations-Liste für den Graphen neu laden - """ - def _btnGraphStationsRefresh_clicked(self): + """ + Klick auf Graf-Stations-Liste-Refresh: + Lässt die Stations-Liste für den Graphen neu laden + """ print("_btnGraphStationsRefresh_clicked") self._graph_load_stations() - """ - Loggt lediglich die Graph-Tages-Änderung - """ - def _numGraphDays_changed(self): + """ + Loggt lediglich die Graf-Tages-Änderung + """ print("_numGraphDays_changed: %s" % (self.ui.numGraphDays.value(),)) - """ - Versucht den aktuell gewünschten Pegelstandsverlauf herunterzuladen und im GraphWidget anzuzeigen. - """ - def _graph_load_graph(self): + """ + Versucht den aktuell gewünschten Pegelstandsverlauf herunterzuladen und im GrafWidget anzuzeigen. + """ print("_graph_load_graph") if not self.ui.slGraphStation.isEnabled(): @@ -859,13 +811,12 @@ class PoRunner(object): self.graph.load(station, days) - """ - Lädt die Stations-Liste für den Graphen neu. - Sperrt solange relevante UI-Elemente. - Versucht die bisher ausgewählten Station in der neuen Liste wiederzufinden. - """ - def _graph_load_stations(self): + """ + Lädt die Stations-Liste für den Graphen neu. + Sperrt so lange relevante UI-Elemente. + Versucht die bisher ausgewählten Station in der neuen Liste wiederzufinden. + """ print("_graph_load_stations") self.ui.slGraphStation.setEnabled(False) self.ui.btnGraphLoad.setEnabled(False) @@ -900,13 +851,12 @@ class PoRunner(object): self.ui.slGraphStation.setEnabled(True) self.ui.btnGraphLoad.setEnabled(True) - """ - Setzt eine Graph-Station anhand des gegebenen Kurznamens - :param shortname: Kurzname der Station die gesetzt werden soll - :type shortname: str - """ - def _graphStation_set_by_shortname(self, shortname): + """ + Setzt eine Graf-Station anhand des gegebenen Kurznamens + :param shortname: Kurzname der Station die gesetzt werden soll + :type shortname: str + """ index = self._graphStation_get_index_by_shortname(shortname) if index is None: # Station nicht gefunden → Abbruch @@ -915,13 +865,12 @@ class PoRunner(object): self.ui.slGraphStation.setCurrentIndex(index) return True - """ - Sucht den Index einer Graph-Station anhand des gegebenen Kurznamens - :param shortname: Kurzname der Station die gesucht werden soll - :type shortname: str - """ - def _graphStation_get_index_by_shortname(self, shortname): + """ + Sucht den Index einer Graf-Station anhand des gegebenen Kurznamens + :param shortname: Kurzname der Station die gesucht werden soll + :type shortname: str + """ print("_graphStation_get_index_by_shortname: shortname=%s" % (shortname,)) for index in range(self.ui.slGraphStation.count()): text = self.ui.slGraphStation.itemText(index)