diff --git a/functions/grenzpunkt_alkis.py b/functions/grenzpunkt_alkis.py index 0885cd7..e7c5f6e 100644 --- a/functions/grenzpunkt_alkis.py +++ b/functions/grenzpunkt_alkis.py @@ -146,6 +146,9 @@ def _wfs_get_gml(url: str, typename: str, extra_params: dict) -> Optional[bytes] GET-Requests mit ``BBOX=``-KVP-Parameter oder ResourceId-``FILTER`` (nur ``xmlns:fes``, kein GML) werden dagegen akzeptiert. + **Proxy-Unterstützung:** Verwendet ``QgsBlockingNetworkRequest``, das automatisch + die in QGIS konfigurierten Proxy-Einstellungen berücksichtigt. + Parameters ---------- url : @@ -161,10 +164,10 @@ def _wfs_get_gml(url: str, typename: str, extra_params: dict) -> Optional[bytes] bytes | None Rohe GML-Antwort oder ``None`` bei Fehler. """ - import urllib.request import urllib.parse - import urllib.error - from qgis.core import QgsMessageLog, Qgis + from qgis.core import QgsMessageLog, Qgis, QgsBlockingNetworkRequest + from qgis.PyQt.QtNetwork import QNetworkRequest + from qgis.PyQt.QtCore import QUrl params = { 'SERVICE': 'WFS', @@ -177,26 +180,34 @@ def _wfs_get_gml(url: str, typename: str, extra_params: dict) -> Optional[bytes] full_url = url + '?' + urllib.parse.urlencode(params) - try: - with urllib.request.urlopen(full_url, timeout=120) as resp: - gml_bytes = resp.read() - except urllib.error.HTTPError as exc: - body_preview = exc.read(200).decode('utf-8', errors='replace') + req = QNetworkRequest(QUrl(full_url)) + req.setTransferTimeout(120_000) + blocker = QgsBlockingNetworkRequest() + err = blocker.get(req) + + if err != QgsBlockingNetworkRequest.ErrorCode.NoError: + msg = blocker.errorMessage() QgsMessageLog.logMessage( - f"WFS GET HTTP {exc.code} ({typename}): {exc.reason}\n" + f"WFS GET fehlgeschlagen ({typename}): {msg}\nURL: {full_url[:300]}", + "sn_verfahrensgebiet", + Qgis.MessageLevel.Critical, + ) + warning("WFS GET", f"Netzwerk-/Proxy-Fehler: {msg}", duration=10) + return None + + reply = blocker.reply() + http_status = reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute) + gml_bytes = bytes(reply.content()) + + if http_status is not None and http_status >= 400: + body_preview = gml_bytes[:200].decode('utf-8', errors='replace') + QgsMessageLog.logMessage( + f"WFS GET HTTP {http_status} ({typename})\n" f"URL: {full_url[:300]}\nAntwort: {body_preview}", "sn_verfahrensgebiet", Qgis.MessageLevel.Critical, ) - warning("WFS GET", f"HTTP {exc.code}: {exc.reason}", duration=10) - return None - except Exception as exc: - QgsMessageLog.logMessage( - f"WFS GET fehlgeschlagen ({typename}): {exc}\nURL: {full_url[:300]}", - "sn_verfahrensgebiet", - Qgis.MessageLevel.Critical, - ) - warning("WFS GET", f"Netzwerkfehler: {exc}", duration=10) + warning("WFS GET", f"HTTP {http_status}", duration=10) return None if not gml_bytes: @@ -477,11 +488,7 @@ def _lade_grenzpunkte_als_dict( ) _gml_bytes = _wfs_get_gml(ALKIS_SF_URL, GRENZPUNKT_TYPENAME, {'FILTER': filter_xml}) if not _gml_bytes: - warning( - "Grenzpunkte (Diagnose)", - f"Batch {i + 1}/{anzahl_batches}: GET-Anfrage fehlgeschlagen – Batch wird übersprungen.", - duration=4, - ) + return {}, [] else: tmp = _parse_alkis_gml_memory_layer(_gml_bytes, "AX_Grenzpunkt", "_TmpGP", geom_prop=None) if not tmp: @@ -704,9 +711,12 @@ def _lade_gemarkung_extents_mit_puffer( return extents -def _wfs_hits_count(url: str, typename: str, extra_params: dict) -> int: +def _wfs_hits_count(url: str, typename: str, extra_params: dict) -> Optional[int]: """Fragt die Anzahl der Features per ``resultType=hits`` ab. + **Proxy-Unterstützung:** Verwendet ``QgsBlockingNetworkRequest``, das automatisch + die in QGIS konfigurierten Proxy-Einstellungen berücksichtigt. + Parameters ---------- url : @@ -714,17 +724,21 @@ def _wfs_hits_count(url: str, typename: str, extra_params: dict) -> int: typename : Vollqualifizierter Feature-Typ. extra_params : - Zus\u00e4tzliche KVP-Parameter (z.B. ``{'BBOX': '...'}``). + Zusätzliche KVP-Parameter (z.B. ``{'BBOX': '...'}``). Returns ------- - int - Anzahl der Features oder ``-1`` wenn nicht ermittelbar. + Optional[int] + Anzahl der Features, + ``-1`` wenn der Server antwortete aber ``numberMatched='unknown'`` lieferte + (gültiger WFS-Fallback, kein Fehler), oder + ``None`` bei Netzwerk-/Proxy-Fehler (Aufrufer soll abbrechen). """ - import urllib.request import urllib.parse - import urllib.error import xml.etree.ElementTree as ET + from qgis.core import QgsMessageLog, Qgis, QgsBlockingNetworkRequest + from qgis.PyQt.QtNetwork import QNetworkRequest + from qgis.PyQt.QtCore import QUrl params = { 'SERVICE': 'WFS', @@ -736,11 +750,22 @@ def _wfs_hits_count(url: str, typename: str, extra_params: dict) -> int: params.update(extra_params) full_url = url + '?' + urllib.parse.urlencode(params) - try: - with urllib.request.urlopen(full_url, timeout=30) as resp: - gml_bytes = resp.read() - except Exception: - return -1 + + req = QNetworkRequest(QUrl(full_url)) + req.setTransferTimeout(30_000) + blocker = QgsBlockingNetworkRequest() + err = blocker.get(req) + + if err != QgsBlockingNetworkRequest.ErrorCode.NoError: + msg = blocker.errorMessage() + QgsMessageLog.logMessage( + f"WFS Hits-Abfrage fehlgeschlagen ({typename}): {msg}\nURL: {full_url[:300]}", + "sn_verfahrensgebiet", + Qgis.MessageLevel.Critical, + ) + return None + + gml_bytes = bytes(blocker.reply().content()) try: root = ET.fromstring(gml_bytes) @@ -796,12 +821,7 @@ def _lade_punktort_ta_batches_per_gemarkung( ) _gml_bytes = _wfs_get_gml(ALKIS_SF_URL, PUNKTORT_TA_TYPENAME, {'BBOX': _punktort_ta_bbox_param(bbox)}) if not _gml_bytes: - warning( - "Grenzpunkte (Diagnose)", - f"Gemarkung {_gemarkungsnummer}: GET-Anfrage fehlgeschlagen – wird übersprungen.", - duration=4, - ) - continue + return None tmp = _parse_alkis_gml_memory_layer(_gml_bytes, "AX_PunktortTA", "_TmpPTA", geom_prop="position", extract_qualitaet=True) if not tmp: warning( @@ -997,6 +1017,8 @@ def lade_punktort_ta( bbox_param = _punktort_ta_bbox_param(bbox) n_hits = _wfs_hits_count(ALKIS_SF_URL, PUNKTORT_TA_TYPENAME, {'BBOX': bbox_param}) + if n_hits is None: + return None n_batches = max(1, math.ceil(n_hits / _BBOX_BATCH)) if n_hits > 0 else 1 info( @@ -1022,13 +1044,7 @@ def lade_punktort_ta( _gml_bytes = _wfs_get_gml(ALKIS_SF_URL, PUNKTORT_TA_TYPENAME, extra) if not _gml_bytes: - warning( - "Grenzpunkte (Diagnose)", - f"Gemarkung {gemarkungsnummer} Batch {b_idx + 1}: " - f"GET-Anfrage fehlgeschlagen – übersprungen.", - duration=4, - ) - continue + return None tmp = _parse_alkis_gml_memory_layer( _gml_bytes, "AX_PunktortTA", "_TmpPTA", geom_prop="position", extract_qualitaet=True @@ -1343,6 +1359,8 @@ def grenzpunkte_gemarkungsweise( for gemarkungsnummer, bbox in extents.items(): bbox_param = _punktort_ta_bbox_param(bbox) n_hits = _wfs_hits_count(ALKIS_SF_URL, PUNKTORT_TA_TYPENAME, {'BBOX': bbox_param}) + if n_hits is None: + return None hits_pro_gemarkung[gemarkungsnummer] = n_hits batches = max(1, math.ceil(n_hits / _BBOX_BATCH)) if n_hits > 0 else 1 n_pta_batches_gesamt += batches @@ -1413,13 +1431,7 @@ def grenzpunkte_gemarkungsweise( _gml_bytes = _wfs_get_gml(ALKIS_SF_URL, PUNKTORT_TA_TYPENAME, extra) if not _gml_bytes: - warning( - "Grenzpunkte (Diagnose)", - f"Gemarkung {gemarkungsnummer} Batch {b_idx + 1}: " - f"GET-Anfrage fehlgeschlagen – Batch wird übersprungen.", - duration=6, - ) - continue + return None tmp = _parse_alkis_gml_memory_layer( _gml_bytes, "AX_PunktortTA", "_TmpPTA", geom_prop="position", extract_qualitaet=True diff --git a/functions/verfahrensgebiet_alkis_komplett.py b/functions/verfahrensgebiet_alkis_komplett.py index 2d98739..7de8af0 100644 --- a/functions/verfahrensgebiet_alkis_komplett.py +++ b/functions/verfahrensgebiet_alkis_komplett.py @@ -488,6 +488,17 @@ def verfahrensgebiet_alkis_komplett( if punktort_layer is None: detail_progress.close() abgeschlossen = True + if not detail_progress.is_canceled(): + QMessageBox.critical( + tab_widget, + "WFS-Fehler", + "Die Grenzpunktdaten (PunktortTA) konnten nicht geladen werden.\n\n" + "Mögliche Ursache: Netzwerk- oder Proxy-Fehler.\n" + "Bitte prüfen Sie die QGIS-Proxy-Einstellungen " + "(Einstellungen -> Optionen -> Netzwerk) und den Log-Eintrag " + "unter Ansicht -> Bedienfelder -> Protokollnachrichten " + "(Kategorie 'sn_verfahrensgebiet').", + ) return enriched_layer, flst_layer, alkis_vg_layer, vg_status # Schritte 2…Ende: Knickpunktprüfung diff --git a/ui/tabs/working_tab.py b/ui/tabs/working_tab.py index 46332c9..dd0a1f5 100644 --- a/ui/tabs/working_tab.py +++ b/ui/tabs/working_tab.py @@ -487,10 +487,19 @@ class WorkingTab(QWidget): if joined_layer and joined_layer.isValid(): iface.mapCanvas().refresh() self.setze_haken(self.haken_grenz, True) - success( - "Grenzpunkte", + QMessageBox.information( + self, + "Grenzpunkte geladen", f"Grenzpunkte erfolgreich geladen ({joined_layer.featureCount()} Objekte).", - duration=5, + ) + elif joined_layer is None: + error( + "Grenzpunkte", + "Laden fehlgeschlagen – WFS- oder Netzwerkfehler. " + "Details unter Ansicht -> Bedienfelder -> Protokollnachrichten " + "(Kategorie 'sn_verfahrensgebiet'). " + "Bitte prüfen Sie ggf. die Proxy-Einstellungen.", + duration=0, ) finally: self._set_busy(self.btn_grenz_alkis, False, "Grenzpunkte aus ALKIS laden")