from __future__ import annotations from typing import Literal from uuid import UUID from pydantic import BaseModel, Field, model_validator CoverageStatus = Literal["operational", "partial", "not_configured", "unsupported"] CoverageAuthority = Literal["authoritative", "official_context", "contextual"] CoverageAcquisitionMode = Literal[ "operator_archive", "operator_wfs", "bounded_api", "bounded_raster", "catalog_only", ] class CoverageBBox(BaseModel): minx: float = Field(ge=-180, le=180) miny: float = Field(ge=-90, le=90) maxx: float = Field(ge=-180, le=180) maxy: float = Field(ge=-90, le=90) @model_validator(mode="after") def validate_extent(self) -> "CoverageBBox": if self.maxx <= self.minx or self.maxy <= self.miny: raise ValueError("bbox max values must be greater than min values") return self class CoverageSourceContract(BaseModel): source_name: str display_name: str authority_level: CoverageAuthority coverage_zones: list[str] themes: list[str] native_layers: list[str] supported_geometry_types: list[str] acquisition_mode: CoverageAcquisitionMode integration_status: CoverageStatus source_url: str attribution: str license_note: str limitation_message: str class CoverageCatalogResponse(BaseModel): themes: list[str] zones: list[str] statuses: list[CoverageStatus] sources: list[CoverageSourceContract] class CoverageResolveRequest(BaseModel): project_id: UUID bbox: CoverageBBox themes: list[str] = Field(default_factory=list, max_length=32) class CoverageResolutionItem(BaseModel): zone: str theme: str status: CoverageStatus source_names: list[str] materialized_dataset_ids: list[UUID] evidence: list["CoverageEvidenceItem"] = Field(default_factory=list) limitation_message: str class CoverageEvidenceItem(BaseModel): dataset_id: UUID source_name: str authority_level: CoverageAuthority source_version: str | None = None observed_at: str | None = None published_at: str | None = None crs: str | None = None resolution: dict | None = None coverage_bbox_epsg4326: list[float] | None = None attribution: str | None = None license_note: str | None = None checksum_sha256: str | None = None class CoverageResolveResponse(BaseModel): project_id: UUID bbox: CoverageBBox requested_themes: list[str] intersected_zones: list[str] outside_supported_scope: bool items: list[CoverageResolutionItem] warnings: list[str]