mirror of
https://github.com/ARUP-CAS/aiscr-qgis-amcr-viewer.git
synced 2026-10-10 04:47:36 +02:00
fix: hesláře osob se po aktualizaci tiše vyprázdní (#68)
Digiarchiv v4.1.0 (Solr 10, json.nl=arrarr) vrací položky facet jako
dvojice ["hodnota", počet] místo objektů {"name": ...}. fetch_set četl
r["name"], spadl na TypeError a hesláře vedoucích a nálezců se uložily
prázdné.
- _facet_name() přijímá oba formáty facet (starý i nový).
- Selhání setu vrací prázdný seznam i při přerušeném stránkování, ať
se neuloží jen část hesláře.
- download_heslare() ponechá u selhaného nebo prázdného setu předchozí
hodnoty z heslar.csv a vrátí seznam selhaných setů.
- Dialog při částečném selhání zobrazí varování místo „Hotovo“.
- Verze 2.1.3 + changelog.
Ověřeno proti produkčnímu API: vedoucí 2497, nálezci 426, ostatní
hesláře beze změny; simulované selhání ponechá předchozí hodnoty.
Refs #67, #66
Připraveno s pomocí AI (Claude).
This commit is contained in:
1 parent
2b783cd13b
commit
f8d938e353
3 files changed
+95
-11
No files matched your search
@@ -104,6 +104,21 @@ def load_all_data():
|
|||||||
return categorized_data
|
return categorized_data
|
||||||
|
|
||||||
|
|
||||||
|
def _facet_name(item):
|
||||||
|
"""
|
||||||
|
Returns the value of one facet item from the Digiarchive API.
|
||||||
|
|
||||||
|
Digiarchive v4.1.0 (Solr 10, json.nl=arrarr) returns facet items as
|
||||||
|
["value", count] pairs; older versions returned {"name": "value", ...}
|
||||||
|
objects. Both shapes are accepted so the plugin works against either.
|
||||||
|
"""
|
||||||
|
if isinstance(item, dict):
|
||||||
|
return item.get("name")
|
||||||
|
if isinstance(item, (list, tuple)) and item:
|
||||||
|
return item[0]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def fetch_set(base_url, internal_name, api_set, task=None):
|
def fetch_set(base_url, internal_name, api_set, task=None):
|
||||||
dataset = []
|
dataset = []
|
||||||
params_amcr = {
|
params_amcr = {
|
||||||
@@ -206,7 +221,9 @@ def fetch_set(base_url, internal_name, api_set, task=None):
|
|||||||
|
|
||||||
for r in records:
|
for r in records:
|
||||||
|
|
||||||
nazev = r["name"]
|
nazev = _facet_name(r)
|
||||||
|
if not nazev:
|
||||||
|
continue
|
||||||
|
|
||||||
dataset.append({
|
dataset.append({
|
||||||
'Název': nazev,
|
'Název': nazev,
|
||||||
@@ -217,17 +234,48 @@ def fetch_set(base_url, internal_name, api_set, task=None):
|
|||||||
break
|
break
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
# A partial set (e.g. pagination interrupted halfway) would
|
||||||
|
# silently drop codes – report the whole set as failed instead
|
||||||
|
# and let the caller keep the previous values
|
||||||
QgsMessageLog.logMessage(
|
QgsMessageLog.logMessage(
|
||||||
f"Chyba u setu {api_set}: {e}",
|
f"Chyba u setu {api_set}: {e}",
|
||||||
"AMČR", Qgis.MessageLevel.Warning)
|
"AMČR", Qgis.MessageLevel.Warning)
|
||||||
break
|
return []
|
||||||
|
|
||||||
return dataset
|
return dataset
|
||||||
|
|
||||||
|
|
||||||
def download_heslare(task=None):
|
def _read_existing_rows():
|
||||||
"""Fetches the codelists from the AMČR API and saves it to a CSV file."""
|
"""
|
||||||
|
Returns the rows of the current heslar.csv grouped by category, so a set
|
||||||
|
that fails to download can keep its previous values.
|
||||||
|
"""
|
||||||
|
rows = {}
|
||||||
|
if not os.path.exists(OUTPUT_FILE):
|
||||||
|
return rows
|
||||||
|
try:
|
||||||
|
with open(OUTPUT_FILE, encoding='utf-8-sig', newline='') as f:
|
||||||
|
for row in csv.DictReader(f, delimiter=';'):
|
||||||
|
cat = (row.get('Kategorie') or '').strip()
|
||||||
|
if cat:
|
||||||
|
rows.setdefault(cat, []).append(row)
|
||||||
|
except Exception as e:
|
||||||
|
QgsMessageLog.logMessage(
|
||||||
|
f"Nelze načíst stávající hesláře: {e}",
|
||||||
|
"AMČR", Qgis.MessageLevel.Warning)
|
||||||
|
return rows
|
||||||
|
|
||||||
|
|
||||||
|
def download_heslare(task=None, failed=None):
|
||||||
|
"""
|
||||||
|
Fetches the codelists from the AMČR API and saves it to a CSV file.
|
||||||
|
|
||||||
|
A set that fails or comes back empty keeps its rows from the current
|
||||||
|
heslar.csv instead of being wiped; its name is appended to ``failed``
|
||||||
|
(if given) so the caller can warn the user.
|
||||||
|
"""
|
||||||
ensure_codelists_dir()
|
ensure_codelists_dir()
|
||||||
|
existing = _read_existing_rows()
|
||||||
all_data = []
|
all_data = []
|
||||||
total_sets = len(slovnicek)
|
total_sets = len(slovnicek)
|
||||||
# index, (interni, api_nazev)
|
# index, (interni, api_nazev)
|
||||||
@@ -251,6 +299,18 @@ def download_heslare(task=None):
|
|||||||
if data is None:
|
if data is None:
|
||||||
return False # Cancelled mid-download
|
return False # Cancelled mid-download
|
||||||
|
|
||||||
|
if not data:
|
||||||
|
# Never replace a working codelist with nothing – an API change
|
||||||
|
# would otherwise silently empty the filter in the dialog
|
||||||
|
old = existing.get(interni, [])
|
||||||
|
QgsMessageLog.logMessage(
|
||||||
|
f"Heslář '{interni}' se nepodařilo stáhnout, "
|
||||||
|
f"ponechávám předchozí hodnoty ({len(old)} položek).",
|
||||||
|
"AMČR", Qgis.MessageLevel.Warning)
|
||||||
|
if failed is not None:
|
||||||
|
failed.append(interni)
|
||||||
|
data = old
|
||||||
|
|
||||||
all_data.extend(data)
|
all_data.extend(data)
|
||||||
|
|
||||||
# Report progress (0-100)
|
# Report progress (0-100)
|
||||||
@@ -261,7 +321,8 @@ def download_heslare(task=None):
|
|||||||
# Save to CSV
|
# Save to CSV
|
||||||
with open(OUTPUT_FILE, 'w', newline='', encoding='utf-8-sig') as f:
|
with open(OUTPUT_FILE, 'w', newline='', encoding='utf-8-sig') as f:
|
||||||
fieldnames = ['Název', 'Kód', 'Kategorie']
|
fieldnames = ['Název', 'Kód', 'Kategorie']
|
||||||
writer = csv.DictWriter(f, fieldnames=fieldnames, delimiter=';')
|
writer = csv.DictWriter(f, fieldnames=fieldnames, delimiter=';',
|
||||||
|
extrasaction='ignore')
|
||||||
writer.writeheader()
|
writer.writeheader()
|
||||||
writer.writerows(all_data)
|
writer.writerows(all_data)
|
||||||
|
|
||||||
|
|||||||
@@ -75,12 +75,15 @@ class UpdateCodelistsTask(QgsTask):
|
|||||||
super().__init__(description, QgsTask.Flag.CanCancel)
|
super().__init__(description, QgsTask.Flag.CanCancel)
|
||||||
self.success = False
|
self.success = False
|
||||||
self.exception = None
|
self.exception = None
|
||||||
|
# Codelists that failed to download and kept their previous values
|
||||||
|
self.failed_sets = []
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""Runs in a background thread."""
|
"""Runs in a background thread."""
|
||||||
try:
|
try:
|
||||||
# Call the download function with the task reference
|
# Call the download function with the task reference
|
||||||
self.success = download_heslare(task=self)
|
self.success = download_heslare(
|
||||||
|
task=self, failed=self.failed_sets)
|
||||||
return self.success
|
return self.success
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.exception = e
|
self.exception = e
|
||||||
@@ -91,10 +94,17 @@ class UpdateCodelistsTask(QgsTask):
|
|||||||
if result:
|
if result:
|
||||||
# Safely update the global variables in the main thread
|
# Safely update the global variables in the main thread
|
||||||
refresh_globals()
|
refresh_globals()
|
||||||
QgsMessageLog.logMessage(
|
if self.failed_sets:
|
||||||
"Hesláře AMČR byly úspěšně aktualizovány.",
|
QgsMessageLog.logMessage(
|
||||||
"AMČR", Qgis.MessageLevel.Info
|
"Hesláře AMČR aktualizovány částečně, beze změny "
|
||||||
)
|
f"zůstaly: {', '.join(self.failed_sets)}",
|
||||||
|
"AMČR", Qgis.MessageLevel.Warning
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
QgsMessageLog.logMessage(
|
||||||
|
"Hesláře AMČR byly úspěšně aktualizovány.",
|
||||||
|
"AMČR", Qgis.MessageLevel.Info
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
if self.isCanceled():
|
if self.isCanceled():
|
||||||
QgsMessageLog.logMessage(
|
QgsMessageLog.logMessage(
|
||||||
@@ -629,6 +639,16 @@ class AmcrFilterDialog(QDialog):
|
|||||||
|
|
||||||
def on_completed():
|
def on_completed():
|
||||||
_cleanup()
|
_cleanup()
|
||||||
|
if task.failed_sets:
|
||||||
|
QMessageBox.warning(
|
||||||
|
parent_win,
|
||||||
|
"Hesláře aktualizovány částečně",
|
||||||
|
"Některé hesláře se nepodařilo stáhnout, "
|
||||||
|
"ponechány byly jejich předchozí hodnoty:\n"
|
||||||
|
+ "\n".join(f"• {name}" for name in task.failed_sets)
|
||||||
|
+ "\n\nPodrobnosti jsou v panelu Zprávy, záložka AMČR."
|
||||||
|
)
|
||||||
|
return
|
||||||
QMessageBox.information(
|
QMessageBox.information(
|
||||||
parent_win,
|
parent_win,
|
||||||
"Hotovo",
|
"Hotovo",
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ name=AMČR Viewer
|
|||||||
qgisMinimumVersion=3.44.0
|
qgisMinimumVersion=3.44.0
|
||||||
qgisMaximumVersion=4.99.0
|
qgisMaximumVersion=4.99.0
|
||||||
description=Viewing and downloading the AMČR data.
|
description=Viewing and downloading the AMČR data.
|
||||||
version=2.1.2
|
version=2.1.3
|
||||||
author=David Spáčil
|
author=David Spáčil
|
||||||
email=spacil@arub.cz
|
email=spacil@arub.cz
|
||||||
|
|
||||||
@@ -24,6 +24,9 @@ hasProcessingProvider=no
|
|||||||
# Uncomment the following line and add your changelog:
|
# Uncomment the following line and add your changelog:
|
||||||
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
|
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.3 (2026-10-01)
|
||||||
|
* Fixed empty person codelists (excavation leaders, finders) after updating codelists against Digiarchive v4.1.0
|
||||||
|
* A codelist that fails to download keeps its previous values and the user is warned
|
||||||
v2.1.2 (2026-09-01)
|
v2.1.2 (2026-09-01)
|
||||||
* Qt6 compatibility
|
* Qt6 compatibility
|
||||||
* Code clean-up
|
* Code clean-up
|
||||||
|
|||||||
Reference in new issue
Block a user