Files
geointel/backend/app/providers/registry.py
T
Codex 488da4cc83
GeoIntel CI / docs-smoke (push) Canceled after 0s
GeoIntel CI / contract-smoke (push) Canceled after 0s
Add bounded GRB map acquisition
2026-07-17 21:29:26 +02:00

154 lines
5.5 KiB
Python

from __future__ import annotations
from pydantic import BaseModel
from app.core.errors import AppError
from app.providers.base import ProviderCapability
from app.providers.fixture import FixtureProvider
from app.providers.grb import GRBProvider
from app.providers.manual import ManualProvider
from app.providers.osm import OSMProvider
class ProviderDatasetMapping(BaseModel):
provider_name: str
dataset_role: str
source_name: str
reference_required: bool
write_path: str = "DatasetService"
class ProviderImportResult(BaseModel):
provider_name: str
status: str
message: str
requested_layers: list[str]
dataset_id: str | None = None
dataset_role: str | None = None
source_name: str | None = None
class ExternalProviderRegistry:
def __init__(self) -> None:
self.providers = {
"grb": GRBProvider(),
"osm": OSMProvider(),
"manual": ManualProvider(),
"fixture": FixtureProvider(),
}
def list_capabilities(self) -> list[ProviderCapability]:
return [provider.capability for provider in self.providers.values()]
def get(self, provider_name: str):
normalized = provider_name.strip().lower()
if normalized not in self.providers:
raise AppError(code="PROVIDER_NOT_FOUND", message="Provider not found", status_code=404)
return self.providers[normalized]
def fetch(self, provider_name: str, project_id: str, area_id: str | None, layers: list[str]) -> dict:
provider = self.get(provider_name)
return provider.fetch(project_id=project_id, area_id=area_id, layers=layers)
def dataset_mapping(self, provider_name: str, requested_dataset_role: str | None = None) -> ProviderDatasetMapping:
provider = self.get(provider_name)
if provider.provider_name == "osm":
dataset_role = "reference" if requested_dataset_role == "reference" else "source"
return ProviderDatasetMapping(
provider_name="osm",
dataset_role=dataset_role,
source_name="osm",
reference_required=requested_dataset_role == "reference",
)
return ProviderDatasetMapping(
provider_name=provider.provider_name,
dataset_role="reference",
source_name=provider.provider_name,
reference_required=True,
)
def import_contract(
self,
provider_name: str,
project_id: str,
area_id: str | None,
layers: list[str],
requested_dataset_role: str | None = None,
) -> ProviderImportResult:
del project_id, area_id
provider = self.get(provider_name)
mapping = self.dataset_mapping(provider.provider_name, requested_dataset_role=requested_dataset_role)
if provider.provider_name == "grb":
return ProviderImportResult(
provider_name="grb",
status="bounded_request_required",
message=(
"Use the governed project GRB acquisition endpoint with an EPSG:4326 bounding box "
"and one supported layer."
),
requested_layers=layers,
dataset_role=mapping.dataset_role,
source_name=mapping.source_name,
)
if provider.provider_name == "osm":
return ProviderImportResult(
provider_name=provider.provider_name,
status="not_configured",
message=f"No live {provider.display_name} import is configured.",
requested_layers=layers,
dataset_role=mapping.dataset_role,
source_name=mapping.source_name,
)
if provider.provider_name == "manual":
return ProviderImportResult(
provider_name="manual",
status="upload_flow_required",
message="Manual provider data must use the existing dataset upload/reference flow.",
requested_layers=layers,
dataset_role=mapping.dataset_role,
source_name=mapping.source_name,
)
return ProviderImportResult(
provider_name="fixture",
status="fixture_flow_required",
message="Fixture provider data must use checked-in demo/test fixture flows.",
requested_layers=layers,
dataset_role=mapping.dataset_role,
source_name=mapping.source_name,
)
_registry = ExternalProviderRegistry()
def list_provider_capabilities() -> list[ProviderCapability]:
return _registry.list_capabilities()
def get_provider(provider_name: str):
return _registry.get(provider_name)
def fetch_provider_data(provider_name: str, project_id: str, area_id: str | None, layers: list[str]) -> dict:
return _registry.fetch(provider_name, project_id, area_id, layers)
def get_provider_dataset_mapping(provider_name: str, requested_dataset_role: str | None = None) -> ProviderDatasetMapping:
return _registry.dataset_mapping(provider_name, requested_dataset_role=requested_dataset_role)
def import_provider_dataset(
provider_name: str,
project_id: str,
area_id: str | None,
layers: list[str],
requested_dataset_role: str | None = None,
) -> ProviderImportResult:
return _registry.import_contract(
provider_name=provider_name,
project_id=project_id,
area_id=area_id,
layers=layers,
requested_dataset_role=requested_dataset_role,
)