Files
Projektwissen/docs/wissen/fallstricke.md
T
DanielandClaude Opus 5.5 9c7c4b900d Kartenrand-Anordnung (Basis #93) dokumentiert
- schnittstellen.md Abschnitt 12: Element-IDs, die print_kartenrand braucht; Seitengröße nur Mindestgröße
- fallstricke.md: minimumSize liefert vor dem ersten Zeichnen die ungefilterte Legendenhöhe
- modulkarte.md: print_kartenrand, aktualisierte Zeilenzahlen
- STATUS.md: Punkt 15 (Stand #88/#90/#92, QGIS 4 geprüft), neuer Punkt 16
- Testkatalog neu erzeugt

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 13:07:03 +02:00

14 KiB
Raw Blame History

Fallstricke und Erkenntnisse

Gemeinsames Gedächtnis: Dinge, die man nicht aus dem Code ablesen kann und die schon einmal Zeit gekostet haben. Kurz, konkret, mit Datum und Quelle. Neue Einträge oben in der passenden Rubrik. Veraltetes löschen, nicht auskommentieren.

Umgebung und Werkzeuge

  • qt_wrapper meldet unter QGIS 3.44 QT_VERSION == 6, obwohl Qt5 läuft. Der „PyQt6“-Zweig importiert qgis.PyQt, das unter QGIS 3 PyQt5 ist; die Qt6-Schreibweise der Enums (Qt.ItemFlag.ItemIsUserCheckable) funktioniert mit PyQt 5.15 trotzdem. QT_VERSION also nicht als Qt-Hauptversion verstehen, nur als „echtes Qt (≠ 0)“. (02.10.2026, QGIS 3.44.4 geprüft, Basis #88)
  • Lücken im Mock-Modus: QgsGeometry hat im Mock kein fromRect, QgsLayoutPoint/QgsLayoutSize haben x/width als Attribute statt als Methoden; QgsRectangle hatte bis Basis #88 gar keinen Mock. Tests patchen solche Stellen gezielt, statt die Produktionsfunktion umzubauen. (02.10.2026)
  • QGIS 3.40 ist seit Januar 2026 End of Life. Aktueller LTR ist 3.44, Stable 4.2 (wird 25.09.2026 LTR). workspace.toml und alle metadata.template stehen noch auf 3.40 – offene Produktentscheidung, siehe docs/konzept/07_qgis_tests_plan.md Abschnitt 2. (04.09.2026, QGIS-Release-Fahrplan)
  • Zwei Qt-Welten. QGIS 3.40/3.44 laufen mit Qt5/PyQt5, QGIS 4 mit Qt6/PyQt6. qt_wrapper lädt PyQt6 zuerst, dann PyQt5, sonst Mock. Enum-Zugriffe unterscheiden sich (Qt.AlignmentFlag.AlignTop statt Qt.AlignTop), deshalb nur Wrapper-Aliase verwenden. (09/2026, Code)
  • Mock-Modus ist kein QGIS. python scripts/run_tests.py läuft in Sekunden, prüft aber nur Logik gegen Mock-Klassen. Geometrieoperationen, WFS, Layouts und Signale müssen in QGIS geprüft werden (tests/test_qgis.bat unter Windows). Manuelle QGIS-Tests im PR dokumentieren. (09/2026)
  • openpyxl ist eine harte Abhängigkeit von sn_basis (Excel-Import) und unter Linux-QGIS oft nicht installiert (Issue Verfahrensgebiet #21). requests ist nur optionaler Fallback. Es gibt keine requirements.txt. (09/2026)
  • QGIS lädt Plugins in nicht garantierter Reihenfolge. Fachplugins dürfen in initGui() nicht davon ausgehen, dass sn_basis fertig ist; sn_basis ruft initGui() aller sn_* nach. (Code main.py)
  • Exit-Crash unter QGIS 3.40 entstand durch nicht getrennte Projektsignale beim Unload. Regel: jeder Tab/Manager, der Signale verbindet, bietet cleanup()/teardown_...() und wird beim Schließen aufgerufen. (Basis, assets/plan-qgis340ExitCrashFix.prompt.md)
  • docs/tests/testkatalog.html (Dashboard „Prüfstand") lädt Mermaid von cdnjs.cloudflare.com. Ohne Internetverbindung beim Öffnen bleiben die Baumdiagramme leer, Text/Tabellen/Filter funktionieren trotzdem (kein Server nötig, einfach lokal im Browser öffnen). Erzeugt zusammen mit testkatalog.md durch python scripts/testkatalog.py; beide Dateien müssen zueinander passen (--pruefen prüft beide). (09/2026)
  • .vscode/ gehört nicht ins Repository. Im Projektwissen wurde er am 04.09.2026 entfernt; brauchbare Einstellungen stehen jetzt in docs/leitfaden/04_werkzeuge_einrichten.md Abschnitt 4.2 zum Kopieren in die Benutzereinstellungen. In Plugin_SN_Basis, Plugin_SN_Plan41, Plugin_SN_Verfahrensgebiet und Plugin_SN_Widmung liegt er noch und enthält Pfade eines einzelnen Arbeitsplatzes (OSGeo-Installationspfad, persönliches Benutzerprofil) – nicht als Vorgabe verstehen. (09/2026)

QGIS-Tests (geplant, siehe docs/konzept/07_qgis_tests_plan.md)

  • Spike/Abnahme ohne QGIS-Oberfläche: Skript mit QT_QPA_PLATFORM=offscreen über python-qgis.bat starten, das Plugin-Repo per Junction (mklink /J <tmp>\sn_basis <Plugin_SN_Basis>) unter dem Paketnamen in sys.path legen. Für Widgets und Dialoge QgsApplication([], True) (mit GUI) – ohne GUI stürzt z. B. QgsSymbolLayerUtils.symbolPreviewIcon ab. Modale Dialoge: exec_dialog patchen und im Ersatz die Widgets prüfen. Layout-Ergebnis mit QgsLayoutExporter.renderRegionToImage als PNG ansehen; ohne installierte Schriften erscheinen Texte als Kästchen. exportToImage liefert bei Erfolg 0. (02.10.2026, Basis #88)

  • QT_QPA_PLATFORM=offscreen muss gesetzt sein, bevor die QgsApplication erzeugt wird. Danach wirkt es nicht mehr. (04.09.2026, Recherche)

  • qgis.utils.iface ist nach start_app() None. Entweder pytest-qgis verwenden (patcht automatisch) oder selbst qgis.utils.iface = get_iface() setzen – und keine Module zu früh importieren. (04.09.2026)

  • QgsProject.instance() ist global. Ohne Aufräumen zwischen den Tests beeinflussen sie sich gegenseitig. (04.09.2026)

  • Abstürze beim Beenden sind ein bekanntes QGIS-Thema, wenn Layer- oder Canvas-Objekte noch referenziert werden. Gegenmittel: pytest-qgis oder --qgis_disable_exit. (04.09.2026)

  • QgisTestCase.render_layout_check() ist für Plugins nicht nutzbar: es sucht Referenzbilder in einem einkompilierten Pfad des QGIS-Quellbaums. Nur QgsRenderChecker bietet setControlImagePath(). Referenzbilder immer im CI-Container erzeugen, nie unter Windows (Font- und Antialiasing-Unterschiede). (04.09.2026)

  • Modale Dialoge blockieren den Test. Reihenfolge der Gegenmittel: modalen Aufruf per monkeypatch ersetzen, open() statt exec(), erst zuletzt QTimer.singleShot. (04.09.2026)

  • Unter Windows nur python-qgis.bat/python-qgis-ltr.bat verwenden – ein normales python -m pytest findet die QGIS-Bindings nicht. (04.09.2026)

  • Gitea ordnet Commits über die E-Mail-Adresse zu. Stimmt user.email nicht mit einer im Gitea-Konto hinterlegten Adresse überein, erscheinen die Commits ohne Zuordnung zum Benutzer. Für dieses Projekt gilt die dienstliche Adresse (@lfulg.sachsen.de). Wer den Rechner auch privat nutzt, setzt sie je Repository mit git config --local statt global. Nachträglich nur durch Umschreiben der Historie korrigierbar. (04.09.2026)

Release und Versionen

  • Der Release-Workflow baut den Kopf des Kanal-Branches, nicht den getaggten Commit (git checkout "$CHANNEL" in Repository:hidden/workflows). Tag nur setzen, wenn der Kanal-Branch auf dem gewünschten Stand ist. (09/2026)
  • metadata.txt nie von Hand pflegen. Sie wird beim Release aus .gitea/templates/metadata.template erzeugt. Die im Repo liegende Datei ist ein Abbild des letzten Builds und kann irreführende Versionen/URLs zeigen (Issue Verfahrensgebiet #26). (09/2026)
  • Stable-Kanal ist leer, ein Branch dafür existiert nicht; ein Tag ohne Suffix würde derzeit fehlschlagen. Der Branch muss exakt stable heißen, weil der Release-Workflow in Repository:hidden/workflows git checkout "$CHANNEL" ausführt und $CHANNEL aus dem Tag-Suffix stammt. Anlegen: docs/konzept/08_repo_einrichten.md (ADR 0007). (04.09.2026, Workflow gelesen)
  • Repo-Name ≠ Paketname. Plugin_SN_Basis wird als sn_basis installiert (Gitea-Variable ZIP_FOLDER). Importe im Code verwenden immer den Paketnamen.
  • Bekannte Metadata-Fehler: Plan41-Template verweist auf Plugin_Test_Action als Repository; FLT-Template auf Plugin_SN_Neu; Widmung trägt Version 4711-unstable. (Gesamtüberblick 09/2026)
  • Workspace-Dateien in Release-ZIPs. Der rsync-Schritt schließt nur .git, .gitea, .gitignore, __pycache__ aus. AGENTS.md, CLAUDE.md, .agents/, .claude/, docs/, tests/ werden mit ausgeliefert, bis die Excludes ergänzt sind (offener Punkt).

Daten und Dienste

  • Punktlinien aus Mapbox-Styles sind in QGIS unsichtbar. basemap.de (wie viele MapLibre-Stile) zeichnet Punktlinien als line-dasharray mit Strichlänge 0 und line-cap: round. QGIS übernimmt das beim Import 1:1, Qt zeichnet Striche der Länge 0 aber gar nicht – auch nicht als Punkt, weder in der Karte noch in der Legende. Betroffen sind bei basemap.de 12 Styles (Baumreihe, Hecke, Durchlass, Seilbahnen …). Abhilfe: Strichlänge 0 durch 0,01 ersetzen (sn_basis.modules.basemap_stilkorrektur). Beim Prüfen solcher Effekte die Beschriftung abschalten – sonst zählen Labels als „sichtbare Pixel“. (02.10.2026, QGIS 3.44 / PyQt 5.15, Basis #90; QGIS 4 ungeprüft)
  • basemap.de-Vektorkacheln (Basis #88): QGIS zeigt für Vektorkachel-Layer keine Legende. Objekte im Gebiet liefert QgsVectorTileLayer.selectByGeometry() (lädt die Kacheln selbst; getRawTile ist in Python gesperrt). Kacheln enden bei Zoom 15. Der Renderer prüft Styles mit scaleToZoomLevel(maßstab, False) und setzt @vector_tile_zoom = scaleToZoom(maßstab) – diese Variable fehlt in der Legende, zoomabhängige Strichmuster sind dort sonst unsichtbar. Beim Import der Style-JSON werden Beschriftungen zu Labeling (Hausnummern = Labeling-Style Hauskoordinate), Nummer_*-Schilder zu Renderer-Symbolen, fill-extrusion (3D) entfällt. Der Legendenkatalog sn_basis/data/basemap_legende.json gehört zur Style-Version bm_web_col v2; nach einer neuen Version python modules/basemap_katalog.py laufen lassen und Meldungen prüfen. Eine QML-Stilvorlage des Layers ist rund 3,7 MB groß. (02.10.2026)
  • WFS-Beschränkungen der sächsischen ALKIS-Dienste: POST/GML-Filter werden blockiert, URL-Länge ist begrenzt, serverseitige Feature-Limits. Deshalb arbeiten Flurstücks- und Grenzpunktabrufe mit BBOX, gemarkungsweisen Batches und Nutzerdialogen. Nicht „vereinfachen“, ohne das gegen den Dienst zu testen. Vollständig mit erprobten Anfragen: docs/wissen/wfs_dienste.md, Objektarten/Attribute: docs/wissen/alkis_objektarten.md. (Verfahrensgebiet, Code)
  • Zwei Linklisten. Zentrale Linkliste/linkliste.csv (Spalten id;gruppe;ebene;inhalt;url;provider;stil) und die vom Plugin genutzte Plugin_SN_Plan41/assets/Linkliste.xlsx (ident, gruppe, kartenebene, inhalt, link, provider, stildatei) sind nicht verbunden. Änderungen an Diensten in beiden nachziehen, bis die Zusammenführung entschieden ist. (09/2026)
  • ArcGIS-REST-Layer nicht nach Nummer deuten. Gleiche Layer-URLs werden in der Linkliste und im Alternativansatz unterschiedlich benannt; Bedeutung und Geometrie immer gegen die Dienstmetadaten prüfen. (Vergleich Alternativansatz 09/2026)
  • CRS: Plan41 und VLN-API arbeiten in EPSG:25833. Der Alternativansatz erzeugt EPSG:25832. Für neue Layer 25833 verwenden, bis eine Entscheidung dokumentiert ist.
  • Shape-Import erwartet Feld FBSchl mit 901/10110F (Neuordnungsgebiet) oder 901/10120F (Neuvermessungsgebiet). Exporte mit abweichendem Feldnamen (FBSchl.) wurden bis 26.8.3 abgewiesen; seit PR Verfahrensgebiet #45 (02.09.2026, 26.8.4-unstable) ist die Feldsuche tolerant. Neue Exportvarianten trotzdem gegen die Erkennung testen.
  • VLN-Upload ersetzt den Serverbestand der VKZ vollständig (PUT). Vor dem Upload sicherstellen, dass alle Teillayer geladen sind.
  • API-Key liegt in QSettings (Registry/Konfigurationsdatei), kein sicherer Schlüsselspeicher. Niemals in Logs oder Tests ausgeben.

Code-Konventionen, die man kennen muss

  • Legendenelemente im Layout (QGIS 3.44): QgsLayoutItemLegend.adjustBoxSize() wirkt erst, nachdem das Element einmal gezeichnet wurde – beim Anlegen per Code ändert es nichts. Platzbedarf vorher über QgsLegendRenderer(legende.model(), einstellungen).minimumSize(QgsLayoutUtils.createRenderContextForLayout(layout, None)) berechnen; für mehrere Spalten zusätzlich setSplitLayer(True), sonst bleibt ein Layer in einer Spalte. Eine Legende mit setLegendFilterByMapEnabled(True) blendet Layer aus, die nicht in der Karte liegen, und ihre Höhe steht erst nach dem Rendern fest. (02.10.2026, Spike Basis #88) Auch QgsLegendRenderer.minimumSize liefert vor dem ersten Zeichnen die ungefilterte Höhe (Beispiel: 344 statt 177 mm). Verlässlich vermessen: Legende einmal mit geringer Auflösung zeichnen (QgsLayoutExporter(layout).renderRegionToImage(legende.sceneBoundingRect(), QSize(), 25)), danach wirken Filter und adjustBoxSize. (02.10.2026, Basis #93)
  • Projektvariablen-Schlüssel ohne sn_ übergeben. set_variable("sn_abdeckungslayer", ...) erzeugt sn_sn_abdeckungslayer (Altlast in Druckmodulen; funktioniert nur, weil Lesen und Schreiben denselben Fehler machen).
  • Zwei Schreibweisen für den Verfahrensgebiet-Layer: verfahrensgebiet_layer (Manager, Fachplugins) und verfahrensgebietslayer (print_logic.py). Bis zur Bereinigung nicht auf Gleichheit vertrauen.
  • Layer werden über Anzeigenamen gefunden (BROR_LAYER_NAME usw.). Umbenennungen in der UI brechen Abläufe.
  • print() ist im Code verbreitet, aber kein Logging. Neue Ausgaben über message_wrapper (Nutzer) oder gar nicht; Debug-print vor dem PR entfernen.
  • Testrunner pro Repo (tests/run_tests.py) und Workspace-Runner unterscheiden sich. Für PR-Nachweise zählt scripts/run_tests.py --baseline.
  • Tests der Verfahrensgebiet-Suite sind teils veraltet (erwarten Einzeldatei-/Einzellayer-Schnittstellen vor der Mehrfachauswahl). Vor dem Fixen prüfen, ob der Test oder der Code falsch ist; siehe Baseline.
  • Bezeichner (Layernamen, Dateinamen) nie mit eigenem Regex bereinigen. sanitize_bezeichner aus sn_basis.functions.text_wrapper verwenden – Umlaute, ß, _ und - wurden in mehreren KI-generierten Regexen vergessen (Plugin_SN_Basis #42).
  • Deutscher Text ohne Umlaute/ß ist ein eigenständiges Muster, kein Einzelfall. Bei der Aufarbeitung von #42 fanden sich über alle Fachplugins verteilt MessageBox-Texte, Labels und Docstrings, die wortwörtlich als ASCII generiert wurden (gueltig statt gültig, ueber statt über, Massstab/Groesse als Anzeigetext statt Maßstab/Größe) – typisch für KI-generierten Text, der Sonderzeichen vermeidet. Neuen deutschen Text (Meldungen, Labels, Kommentare, Docstrings) immer mit echten Umlauten/ß schreiben, nicht mit ae/oe/ue/ss behelfen. Vor dem Commit python scripts/pruefe_umlaute.py [<repo>] laufen lassen – findet genau dieses Muster (String-Inhalte und Kommentare mit Leerzeichen, die einen bekannten ASCII-Wortstamm enthalten; technische Bezeichner ohne Leerzeichen werden nicht angetastet). Die Wortstammliste im Skript ist bewusst konservativ (keine Fehlalarme wichtiger als Vollständigkeit) – Ersatz fürs Lesen des eigenen Textes ist sie nicht.

Zusammenarbeit

  • Tool-Gedächtnis ist lokal. Die Claude-Auto-Memory sieht niemand sonst. Geteiltes Wissen nur in diesem Ordner (siehe Issue Basis #36 „shared-memory-architektur“, Kai).
  • Issues sind teils Diskussionen, nicht Aufträge (Label Diskussion). Vor der Umsetzung Konsens im Issue abwarten oder im PR als Annahme kennzeichnen.