feat: complete Wallonia land cover and terrain sources
GeoIntel release gates / Compile, test, contracts and builds (push) Canceled after 0s
GeoIntel release gates / Python and npm vulnerability policy (push) Canceled after 0s
GeoIntel release gates / GIS image, SBOM and container scan (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-22 06:28:46 +02:00
parent d45d34186d
commit cee6cd05ae
46 changed files with 2542 additions and 276 deletions
@@ -59,6 +59,8 @@ def test_configured_yolo_and_active_asset_are_selected_without_hiding_limitation
assert "getYoloPreflight" in hook
assert 'aria-label="Status gebouwdetectie"' in lab
assert "Nog niet nationaal gevalideerd" in lab
assert "selectedDetectionModel?.nationally_validated !== true" in lab
assert "selectedDetectionModel?.validation_scope" in lab
assert "vereisen lokale referentiedata en QA" in lab
assert "Modelkalibratie voor beheerders" in lab
@@ -232,6 +232,10 @@ def test_yolo_configured_model_reports_configured_with_local_model_and_dependenc
assert model.configured is True
assert model.status == "configured"
assert model.version == settings.yolo_model_version
assert model.nationally_validated is False
assert model.operator_review_required is True
assert model.validated_regions == ["flanders_mol_kempen"]
assert "Mol and the Kempen" in (model.validation_scope or "")
def test_yolo_dependency_check_uses_real_imports_not_find_spec() -> None:
+268
View File
@@ -0,0 +1,268 @@
from __future__ import annotations
from pathlib import Path
from types import SimpleNamespace
from uuid import uuid4
import numpy as np
from fastapi.testclient import TestClient
from pyproj import Transformer
import rasterio
from rasterio.transform import from_origin
from app.core.config import Settings
from app.db.session import get_db
from app.main import app
from app.models import Dataset, Job, Project
from app.schemas.dhmv import TerrainSelectionRequest
from app.schemas.spw_terrain import SpwTerrainAcquireRequest
from app.services.dataset_service import DatasetService
from app.services.spw_terrain_service import SpwTerrainService
from app.services.terrain_analysis_service import TerrainAnalysisService
class FakeQuery:
def filter(self, *_args):
return self
def order_by(self, *_args):
return self
def first(self):
return None
class FakeSession:
def __init__(self, project, dataset=None):
self.project = project
self.dataset = dataset
self.added = []
def get(self, model, row_id):
if model is Project and row_id == self.project.id:
return self.project
if model is Dataset and self.dataset is not None and row_id == self.dataset.id:
return self.dataset
return next(
(
item
for item in self.added
if isinstance(item, model) and item.id == row_id
),
None,
)
def query(self, _model):
return FakeQuery()
def add(self, row):
self.added.append(row)
def commit(self):
return None
def rollback(self):
return None
def refresh(self, row):
return row
def settings(source_dir: Path) -> Settings:
return Settings(
_env_file=None,
SPW_TERRAIN_SOURCE_DIR=str(source_dir),
SPW_TERRAIN_ANALYSIS_RESOLUTION_M=5,
SPW_TERRAIN_MAX_SIDE_M=20_000,
SPW_TERRAIN_MAX_PIXELS=1_000_000,
DHMV_MAX_PIXELS=1_000_000,
)
def make_source(path: Path) -> list[float]:
to_3812 = Transformer.from_crs("EPSG:4326", "EPSG:3812", always_xy=True)
to_4326 = Transformer.from_crs("EPSG:3812", "EPSG:4326", always_xy=True)
x, y = to_3812.transform(4.85, 50.45)
values = np.linspace(100.0, 125.0, 40_000, dtype="float32").reshape(200, 200)
with rasterio.open(
path,
"w",
driver="GTiff",
width=200,
height=200,
count=1,
dtype="float32",
crs="EPSG:3812",
transform=from_origin(x, y + 200, 1, 1),
nodata=-9999.0,
) as target:
target.write(values, 1)
min_lon, min_lat = to_4326.transform(x, y)
max_lon, max_lat = to_4326.transform(x + 200, y + 200)
return [min_lon, min_lat, max_lon, max_lat]
def test_spw_terrain_registry_reports_real_source_state(tmp_path: Path) -> None:
before = SpwTerrainService.list_products(settings=settings(tmp_path))[0]
assert before["status"] == "source_not_provisioned"
make_source(tmp_path / SpwTerrainService.SOURCE_FILENAME)
after = SpwTerrainService.list_products(settings=settings(tmp_path))[0]
assert after["configured"] is True
assert after["coverage_zones"] == ["wallonia"]
assert after["source_crs"] == "EPSG:3812"
assert after["vertical_reference"].endswith("(EPSG:5710)")
def test_spw_terrain_acquisition_persists_bounded_dng_raster_and_provenance(
tmp_path: Path, monkeypatch
) -> None:
bbox = make_source(tmp_path / SpwTerrainService.SOURCE_FILENAME)
project = Project(id=uuid4(), name="Belgium")
captured = {}
def persist(_db, **kwargs):
captured.update(kwargs)
return SimpleNamespace(id=uuid4())
monkeypatch.setattr(DatasetService, "import_raster_bytes", persist)
result = SpwTerrainService.acquire(
FakeSession(project),
project.id,
SpwTerrainAcquireRequest(
bbox={
"min_x": bbox[0],
"min_y": bbox[1],
"max_x": bbox[2],
"max_y": bbox[3],
"crs": "EPSG:4326",
},
resolution_m=5,
force_refresh=True,
),
settings=settings(tmp_path),
)
assert result["provider"] == "spw_terrain"
assert result["resolution_m"] == 5
assert result["valid_pixel_count"] > 0
assert captured["source_metadata"]["vertical_unit_label"] == "m DNG"
assert captured["source_metadata"]["coverage_zones"] == ["wallonia"]
assert captured["provenance_metadata"]["resampling"] == "bilinear"
assert captured["valid_from"].date().isoformat() == "2021-02-19"
with rasterio.MemoryFile(captured["content"]) as memory:
with memory.open() as derived:
assert derived.crs.to_epsg() == 3812
assert derived.res == (5.0, 5.0)
assert derived.nodata == -9999.0
def test_terrain_analysis_preserves_spw_vertical_datum_and_limitations(
tmp_path: Path,
) -> None:
bbox = make_source(tmp_path / "derived.tif")
project = Project(id=uuid4(), name="Belgium")
dataset = Dataset(
id=uuid4(),
project_id=project.id,
name="derived.tif",
dataset_type="raster",
source="SPW MNT",
source_name="spw_terrain",
source_metadata={
"product_key": SpwTerrainService.PRODUCT_KEY,
"surface_model": "terrain",
"vertical_reference": SpwTerrainService.VERTICAL_REFERENCE,
"vertical_unit_label": "m DNG",
"limitation_message": SpwTerrainService.LIMITATION,
},
storage_path=str(tmp_path / "derived.tif"),
status="ready",
)
result = TerrainAnalysisService.analyze(
FakeSession(project, dataset),
project.id,
dataset.id,
TerrainSelectionRequest(
bbox={
"min_x": bbox[0],
"min_y": bbox[1],
"max_x": bbox[2],
"max_y": bbox[3],
"crs": "EPSG:4326",
},
),
settings=settings(tmp_path),
)
assert result["vertical_reference"] == SpwTerrainService.VERTICAL_REFERENCE
assert result["summary"]["metric_unit"] == "m DNG"
assert result["summary"]["metrics"][0]["metric_unit"] == "m DNG"
assert result["limitation_message"] == SpwTerrainService.LIMITATION
assert result["unsupported_metrics"] == ["water_depth_m", "water_volume_m3"]
def test_spw_terrain_routes_use_canonical_envelopes(monkeypatch) -> None:
project = Project(id=uuid4(), name="Belgium")
db = FakeSession(project)
monkeypatch.setattr(
SpwTerrainService,
"acquire",
lambda *_args, **_kwargs: {
"output_dataset_id": str(uuid4()),
"provider": SpwTerrainService.PROVIDER,
},
)
monkeypatch.setattr(
SpwTerrainService,
"list_products",
lambda *_args, **_kwargs: [
{
"key": SpwTerrainService.PRODUCT_KEY,
"display_name": SpwTerrainService.DISPLAY_NAME,
"surface_model": "terrain",
"source_filename": SpwTerrainService.SOURCE_FILENAME,
"native_resolution_m": 1,
"analysis_resolution_m": 5,
"source_crs": "EPSG:3812",
"vertical_reference": SpwTerrainService.VERTICAL_REFERENCE,
"acquisition_period": SpwTerrainService.ACQUISITION_PERIOD,
"catalog_url": SpwTerrainService.CATALOG_URL,
"attribution": SpwTerrainService.ATTRIBUTION,
"license_note": SpwTerrainService.LICENSE_NOTE,
"limitation_message": SpwTerrainService.LIMITATION,
"coverage_zones": ["wallonia"],
"configured": True,
"status": "configured",
}
],
)
app.dependency_overrides[get_db] = lambda: db
try:
client = TestClient(app)
products = client.get(
f"/api/v1/projects/{project.id}/datasets/spw-terrain/products"
)
acquisition = client.post(
f"/api/v1/projects/{project.id}/datasets/spw-terrain/acquire",
json={
"bbox": {
"min_x": 4.8,
"min_y": 50.4,
"max_x": 4.9,
"max_y": 50.5,
"crs": "EPSG:4326",
},
"product_key": SpwTerrainService.PRODUCT_KEY,
},
)
finally:
app.dependency_overrides.clear()
assert products.status_code == 200 and products.json()["data"]["total"] == 1
assert (
acquisition.status_code == 200
and acquisition.json()["data"]["job_type"] == "raster.spw-terrain.acquire"
)
assert any(isinstance(item, Job) for item in db.added)
+240 -36
View File
@@ -16,7 +16,10 @@ from app.core.config import Settings
from app.db.session import get_db
from app.main import app
from app.models import Dataset, Job, Project
from app.schemas.thematic_raster import ThematicRasterAcquireRequest, ThematicRasterSelectionRequest
from app.schemas.thematic_raster import (
ThematicRasterAcquireRequest,
ThematicRasterSelectionRequest,
)
from app.schemas.temporal import TemporalComparisonRequest
from app.services.dataset_service import DatasetService
from app.services.temporal_analysis_service import TemporalAnalysisService
@@ -24,8 +27,12 @@ from app.services.walous_land_cover_service import WalousLandCoverService
def load_provisioner():
path = Path(__file__).resolve().parents[2] / "scripts" / "provision_walous_sources.py"
spec = importlib.util.spec_from_file_location("walous_source_provisioner_test", path)
path = (
Path(__file__).resolve().parents[2] / "scripts" / "provision_walous_sources.py"
)
spec = importlib.util.spec_from_file_location(
"walous_source_provisioner_test", path
)
assert spec and spec.loader
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
@@ -54,7 +61,14 @@ class FakeSession:
return self.project
if model is Dataset and self.dataset is not None and row_id == self.dataset.id:
return self.dataset
match = next((item for item in self.added if isinstance(item, model) and item.id == row_id), None)
match = next(
(
item
for item in self.added
if isinstance(item, model) and item.id == row_id
),
None,
)
if match is not None:
return match
return None
@@ -80,12 +94,13 @@ def make_source(
*,
dtype: str = "uint8",
nodata: int = 255,
class_codes: list[int] | None = None,
) -> tuple[list[float], np.ndarray]:
to_3812 = Transformer.from_crs("EPSG:4326", "EPSG:3812", always_xy=True)
to_4326 = Transformer.from_crs("EPSG:3812", "EPSG:4326", always_xy=True)
x, y = to_3812.transform(4.85, 50.45)
transform = from_origin(x, y + 100, 1, 1)
class_codes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 80, 90]
class_codes = class_codes or [1, 2, 3, 4, 5, 6, 7, 8, 9, 80, 90]
values = np.empty((100, len(class_codes) * 20), dtype=dtype)
for index, class_code in enumerate(class_codes):
values[:, index * 20 : (index + 1) * 20] = class_code
@@ -118,20 +133,40 @@ def settings(source_dir: Path) -> Settings:
def test_walous_registry_reports_real_provisioning_state(tmp_path: Path) -> None:
before = {item["key"]: item for item in WalousLandCoverService.list_products(settings=settings(tmp_path))}
before = {
item["key"]: item
for item in WalousLandCoverService.list_products(settings=settings(tmp_path))
}
assert before["walous_land_cover_2023"]["status"] == "source_not_provisioned"
make_source(tmp_path / "walous_land_cover_2023_3812.tif")
after = {item["key"]: item for item in WalousLandCoverService.list_products(settings=settings(tmp_path))}
after = {
item["key"]: item
for item in WalousLandCoverService.list_products(settings=settings(tmp_path))
}
assert after["walous_land_cover_2023"]["configured"] is True
assert after["walous_land_cover_2023"]["source_crs"] == "EPSG:3812"
assert after["walous_land_cover_2023"]["native_resolution_m"] == 1.0
assert after["walous_land_cover_2023"]["analysis_resolution_m"] == 10.0
assert after["walous_land_cover_2023"]["coverage_zones"] == ["wallonia"]
assert after["walous_land_cover_2023"]["included_source_values"] == [1, 2, 3, 4, 5, 6, 7, 8, 9, 80, 90]
assert after["walous_land_cover_2023"]["included_source_values"] == [
1,
2,
3,
4,
5,
6,
7,
8,
9,
80,
90,
]
assert after["walous_land_cover_2023"]["source_value_unit"] == "walous_class_code"
def test_walous_provisioner_accepts_official_non_contiguous_class_codes(tmp_path: Path) -> None:
def test_walous_provisioner_accepts_official_non_contiguous_class_codes(
tmp_path: Path,
) -> None:
source_path = tmp_path / "walous_land_cover_2023_3812.tif"
make_source(source_path)
@@ -140,7 +175,86 @@ def test_walous_provisioner_accepts_official_non_contiguous_class_codes(tmp_path
assert validation["sample_classes"] == [1, 2, 3, 4, 5, 6, 7, 8, 9, 80, 90]
def test_walous_acquisition_reads_real_classes_and_persists_provenance(tmp_path: Path, monkeypatch) -> None:
def test_walous_2018_registry_and_provisioner_accept_official_stacked_classes(
tmp_path: Path,
) -> None:
source_codes = sorted(WalousLandCoverService.WALOUS_2018_CLASS_CROSSWALK)
source_path = tmp_path / "walous_land_cover_2018_3812.tif"
make_source(source_path, class_codes=source_codes)
validation = load_provisioner().validate_raster(source_path)
registry = {
item["key"]: item
for item in WalousLandCoverService.list_products(settings=settings(tmp_path))
}
assert validation["sample_classes"] == source_codes
assert validation["implicit_source_nodata_values"] == [0]
assert registry["walous_land_cover_2018"]["configured"] is True
assert registry["walous_land_cover_2018"]["observation_year"] == 2018
assert "crosswalk" in registry["walous_land_cover_2018"]["limitation_message"]
def test_walous_2018_acquisition_normalizes_stacked_classes_with_explicit_provenance(
tmp_path: Path, monkeypatch
) -> None:
source_codes = sorted(WalousLandCoverService.WALOUS_2018_CLASS_CROSSWALK)
bbox, _values = make_source(
tmp_path / "walous_land_cover_2018_3812.tif",
class_codes=source_codes,
)
project = Project(id=uuid4(), name="Belgium")
captured = {}
def persist(_db, **kwargs):
captured.update(kwargs)
return SimpleNamespace(id=uuid4())
monkeypatch.setattr(DatasetService, "import_raster_bytes", persist)
result = WalousLandCoverService.acquire(
FakeSession(project),
project.id,
ThematicRasterAcquireRequest(
bbox={
"min_x": bbox[0],
"min_y": bbox[1],
"max_x": bbox[2],
"max_y": bbox[3],
"crs": "EPSG:4326",
},
product_key="walous_land_cover_2018",
force_refresh=True,
),
settings=settings(tmp_path),
)
assert result["observation_year"] == 2018
assert captured["source_metadata"]["classes_present"] == [
1,
2,
3,
4,
5,
6,
7,
8,
9,
80,
90,
]
assert captured["source_metadata"]["source_classes_present"] == source_codes
assert captured["source_metadata"]["class_crosswalk"][62] == 2
assert captured["source_metadata"]["class_crosswalk"][0] == 255
assert (
captured["source_metadata"]["attribution"]
== "Service public de Wallonie (SPW), UCLouvain, ULB, ISSeP"
)
assert captured["observed_at"].date().isoformat() == "2018-12-31"
def test_walous_acquisition_reads_real_classes_and_persists_provenance(
tmp_path: Path, monkeypatch
) -> None:
bbox, _values = make_source(tmp_path / "walous_land_cover_2023_3812.tif")
project = Project(id=uuid4(), name="Belgium")
db = FakeSession(project)
@@ -156,7 +270,13 @@ def test_walous_acquisition_reads_real_classes_and_persists_provenance(tmp_path:
db,
project.id,
ThematicRasterAcquireRequest(
bbox={"min_x": bbox[0], "min_y": bbox[1], "max_x": bbox[2], "max_y": bbox[3], "crs": "EPSG:4326"},
bbox={
"min_x": bbox[0],
"min_y": bbox[1],
"max_x": bbox[2],
"max_y": bbox[3],
"crs": "EPSG:4326",
},
product_key="walous_land_cover_2023",
force_refresh=True,
),
@@ -166,7 +286,19 @@ def test_walous_acquisition_reads_real_classes_and_persists_provenance(tmp_path:
assert result["output_dataset_id"] == str(output_id)
assert result["resolution_m"] == 10
assert captured["source_name"] == "spw_walous_land_cover"
assert captured["source_metadata"]["classes_present"] == [1, 2, 3, 4, 5, 6, 7, 8, 9, 80, 90]
assert captured["source_metadata"]["classes_present"] == [
1,
2,
3,
4,
5,
6,
7,
8,
9,
80,
90,
]
assert captured["provenance_metadata"]["resampling"] == "nearest"
assert captured["temporal_series_key"].startswith("spw:walous:land-cover:")
assert captured["observed_at"].date().isoformat() == "2023-06-25"
@@ -174,7 +306,9 @@ def test_walous_acquisition_reads_real_classes_and_persists_provenance(tmp_path:
assert captured["valid_to"] == captured["observed_at"]
def test_walous_acquisition_accepts_official_signed_int8_nodata(tmp_path: Path, monkeypatch) -> None:
def test_walous_acquisition_accepts_official_signed_int8_nodata(
tmp_path: Path, monkeypatch
) -> None:
bbox, _values = make_source(
tmp_path / "walous_land_cover_2023_3812.tif",
dtype="int8",
@@ -193,7 +327,13 @@ def test_walous_acquisition_accepts_official_signed_int8_nodata(tmp_path: Path,
FakeSession(project),
project.id,
ThematicRasterAcquireRequest(
bbox={"min_x": bbox[0], "min_y": bbox[1], "max_x": bbox[2], "max_y": bbox[3], "crs": "EPSG:4326"},
bbox={
"min_x": bbox[0],
"min_y": bbox[1],
"max_x": bbox[2],
"max_y": bbox[3],
"crs": "EPSG:4326",
},
product_key="walous_land_cover_2023",
force_refresh=True,
),
@@ -201,14 +341,28 @@ def test_walous_acquisition_accepts_official_signed_int8_nodata(tmp_path: Path,
)
assert result["output_dataset_id"] == str(output_id)
assert captured["source_metadata"]["classes_present"] == [1, 2, 3, 4, 5, 6, 7, 8, 9, 80, 90]
assert captured["source_metadata"]["classes_present"] == [
1,
2,
3,
4,
5,
6,
7,
8,
9,
80,
90,
]
with rasterio.MemoryFile(captured["content"]) as memory:
with memory.open() as derived:
assert derived.dtypes == ("uint8",)
assert derived.nodata == 255
def test_walous_analysis_returns_semantic_area_metrics(tmp_path: Path, monkeypatch) -> None:
def test_walous_analysis_returns_semantic_area_metrics(
tmp_path: Path, monkeypatch
) -> None:
bbox, _values = make_source(tmp_path / "walous_land_cover_2023_3812.tif")
project = Project(id=uuid4(), name="Belgium")
output_id = uuid4()
@@ -221,7 +375,13 @@ def test_walous_analysis_returns_semantic_area_metrics(tmp_path: Path, monkeypat
monkeypatch.setattr(DatasetService, "import_raster_bytes", persist)
db = FakeSession(project)
payload = ThematicRasterAcquireRequest(
bbox={"min_x": bbox[0], "min_y": bbox[1], "max_x": bbox[2], "max_y": bbox[3], "crs": "EPSG:4326"},
bbox={
"min_x": bbox[0],
"min_y": bbox[1],
"max_x": bbox[2],
"max_y": bbox[3],
"crs": "EPSG:4326",
},
product_key="walous_land_cover_2023",
force_refresh=True,
)
@@ -247,7 +407,10 @@ def test_walous_analysis_returns_semantic_area_metrics(tmp_path: Path, monkeypat
output_id,
ThematicRasterSelectionRequest(bbox=payload.bbox),
)
metrics = {item["metric_key"]: item["metric_value"] for item in result["summary"]["metrics"]}
metrics = {
item["metric_key"]: item["metric_value"]
for item in result["summary"]["metrics"]
}
assert result["metric_kind"] == "categorical_area"
assert metrics["land_cover_observed_area_ha"] > 0
@@ -270,7 +433,10 @@ def test_walous_render_png_uses_governed_class_colours(tmp_path: Path) -> None:
dataset_type="raster",
source="SPW WALOUS",
source_name="spw_walous_land_cover",
source_metadata={"product_key": "walous_land_cover_2023", "bbox_epsg4326": bbox},
source_metadata={
"product_key": "walous_land_cover_2023",
"bbox_epsg4326": bbox,
},
storage_path=str(tmp_path / "walous_land_cover_2023_3812.tif"),
status="ready",
)
@@ -281,7 +447,9 @@ def test_walous_render_png_uses_governed_class_colours(tmp_path: Path) -> None:
assert rendered.startswith(b"\x89PNG\r\n\x1a\n")
def test_walous_temporal_comparison_reuses_persisted_raster_metrics(monkeypatch) -> None:
def test_walous_temporal_comparison_reuses_persisted_raster_metrics(
monkeypatch,
) -> None:
project_id = uuid4()
earlier = Dataset(
id=uuid4(),
@@ -320,14 +488,16 @@ def test_walous_temporal_comparison_reuses_persisted_raster_metrics(monkeypatch)
"metric_unit": "ha",
"aggregation_method": "nearest_resampled_cells_times_cell_area",
"primary_metric_key": "land_cover_observed_area_ha",
"metrics": [{
"metric_key": "land_cover_observed_area_ha",
"metric_label": "Gekarteerde landbedekking",
"metric_value": value,
"metric_unit": "ha",
"aggregation_method": "nearest_resampled_cells_times_cell_area",
"is_estimate": True,
}],
"metrics": [
{
"metric_key": "land_cover_observed_area_ha",
"metric_label": "Gekarteerde landbedekking",
"metric_value": value,
"metric_unit": "ha",
"aggregation_method": "nearest_resampled_cells_times_cell_area",
"is_estimate": True,
}
],
},
"limitation_message": "Cell-based estimate.",
}
@@ -336,10 +506,18 @@ def test_walous_temporal_comparison_reuses_persisted_raster_metrics(monkeypatch)
payload = TemporalComparisonRequest(
earlier_dataset_id=earlier.id,
later_dataset_id=later.id,
bbox={"min_x": 4.8, "min_y": 50.4, "max_x": 4.9, "max_y": 50.5, "crs": "EPSG:4326"},
bbox={
"min_x": 4.8,
"min_y": 50.4,
"max_x": 4.9,
"max_y": 50.5,
"crs": "EPSG:4326",
},
)
result = TemporalAnalysisService.compare(TemporalSession(), project_id=project_id, payload=payload)
result = TemporalAnalysisService.compare(
TemporalSession(), project_id=project_id, payload=payload
)
assert result.metric.earlier_value == 4.0
assert result.metric.later_value == 5.5
@@ -354,7 +532,10 @@ def test_walous_api_routes_use_canonical_envelopes(monkeypatch) -> None:
monkeypatch.setattr(
WalousLandCoverService,
"acquire",
lambda *_args, **_kwargs: {"output_dataset_id": str(dataset_id), "provider": WalousLandCoverService.PROVIDER},
lambda *_args, **_kwargs: {
"output_dataset_id": str(dataset_id),
"provider": WalousLandCoverService.PROVIDER,
},
)
monkeypatch.setattr(
WalousLandCoverService,
@@ -364,7 +545,13 @@ def test_walous_api_routes_use_canonical_envelopes(monkeypatch) -> None:
"product_key": "walous_land_cover_2023",
"theme": "land_cover_use",
"metric_kind": "categorical_area",
"selection_bbox": {"min_x": 4.8, "min_y": 50.4, "max_x": 4.9, "max_y": 50.5, "crs": "EPSG:4326"},
"selection_bbox": {
"min_x": 4.8,
"min_y": 50.4,
"max_x": 4.9,
"max_y": 50.5,
"crs": "EPSG:4326",
},
"selected_cell_count": 100,
"valid_cell_count": 100,
"coverage_ratio": 1.0,
@@ -390,20 +577,37 @@ def test_walous_api_routes_use_canonical_envelopes(monkeypatch) -> None:
acquisition = client.post(
f"/api/v1/projects/{project.id}/datasets/walous/acquire",
json={
"bbox": {"min_x": 4.8, "min_y": 50.4, "max_x": 4.9, "max_y": 50.5, "crs": "EPSG:4326"},
"bbox": {
"min_x": 4.8,
"min_y": 50.4,
"max_x": 4.9,
"max_y": 50.5,
"crs": "EPSG:4326",
},
"product_key": "walous_land_cover_2023",
},
)
selection = client.post(
f"/api/v1/projects/{project.id}/datasets/{dataset_id}/raster/walous/select",
json={"bbox": {"min_x": 4.8, "min_y": 50.4, "max_x": 4.9, "max_y": 50.5, "crs": "EPSG:4326"}},
json={
"bbox": {
"min_x": 4.8,
"min_y": 50.4,
"max_x": 4.9,
"max_y": 50.5,
"crs": "EPSG:4326",
}
},
)
finally:
app.dependency_overrides.clear()
assert products.status_code == 200 and set(products.json()) == {"data"}
assert products.json()["data"]["total"] == 2
assert products.json()["data"]["total"] == 3
assert acquisition.status_code == 200 and set(acquisition.json()) == {"data"}
assert acquisition.json()["data"]["job_type"] == "raster.walous.acquire"
assert selection.status_code == 200 and selection.json()["data"]["theme"] == "land_cover_use"
assert (
selection.status_code == 200
and selection.json()["data"]["theme"] == "land_cover_use"
)
assert any(isinstance(item, Job) for item in db.added)