fix(nspd): list_layers parse flat layers[] response, not children-tree
НСПД /layers-theme-tree отдаёт {"layers":[...flat...], "tree":...} с ключом
layerId, а list_layers() ходил _walk_layer_tree по id/children → молча возвращал
[] для любой темы (слои не в children-дереве). Добавлен flat-layers путь с
fallback на nested-tree (id/children) + data-wrapper; defensive на missing id.
Refs #1067 (ИРД — discovery слоёв НСПД).
This commit is contained in:
parent
d9c2157d02
commit
a609bcf741
2 changed files with 66 additions and 6 deletions
|
|
@ -613,9 +613,24 @@ class NSPDClient:
|
|||
# Shape defense: NSPD иногда оборачивает в {"data": [...]} — паттерн уже
|
||||
# ловили в Bug_Nspd_Geo_Str_Object_No_Get_Fixed. Без проверки walker
|
||||
# молча вернул бы [], а caller увидел бы пустой catalog.
|
||||
if isinstance(data, dict) and "data" in data and not data.get("children"):
|
||||
if (
|
||||
isinstance(data, dict)
|
||||
and "data" in data
|
||||
and not data.get("children")
|
||||
and "layers" not in data
|
||||
):
|
||||
data = data.get("data") or []
|
||||
if not isinstance(data, list | dict):
|
||||
# Реальная форма layers-theme-tree: {"layers": [...flat...], "tree": ...},
|
||||
# где каждая запись = {"layerId": N, "title", "layerName", "layerType"}.
|
||||
# Раньше walker искал id/children и для этой (актуальной) формы молча
|
||||
# возвращал [] — слои не в children-дереве, а в плоском layers[]
|
||||
# (см. research/NSPD_IRD_Layers_Automation_Recon_Jun06). Сначала пробуем
|
||||
# плоский layers[], иначе fallback на nested-tree walker (id/children).
|
||||
if isinstance(data, dict) and isinstance(data.get("layers"), list):
|
||||
raw_entries: list[dict[str, Any]] = data["layers"]
|
||||
elif isinstance(data, list | dict):
|
||||
raw_entries = _walk_layer_tree(data)
|
||||
else:
|
||||
logger.warning(
|
||||
"list_layers: unexpected NSPD response type %s for theme_id=%s",
|
||||
type(data).__name__,
|
||||
|
|
@ -623,12 +638,14 @@ class NSPDClient:
|
|||
)
|
||||
return []
|
||||
layers: list[NSPDLayer] = []
|
||||
# Tree response: nested {"children": [...], "id": N, "title": "..."}
|
||||
# Используем walker по subtree чтобы вытащить все leaf layers
|
||||
for entry in _walk_layer_tree(data):
|
||||
for entry in raw_entries:
|
||||
# актуальная форма использует layerId; старая nested-tree — id
|
||||
raw_id = entry.get("layerId", entry.get("id"))
|
||||
if raw_id is None:
|
||||
continue
|
||||
layers.append(
|
||||
NSPDLayer(
|
||||
layer_id=int(entry["id"]),
|
||||
layer_id=int(raw_id),
|
||||
title=str(entry.get("title", "")),
|
||||
layer_type=entry.get("layerType") or entry.get("layer_type"),
|
||||
metadata=entry,
|
||||
|
|
|
|||
|
|
@ -323,6 +323,49 @@ def test_list_layers_handles_garbage_response(monkeypatch: pytest.MonkeyPatch) -
|
|||
assert NSPDClient().list_layers(theme_id=1) == []
|
||||
|
||||
|
||||
def test_list_layers_parses_flat_layers_response(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""Актуальная форма NSPD: {"layers": [...flat...], "tree": ...} с ключом layerId.
|
||||
|
||||
Регрессия на баг: walker искал id/children, а реальный ответ держит слои в
|
||||
плоском layers[] (layerId/title/layerName/layerType) — list_layers молча
|
||||
возвращал [] для любой темы (см.
|
||||
research/NSPD_IRD_Layers_Automation_Recon_Jun06).
|
||||
"""
|
||||
fake_resp = {
|
||||
"layers": [
|
||||
{
|
||||
"layerId": 36945,
|
||||
"title": "Кадастровые округа",
|
||||
"layerName": "ЕГРН. Округа",
|
||||
"layerType": "wms",
|
||||
},
|
||||
{
|
||||
"layerId": 875838,
|
||||
"title": "Территориальные зоны",
|
||||
"layerName": "ПЗЗ",
|
||||
"layerType": "wms",
|
||||
},
|
||||
{
|
||||
"layerId": 37577,
|
||||
"title": "ЗОУИТ ОКН",
|
||||
"layerName": "ЗОУИТ ОКН",
|
||||
"layerType": "wms",
|
||||
},
|
||||
],
|
||||
"tree": {"categories": []},
|
||||
}
|
||||
monkeypatch.setattr(
|
||||
"app.services.scrapers.nspd_client._http_get_json",
|
||||
lambda url, **kw: fake_resp,
|
||||
)
|
||||
layers = NSPDClient().list_layers(theme_id=1)
|
||||
assert sorted(layer.layer_id for layer in layers) == [36945, 37577, 875838]
|
||||
tz = next(layer for layer in layers if layer.layer_id == 875838)
|
||||
assert tz.title == "Территориальные зоны"
|
||||
assert tz.layer_type == "wms"
|
||||
assert tz.metadata["layerName"] == "ПЗЗ"
|
||||
|
||||
|
||||
# ── _geojson_bbox_3857 tests ──────────────────────────────────────────────────
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue