From d398d2cd1b28c74617e02b28a0e7de91dbc20773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Sp=C3=A1=C4=8Dil?= Date: Tue, 1 Sep 2026 23:05:02 +0200 Subject: [PATCH 1/5] fix: kompatibilita s Qt6 / QGIS 4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Oficiální kontrola pyqgis4-checker (skript pyqt5_to_pyqt6.py z QGISu) hlásila u pluginu 13 nekompatibilit a tři soubory vůbec nepřečetla. Odstraněn UTF-8 BOM z amcr_codelists.py, amcr_dialog.py a amcr_tools.py. Checker čte zdroják jako UTF-8 bez utf-8-sig a na BOM padá na SyntaxError: invalid non-printable character U+FEFF, takže se ty soubory nezkontrolovaly vůbec. Pythonu při běhu BOM nevadí, proto to nikdy nevyskočilo. heslar.csv si BOM ponechává, tam je kvůli Excelu. Enumy převedeny na plně kvalifikované tvary (13 míst): Qgis.{Info,Warning,Critical} -> Qgis.MessageLevel.*, QgsTask.CanCancel -> QgsTask.Flag.CanCancel, QgsWkbTypes.*Geometry -> QgsWkbTypes.GeometryType.*Geometry. Zkrácené tvary v QGIS 4.2.1 zatím fungují, ale kontrola je vytýká a aliasy do budoucna mizí. Zbytek kódu už scoped tvary používal. Do AGENTS.md doplněna sekce o kompatibilitě s Qt6 / QGIS 4 se závaznými pravidly a příkazy na ověření. Ověřeno spuštěním v QGIS 3.44.13 (Qt 5.15.18) i QGIS 4.2.1 (Qt 6.10.3): importy, vytvoření tasku i všechny tři filtrační dialogy fungují shodně. Log pyqgis4-checkeru je nově prázdný. --- AGENTS.md | 52 +++++++++++++++++++++++++++++++++++ amcr_viewer/amcr_codelists.py | 8 +++--- amcr_viewer/amcr_dialog.py | 10 +++---- amcr_viewer/amcr_tools.py | 14 +++++----- 4 files changed, 68 insertions(+), 16 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 251cf42..b6107b8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -83,6 +83,58 @@ Další pravidla: definice pole (`QgsField`), naplnění hodnoty z dokumentu, překlad hlavičky sloupce a export atributů. +### Kompatibilita s Qt6 / QGIS 4 + +Plugin cílí na QGIS 3.44 i na QGIS 4 (`qgisMaximumVersion=4.99.0`), tedy na +Qt5 i Qt6 zároveň. **Tohle se drží rigorózně** – ne až před releasem, ale při +každé změně kódu. Chování obou větví se liší tiše: pod Qt5 projde i to, co +QGIS 4 odmítne, takže lokální „funguje mi to“ nic nedokazuje. + +Závazná pravidla: + +- **Nikdy neimportuj přímo z `PyQt5` ani z `PyQt6`.** Vždy přes shim + `qgis.PyQt.*`. Ten mimo jiné pod Qt6 přetahuje `QAction`, `QActionGroup` + a `QShortcut` z `QtGui`, takže import z `qgis.PyQt.QtWidgets` je správně. +- **Enumy vždy plně kvalifikované (scoped).** `Qgis.MessageLevel.Info`, ne + `Qgis.Info`; `QgsTask.Flag.CanCancel`, ne `QgsTask.CanCancel`; + `QgsWkbTypes.GeometryType.PointGeometry`, ne `QgsWkbTypes.PointGeometry`. + Totéž pro Qt: `Qt.CheckState.Checked`, `QDialogButtonBox.StandardButton.Ok`. + Zkrácené tvary sice v QGIS 4.2 zatím fungují, ale oficiální kontrola je + hlásí a do budoucna mizí. +- **Zdrojové `.py` soubory ukládej bez BOM.** Kontrolní skript čte soubor + jako UTF-8 bez `utf-8-sig` a na BOM spadne s + `SyntaxError: invalid non-printable character U+FEFF`, takže se takový + soubor **vůbec nezkontroluje**. (`codelists/heslar.csv` BOM mít smí, tam je + kvůli Excelu.) +- Nepoužívej API zrušená v Qt6: `exec_()`, `QRegExp`, `QDesktopWidget`, + `QApplication.desktop()`, `Qt.MidButton`, `QFontMetrics.width()`, + `setResizeMode`, atributy `AA_EnableHighDpiScaling` / `AA_UseHighDpiPixmaps`. +- `supportsQt6=True` v `metadata.txt` **nepatří** – bylo zrušeno; o zařazení + mezi „QGIS 4 Ready“ rozhoduje rozsah `qgisMinimumVersion` až + `qgisMaximumVersion`. + +Ověření před PR, který mění Python kód: + +```sh +# oficiální kontrola, kterou pouští i plugins.qgis.org (pyqgis4-checker) +docker run --rm --pull always --user $(id -u):$(id -g) \ + --workdir /workspace/ -v "$(pwd):/workspace/" \ + ghcr.io/qgis/pyqgis4-checker:main-ubuntu \ + pyqt5_to_pyqt6.py --dry_run --logfile /workspace/pyqt6_checker.log . +``` + +Prázdný log = čisté. Kontrola je na plugins.qgis.org informativní +(neblokuje schválení), ale nález znamená, že plugin v QGIS 4 dříve nebo +později přestane fungovat. + +Když je po ruce QGIS 4 (např. flatpak `org.qgis.qgis`), ověř navíc, že se +plugin pod Qt6 opravdu načte: + +```sh +flatpak run --command=sh org.qgis.qgis -c \ + 'PYTHONPATH=/app/share/qgis/python python3 -c "import qgis.core"' +``` + ## Verzování a release - Verze pluginu žije v **`amcr_viewer/metadata.txt`** (`version=`). diff --git a/amcr_viewer/amcr_codelists.py b/amcr_viewer/amcr_codelists.py index 962b928..d537f81 100644 --- a/amcr_viewer/amcr_codelists.py +++ b/amcr_viewer/amcr_codelists.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- import os import csv import requests @@ -90,7 +90,7 @@ def parse_codelist_file(filename, target_dict=None): except Exception as e: QgsMessageLog.logMessage( f"AMČR Codelist Read Error for {filename}: {e}", - "AMČR", Qgis.Critical) + "AMČR", Qgis.MessageLevel.Critical) return target_dict @@ -216,7 +216,7 @@ def fetch_set(base_url, internal_name, api_set, task=None): except Exception as e: QgsMessageLog.logMessage( f"Chyba u setu {api_set}: {e}", - "AMČR", Qgis.Warning) + "AMČR", Qgis.MessageLevel.Warning) break return dataset @@ -240,7 +240,7 @@ def download_heslare(task=None): QgsMessageLog.logMessage( f"Zpracovávám kategorii: {interni}...", - "AMČR", Qgis.Info) + "AMČR", Qgis.MessageLevel.Info) # Pass the task correctly to the updated fetch function data = fetch_set(base_url, interni, api_nazev, task=task) diff --git a/amcr_viewer/amcr_dialog.py b/amcr_viewer/amcr_dialog.py index 645a64c..ba6401a 100644 --- a/amcr_viewer/amcr_dialog.py +++ b/amcr_viewer/amcr_dialog.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- from qgis.PyQt.QtWidgets import (QDialog, QVBoxLayout, QLineEdit, QDialogButtonBox, QCheckBox, QGroupBox, QPushButton, @@ -38,7 +38,7 @@ _ACTIVE_TASKS = [] class UpdateCodelistsTask(QgsTask): def __init__(self, description): - super().__init__(description, QgsTask.CanCancel) + super().__init__(description, QgsTask.Flag.CanCancel) self.success = False self.exception = None @@ -59,18 +59,18 @@ class UpdateCodelistsTask(QgsTask): refresh_globals() QgsMessageLog.logMessage( "Hesláře AMČR byly úspěšně aktualizovány.", - "AMČR", Qgis.Info + "AMČR", Qgis.MessageLevel.Info ) else: if self.isCanceled(): QgsMessageLog.logMessage( "Aktualizace heslářů byla zrušena.", - "AMČR", Qgis.Warning + "AMČR", Qgis.MessageLevel.Warning ) else: QgsMessageLog.logMessage( f"Chyba aktualizace: {self.exception}", - "AMČR", Qgis.Critical + "AMČR", Qgis.MessageLevel.Critical ) diff --git a/amcr_viewer/amcr_tools.py b/amcr_viewer/amcr_tools.py index d0d55ac..cb6a51c 100644 --- a/amcr_viewer/amcr_tools.py +++ b/amcr_viewer/amcr_tools.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- from qgis.core import (QgsProject, QgsVectorLayer, QgsFeature, QgsGeometry, QgsField, QgsCoordinateReferenceSystem, QgsCoordinateTransform, QgsWkbTypes, Qgis, @@ -1138,11 +1138,11 @@ def load_amcr_data(canvas, bb, filters=None, if geom.isGeosValid(): t = geom.type() target_list = None - if t == QgsWkbTypes.PolygonGeometry: + if t == QgsWkbTypes.GeometryType.PolygonGeometry: target_list = feats_p - elif t == QgsWkbTypes.LineGeometry: + elif t == QgsWkbTypes.GeometryType.LineGeometry: target_list = feats_l - elif t == QgsWkbTypes.PointGeometry: + elif t == QgsWkbTypes.GeometryType.PointGeometry: target_list = feats_pt if target_list is None: @@ -1227,11 +1227,11 @@ def load_amcr_data(canvas, bb, filters=None, if geom.isGeosValid(): t = geom.type() target_list = None - if t == QgsWkbTypes.PolygonGeometry: + if t == QgsWkbTypes.GeometryType.PolygonGeometry: target_list = feats_p - elif t == QgsWkbTypes.LineGeometry: + elif t == QgsWkbTypes.GeometryType.LineGeometry: target_list = feats_l - elif t == QgsWkbTypes.PointGeometry: + elif t == QgsWkbTypes.GeometryType.PointGeometry: target_list = feats_pt if target_list is None: From 048ffe4e2afefa90108076b766d3212bbc6668b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Sp=C3=A1=C4=8Dil?= Date: Tue, 1 Sep 2026 23:10:33 +0200 Subject: [PATCH 2/5] =?UTF-8?q?chore:=20=C3=BAklid=20n=C3=A1lez=C5=AF=20z?= =?UTF-8?q?=20lint=C5=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bez změny chování. Kontroly, které pouští plugins.qgis.org (flake8), plus ruff. flake8: odstraněny koncové bílé znaky, srovnány nadbytečné prázdné řádky a zalomeno 12 řádků přes 79 znaků. Hlášku o HTTP chybě v login_to_api() si nešlo jen zalomit – tělo odpovědi je nově v proměnné `telo`, výsledný text je stejný. ruff: odstraněny zbytečné prefixy u'' u překládaných řetězců (6×), .format() nahrazen f-stringem, str() uvnitř f-stringu převedeno na !s, `k in dict.keys()` na `k in dict`, prázdný komentář; nepoužitá rozbalená proměnná `existing_cfg` nahrazena `_`. Vědomě neřešeno: - resources.py (5 zbylých nálezů flake8) je generovaný výstup pyrcc, nese hlavičku "All changes made in this file will be lost", není nikde importovaný a v repu k němu chybí zdrojový .qrc. - ruff BLE001 (10×) hlásí `except Exception`. Ty jsou v pluginu záměrné: drží pád mimo QGIS a chybu ukážou v liště zpráv. Změna by byla zásah do chování, ne úklid. - ruff SIM103 (2×) navrhuje sloučit strážní podmínky do jednoho výrazu. Obě místa mají ke každé větvi vysvětlující komentář, sloučením by se staly hůř čitelnými. - ruff UP009 a I001 (coding hlavička a řazení importů) jsou celoprojektová konvence; jejich změna patří do samostatného rozhodnutí, ne sem. Ověřeno v QGIS 3.44.13 (Qt5) i QGIS 4.2.1 (Qt6): importy, vytvoření tasku i všechny tři filtrační dialogy fungují shodně. Bandit, detect-secrets i pyqgis4-checker hlásí nula nálezů. --- amcr_viewer/__init__.py | 1 - amcr_viewer/amcr_codelists.py | 12 +++++++----- amcr_viewer/amcr_dialog.py | 26 +++++++++++++++++--------- amcr_viewer/amcr_tools.py | 23 ++++++++++++----------- amcr_viewer/amcr_viewer.py | 17 +++++++++-------- 5 files changed, 45 insertions(+), 34 deletions(-) diff --git a/amcr_viewer/__init__.py b/amcr_viewer/__init__.py index 017a968..f7f7d86 100644 --- a/amcr_viewer/__init__.py +++ b/amcr_viewer/__init__.py @@ -31,6 +31,5 @@ def classFactory(iface): # pylint: disable=invalid-name :param iface: A QGIS interface instance. :type iface: QgsInterface """ - # from .amcr_viewer import AmcrViewer return AmcrViewer(iface) diff --git a/amcr_viewer/amcr_codelists.py b/amcr_viewer/amcr_codelists.py index d537f81..638f51c 100644 --- a/amcr_viewer/amcr_codelists.py +++ b/amcr_viewer/amcr_codelists.py @@ -98,7 +98,7 @@ def parse_codelist_file(filename, target_dict=None): def load_all_data(): """Loads the codelist during plugin startup.""" ensure_codelists_dir() - categorized_data = {k: {} for k in slovnicek.keys()} + categorized_data = {k: {} for k in slovnicek} parse_codelist_file('heslar.csv', categorized_data) return categorized_data @@ -124,7 +124,9 @@ def fetch_set(base_url, internal_name, api_set, task=None): try: if "digiarchiv" not in base_url: - response = requests.get(base_url, params=params_amcr, timeout=30) + response = requests.get( + base_url, params=params_amcr, timeout=30 + ) response.raise_for_status() root = ET.fromstring(response.content) # nosec @@ -193,7 +195,7 @@ def fetch_set(base_url, internal_name, api_set, task=None): time.sleep(0.5) else: break - + else: response = requests.get(base_url, params=params_da, timeout=30) response.raise_for_status() @@ -210,8 +212,8 @@ def fetch_set(base_url, internal_name, api_set, task=None): 'Kód': nazev, 'Kategorie': internal_name }) - - break + + break except Exception as e: QgsMessageLog.logMessage( diff --git a/amcr_viewer/amcr_dialog.py b/amcr_viewer/amcr_dialog.py index ba6401a..776fdc1 100644 --- a/amcr_viewer/amcr_dialog.py +++ b/amcr_viewer/amcr_dialog.py @@ -13,7 +13,7 @@ from qgis.utils import iface from .amcr_codelists import (OBDOBI, TYP_AKCE, KRAJE, AREAL, ORGANIZACE, OKRESY, KATASTRY, VEDOUCI, PIAN_PRESNOST, TYP_LOKALITY, DRUH_LOKALITY, JISTOTA, - LOKALITA_ZACHOVALOST, PRISTUPNOST, + LOKALITA_ZACHOVALOST, PRISTUPNOST, NALEZ_KATEGORIE, DRUH_NALEZU, SPECIFIKACE, NALEZOVE_OKOLNOSTI, NALEZCE, download_heslare, refresh_globals) @@ -608,7 +608,7 @@ class AmcrFilterDialog(QDialog): # This will show exactly what went wrong (e.g. PermissionError) msg = ( "Aktualizace selhala z důvodu chyby:\n" - f"{str(task.exception)}" + f"{task.exception!s}" ) else: msg = "Aktualizace byla zrušena uživatelem." @@ -660,7 +660,7 @@ class AmcrFilterDialog(QDialog): filters['f_vedouci'] = self.selection_cache['vedouci'] if self.selection_cache['organizace']: - filters['f_organizace'] = self.selection_cache['organizace'] + filters['f_organizace'] = self.selection_cache['organizace'] if self.selection_cache['typ_lokality']: filters['f_typ_lokality'] = self.selection_cache['typ_lokality'] @@ -669,7 +669,9 @@ class AmcrFilterDialog(QDialog): if self.selection_cache['jistota']: filters['f_jistota'] = self.selection_cache['jistota'] if self.selection_cache['lokalita_zachovalost']: - filters['f_lokalita_zachovalost'] = self.selection_cache['lokalita_zachovalost'] + filters['f_lokalita_zachovalost'] = ( + self.selection_cache['lokalita_zachovalost'] + ) # Samostatné nálezy if self.selection_cache['nalez_kategorie']: @@ -679,7 +681,9 @@ class AmcrFilterDialog(QDialog): if self.selection_cache['specifikace']: filters['f_specifikace'] = self.selection_cache['specifikace'] if self.selection_cache['nalezove_okolnosti']: - filters['f_nalezove_okolnosti'] = self.selection_cache['nalezove_okolnosti'] + filters['f_nalezove_okolnosti'] = ( + self.selection_cache['nalezove_okolnosti'] + ) if self.selection_cache['nalezce']: filters['f_nalezce'] = self.selection_cache['nalezce'] @@ -718,7 +722,8 @@ class LoginDialog(QDialog): - storeAuthenticationConfig() and loadAuthenticationConfig() both have SIP_INOUT on their config parameter, so Python bindings return a tuple (bool, QgsAuthMethodConfig) rather than just bool. Always unpack both. - - loadAuthenticationConfig() with full=False loads only metadata (name, method, + - loadAuthenticationConfig() with full=False loads only metadata + (name, method, id) but NOT the config() values like username/password. Use full=True to access those. """ @@ -949,7 +954,7 @@ class LoginDialog(QDialog): # We skip hasConfigId() as it may return False # despite the config existing # (in-memory cache may not be populated yet in QGIS 4). - ok_load, existing_cfg = ( + ok_load, _ = ( self._load_config(existing_id, full=False) if existing_id else (False, None) @@ -978,7 +983,9 @@ class LoginDialog(QDialog): settings = QSettings() existing_id = settings.value(self.SETTINGS_KEY, "") if existing_id: - QgsApplication.authManager().removeAuthenticationConfig(existing_id) + QgsApplication.authManager().removeAuthenticationConfig( + existing_id + ) settings.remove(self.SETTINGS_KEY) QMessageBox.information( self, @@ -1013,4 +1020,5 @@ class LoginDialog(QDialog): if not ok: return "", "" - return cfg.config("username", ""), cfg.config("password", "") # nosec B106 + return (cfg.config("username", ""), + cfg.config("password", "")) # nosec B106 diff --git a/amcr_viewer/amcr_tools.py b/amcr_viewer/amcr_tools.py index cb6a51c..70386a5 100644 --- a/amcr_viewer/amcr_tools.py +++ b/amcr_viewer/amcr_tools.py @@ -109,8 +109,9 @@ def login_to_api(username: str, password: str): except requests.exceptions.HTTPError as e: status = e.response.status_code if e.response is not None else None - _log(f"CHYBA HTTP {status if status else '?'}: " - f"{e.response.text[:300] if e.response is not None else 'žádná odpověď'}", + telo = (e.response.text[:300] if e.response is not None + else "žádná odpověď") + _log(f"CHYBA HTTP {status if status else '?'}: {telo}", Qgis.MessageLevel.Critical) LAST_LOGIN_ERROR = 'auth' if status in (401, 403) else 'network' return None @@ -623,7 +624,8 @@ def load_amcr_data(canvas, bb, filters=None, for dj in djs: # Skip negative evidence units if requested - if skip_negativni and dj.get('dj_negativni_jednotka') is True: + if (skip_negativni + and dj.get('dj_negativni_jednotka') is True): continue komps = dj.get('dj_komponenta', []) @@ -643,7 +645,8 @@ def load_amcr_data(canvas, bb, filters=None, dj_id = dj.get('ident_cely') dj_typ = dj.get('dj_typ') - # Merge shared metadata with documentation unit-specific fields + # Merge shared metadata with documentation + # unit-specific fields dj_meta = { **meta, 'dj_id': dj_id, @@ -690,7 +693,8 @@ def load_amcr_data(canvas, bb, filters=None, or {} ).get('value', ""), } - pian_lookup[dj_pian_value].append(komp_meta) + pian_lookup[dj_pian_value].append( + komp_meta) target_pian_ids_count += 1 else: # DJ without components — still include @@ -704,7 +708,8 @@ def load_amcr_data(canvas, bb, filters=None, 'komponenta_areal': "", 'komponenta_obdobi': "", } - pian_lookup[dj_pian_value].append(empty_meta) + pian_lookup[dj_pian_value].append( + empty_meta) target_pian_ids_count += 1 else: target_pian_ids_count += 1 @@ -907,9 +912,6 @@ def load_amcr_data(canvas, bb, filters=None, ) return - - - # ========================================== # D) LAYER CREATION (QGIS Memory Layers) # ========================================== @@ -947,7 +949,6 @@ def load_amcr_data(canvas, bb, filters=None, QgsField("typ_dj", QMetaType.Type.QString), ] - cols += [ QgsField(typ_dat, QMetaType.Type.QString), QgsField("definicni_body", QMetaType.Type.QString), @@ -1265,7 +1266,7 @@ def load_amcr_data(canvas, bb, filters=None, ] feat.setAttributes(atributy) target_list.append(feat) - + except Exception as ex: QgsMessageLog.logMessage( f"Chyba při tvorbě feature: {ex}", diff --git a/amcr_viewer/amcr_viewer.py b/amcr_viewer/amcr_viewer.py index 4062883..a16fe8b 100644 --- a/amcr_viewer/amcr_viewer.py +++ b/amcr_viewer/amcr_viewer.py @@ -29,7 +29,7 @@ class AmcrViewer: locale_path = os.path.join( self.plugin_dir, 'i18n', - 'AmcrViewer_{}.qm'.format(locale) + f'AmcrViewer_{locale}.qm' ) # Install the translator if a translation file @@ -41,7 +41,7 @@ class AmcrViewer: # Initialize internal state self.actions = [] - self.menu = self.tr(u'&AMČR Viewer') + self.menu = self.tr('&AMČR Viewer') self.first_start = None def tr(self, message): @@ -102,7 +102,7 @@ class AmcrViewer: # custom dropdown menu self.action_download_akce = self.add_action( icon_path=icon_akce_path, - text=self.tr(u'Stáhnout data akcí | AMČR Viewer'), + text=self.tr('Stáhnout data akcí | AMČR Viewer'), callback=lambda checked=False: self.run_download('akce'), parent=self.iface.mainWindow(), add_to_menu=False, @@ -112,8 +112,9 @@ class AmcrViewer: self.action_download_pas = self.add_action( icon_path=icon_pas_path, - text=self.tr(u'Stáhnout data samostatných nálezů | AMČR Viewer'), - callback=lambda checked=False: self.run_download('samostatny_nalez'), + text=self.tr('Stáhnout data samostatných nálezů | AMČR Viewer'), + callback=lambda checked=False: self.run_download( + 'samostatny_nalez'), parent=self.iface.mainWindow(), add_to_menu=False, add_to_toolbar=False @@ -122,7 +123,7 @@ class AmcrViewer: self.action_download_lokality = self.add_action( icon_path=icon_lokality_path, - text=self.tr(u'Stáhnout data lokalit | AMČR Viewer'), + text=self.tr('Stáhnout data lokalit | AMČR Viewer'), callback=lambda checked=False: self.run_download('lokalita'), parent=self.iface.mainWindow(), add_to_menu=False, @@ -132,7 +133,7 @@ class AmcrViewer: self.action_login_dialog = self.add_action( icon_path=icon_pas_path, - text=self.tr(u'Přihlásit se | AMČR Viewer'), + text=self.tr('Přihlásit se | AMČR Viewer'), callback=lambda checked=False: self.login(), parent=self.iface.mainWindow(), add_to_menu=False, @@ -142,7 +143,7 @@ class AmcrViewer: self.action_amcr_help = self.add_action( icon_path=icon_amcr_help_path, - text=self.tr(u'Nápověda AMČR Help | AMČR Viewer'), + text=self.tr('Nápověda AMČR Help | AMČR Viewer'), callback=lambda checked=False: self.open_help(), parent=self.iface.mainWindow(), add_to_menu=False, From 9aba28317a87f417cc2591a1908604f26b57402b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Sp=C3=A1=C4=8Dil?= Date: Tue, 1 Sep 2026 23:13:18 +0200 Subject: [PATCH 3/5] =?UTF-8?q?chore:=20po=C5=99ad=C3=AD=20import=C5=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- amcr_viewer/amcr_codelists.py | 9 ++--- amcr_viewer/amcr_dialog.py | 62 +++++++++++++++++++++++++---------- amcr_viewer/amcr_tools.py | 29 ++++++++++------ amcr_viewer/amcr_viewer.py | 15 +++++---- 4 files changed, 77 insertions(+), 38 deletions(-) diff --git a/amcr_viewer/amcr_codelists.py b/amcr_viewer/amcr_codelists.py index 638f51c..c409359 100644 --- a/amcr_viewer/amcr_codelists.py +++ b/amcr_viewer/amcr_codelists.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- -import os import csv -import requests -import xml.etree.ElementTree as ET # nosec +import os import time -from qgis.core import QgsMessageLog, Qgis +import xml.etree.ElementTree as ET # nosec + +import requests +from qgis.core import Qgis, QgsMessageLog # Define paths for the plugin and its codelists directory PLUGIN_DIR = os.path.dirname(__file__) diff --git a/amcr_viewer/amcr_dialog.py b/amcr_viewer/amcr_dialog.py index 776fdc1..862d24f 100644 --- a/amcr_viewer/amcr_dialog.py +++ b/amcr_viewer/amcr_dialog.py @@ -1,23 +1,51 @@ -# -*- coding: utf-8 -*- -from qgis.PyQt.QtWidgets import (QDialog, QVBoxLayout, - QLineEdit, QDialogButtonBox, - QCheckBox, QGroupBox, QPushButton, - QListWidget, QListWidgetItem, QHBoxLayout, - QMessageBox, QLabel, QFormLayout, - QGridLayout, QScrollArea, QFrame, QWidget) -from qgis.PyQt.QtCore import Qt, QSettings -from qgis.core import (QgsTask, QgsApplication, - QgsMessageLog, Qgis, QgsAuthMethodConfig) +# -*- coding: utf-8 -*- +from qgis.core import Qgis, QgsApplication, QgsAuthMethodConfig, QgsMessageLog, QgsTask from qgis.gui import QgsDateEdit +from qgis.PyQt.QtCore import QSettings, Qt +from qgis.PyQt.QtWidgets import ( + QCheckBox, + QDialog, + QDialogButtonBox, + QFormLayout, + QFrame, + QGridLayout, + QGroupBox, + QHBoxLayout, + QLabel, + QLineEdit, + QListWidget, + QListWidgetItem, + QMessageBox, + QPushButton, + QScrollArea, + QVBoxLayout, + QWidget, +) from qgis.utils import iface -from .amcr_codelists import (OBDOBI, TYP_AKCE, KRAJE, AREAL, ORGANIZACE, - OKRESY, KATASTRY, VEDOUCI, PIAN_PRESNOST, - TYP_LOKALITY, DRUH_LOKALITY, JISTOTA, - LOKALITA_ZACHOVALOST, PRISTUPNOST, - NALEZ_KATEGORIE, DRUH_NALEZU, SPECIFIKACE, - NALEZOVE_OKOLNOSTI, NALEZCE, - download_heslare, refresh_globals) +from .amcr_codelists import ( + AREAL, + DRUH_LOKALITY, + DRUH_NALEZU, + JISTOTA, + KATASTRY, + KRAJE, + LOKALITA_ZACHOVALOST, + NALEZ_KATEGORIE, + NALEZCE, + NALEZOVE_OKOLNOSTI, + OBDOBI, + OKRESY, + ORGANIZACE, + PIAN_PRESNOST, + PRISTUPNOST, + SPECIFIKACE, + TYP_AKCE, + TYP_LOKALITY, + VEDOUCI, + download_heslare, + refresh_globals, +) # The date filter of the API requires both bounds; a one-sided range makes # the server fail with an ArrayIndexOutOfBoundsException and '*' is not diff --git a/amcr_viewer/amcr_tools.py b/amcr_viewer/amcr_tools.py index 70386a5..d0b1538 100644 --- a/amcr_viewer/amcr_tools.py +++ b/amcr_viewer/amcr_tools.py @@ -1,15 +1,24 @@ -# -*- coding: utf-8 -*- -from qgis.core import (QgsProject, QgsVectorLayer, QgsFeature, QgsGeometry, - QgsField, QgsCoordinateReferenceSystem, - QgsCoordinateTransform, QgsWkbTypes, Qgis, - QgsMessageLog) -from qgis.utils import iface -from qgis.PyQt.QtCore import Qt, QMetaType -from qgis.PyQt.QtWidgets import QApplication -from qgis.PyQt.QtGui import QCursor -import requests +# -*- coding: utf-8 -*- import json +import requests +from qgis.core import ( + Qgis, + QgsCoordinateReferenceSystem, + QgsCoordinateTransform, + QgsFeature, + QgsField, + QgsGeometry, + QgsMessageLog, + QgsProject, + QgsVectorLayer, + QgsWkbTypes, +) +from qgis.PyQt.QtCore import QMetaType, Qt +from qgis.PyQt.QtGui import QCursor +from qgis.PyQt.QtWidgets import QApplication +from qgis.utils import iface + # Global cache to store translated terms from the Digital Archive TRANSLATIONS = {} diff --git a/amcr_viewer/amcr_viewer.py b/amcr_viewer/amcr_viewer.py index a16fe8b..065d1d0 100644 --- a/amcr_viewer/amcr_viewer.py +++ b/amcr_viewer/amcr_viewer.py @@ -1,13 +1,14 @@ # -*- coding: utf-8 -*- -from qgis.PyQt.QtCore import QSettings, QTranslator, QCoreApplication, QUrl -from qgis.PyQt.QtGui import QIcon, QDesktopServices -from qgis.PyQt.QtWidgets import QMenu, QAction, QToolButton, QDialog -from qgis.core import Qgis - -from .amcr_tools import load_amcr_data, login_to_api -from .amcr_dialog import AmcrFilterDialog, LoginDialog import os.path +from qgis.core import Qgis +from qgis.PyQt.QtCore import QCoreApplication, QSettings, QTranslator, QUrl +from qgis.PyQt.QtGui import QDesktopServices, QIcon +from qgis.PyQt.QtWidgets import QAction, QDialog, QMenu, QToolButton + +from .amcr_dialog import AmcrFilterDialog, LoginDialog +from .amcr_tools import load_amcr_data, login_to_api + class AmcrViewer: """ From 3f7839c818e28aa4034c1b2be6fe384abb18f294 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Sp=C3=A1=C4=8Dil?= Date: Tue, 1 Sep 2026 23:15:28 +0200 Subject: [PATCH 4/5] =?UTF-8?q?fix:=20znovu=20odstran=C4=9Bn=20BOM=20a=20z?= =?UTF-8?q?alomen=20dlouh=C3=BD=20import?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 9aba283 vrátil UTF-8 BOM do amcr_dialog.py a amcr_tools.py – patrně ho doplnil editor při uložení. Oficiální pyqgis4-checker na nich kvůli tomu znovu padal na SyntaxError, tedy přesně to, co d398d2c opravoval. Zároveň zalomen sloučený import z qgis.core v amcr_dialog.py, který měl 87 znaků. --- amcr_viewer/amcr_dialog.py | 10 ++++++++-- amcr_viewer/amcr_tools.py | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/amcr_viewer/amcr_dialog.py b/amcr_viewer/amcr_dialog.py index 862d24f..3cd69b9 100644 --- a/amcr_viewer/amcr_dialog.py +++ b/amcr_viewer/amcr_dialog.py @@ -1,5 +1,11 @@ -# -*- coding: utf-8 -*- -from qgis.core import Qgis, QgsApplication, QgsAuthMethodConfig, QgsMessageLog, QgsTask +# -*- coding: utf-8 -*- +from qgis.core import ( + Qgis, + QgsApplication, + QgsAuthMethodConfig, + QgsMessageLog, + QgsTask, +) from qgis.gui import QgsDateEdit from qgis.PyQt.QtCore import QSettings, Qt from qgis.PyQt.QtWidgets import ( diff --git a/amcr_viewer/amcr_tools.py b/amcr_viewer/amcr_tools.py index d0b1538..18fd078 100644 --- a/amcr_viewer/amcr_tools.py +++ b/amcr_viewer/amcr_tools.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- import json import requests From b708930ca2be09f4989577e8c071dd4cf8196546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Sp=C3=A1=C4=8Dil?= Date: Tue, 1 Sep 2026 23:21:04 +0200 Subject: [PATCH 5/5] update metadata --- amcr_viewer/metadata.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/amcr_viewer/metadata.txt b/amcr_viewer/metadata.txt index 72ecc26..3dc8fd2 100644 --- a/amcr_viewer/metadata.txt +++ b/amcr_viewer/metadata.txt @@ -8,7 +8,7 @@ name=AMČR Viewer qgisMinimumVersion=3.44.0 qgisMaximumVersion=4.99.0 description=Viewing and downloading the AMČR data. -version=2.1.1 +version=2.1.2 author=David Spáčil email=spacil@arub.cz @@ -24,6 +24,9 @@ hasProcessingProvider=no # Uncomment the following line and add your changelog: changelog= Plný seznam změn v češtině je dostupný zde: https://github.com/ARUP-CAS/aiscr-qgis-amcr-viewer/releases/tag/v2.1.1 + v2.1.2 (2026-09-01) + * Qt6 compatibility + * Code clean-up v2.1.1 (2026-09-01) * Added download of Individual finds (PAS), including a dedicated menu entry * Added filtering by date