From 547d78beb43260b3020bc91f759fbc98bd08883a Mon Sep 17 00:00:00 2001 From: mishaschwartz <4380924+mishaschwartz@users.noreply.github.com> Date: Wed, 10 Jun 2026 13:25:42 -0400 Subject: [PATCH 1/2] store assets directly --- marble_api/versions/v1/data_request/models.py | 9 ++++----- test/faker_providers.py | 20 +++++++++++++++---- .../versions/v1/data_request/test_models.py | 8 ++------ 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/marble_api/versions/v1/data_request/models.py b/marble_api/versions/v1/data_request/models.py index 872a4c4..452cf61 100644 --- a/marble_api/versions/v1/data_request/models.py +++ b/marble_api/versions/v1/data_request/models.py @@ -21,6 +21,7 @@ from pydantic.json_schema import SkipJsonSchema from stac_pydantic.item import Item from stac_pydantic.links import Links +from stac_pydantic.shared import Asset from typing_extensions import Annotated from marble_api.utils.geojson import ( @@ -59,14 +60,12 @@ class DataRequest(BaseModel): temporal: Temporal tz_offset: SkipJsonSchema[list[float] | None] = Field(default=None, exclude=True) links: Links - path: str + assets: dict[str, Asset] contact: EmailStr - additional_paths: list[str] = [] - variables: list[str] = [] extra_properties: dict[str, str] = {} model_config = ConfigDict(populate_by_name=True, arbitrary_types_allowed=True) - @field_validator("title", "description", "authors", "path", "contact") + @field_validator("title", "description", "authors", "assets", "contact") @classmethod def min_length_if_set(cls, value: Sized | None, info: ValidationInfo) -> Sized | None: """Raise an error if the value is not None and is empty.""" @@ -138,7 +137,7 @@ def stac_item(self) -> Item: "bbox": None, "properties": dict(self.extra_properties), # TODO: add more "links": self.links.model_dump(), - "assets": {}, # TODO: determine assets from other fields + "assets": self.assets.model_dump(), } # STAC spec recommends including datetime even if using start_datetime and end_datetime diff --git a/test/faker_providers.py b/test/faker_providers.py index 69e2646..06f343a 100644 --- a/test/faker_providers.py +++ b/test/faker_providers.py @@ -210,6 +210,15 @@ def temporal(self): def link(self): return {"href": self.generator.uri(), "rel": self.generator.word(), "type": self.generator.mime_type()} + def asset(self): + return { + "href": self.generator.uri(), + "type": self.generator.mime_type(), + "title": self.generator.word(), + "description": self.generator.sentence(), + "roles": self.generator.get_words_list(), + } + def _data_request_inputs(self, unset=None): inputs = dict( id=bson.ObjectId(), @@ -220,11 +229,14 @@ def _data_request_inputs(self, unset=None): geometry=self.collapsible_geojson(), temporal=self.temporal(), links=[self.link() for _ in range(self.generator.random.randint(0, 10))], - path=self.generator.file_path(), + assets={ + key: self.asset() + for key in self.generator.pylist( + nb_elements=self.generator.pyint(1, 10), variable_nb_elements=False, value_types=[str] + ) + }, contact=self.generator.email(), - additional_paths=[self.generator.file_path() for _ in range(self.generator.random.randint(0, 10))], - variables=([] if self.generator.pybool(10) else self.generator.pylist(allowed_types=[str])), - extra_properties=({} if self.generator.pybool(10) else self.generator.pydict(allowed_types=[str])), + extra_properties=({} if self.generator.pybool(10) else self.generator.pydict(value_types=[str])), ) if unset: for field in unset: diff --git a/test/unit/versions/v1/data_request/test_models.py b/test/unit/versions/v1/data_request/test_models.py index 191a33a..e038d55 100644 --- a/test/unit/versions/v1/data_request/test_models.py +++ b/test/unit/versions/v1/data_request/test_models.py @@ -34,7 +34,7 @@ def fake_class(self, fake): def test_id_dumped(self, fake_class): assert "id" not in fake_class().model_dump() - @pytest.mark.parametrize("field", ["title", "description", "authors", "path", "contact"]) + @pytest.mark.parametrize("field", ["title", "description", "authors", "assets", "contact"]) def test_text_fields_not_empty(self, fake_class, field): with pytest.raises(ValidationError): fake_class(**{field: ""}) @@ -46,10 +46,8 @@ def test_text_fields_not_empty(self, fake_class, field): "authors", "temporal", "links", - "path", + "assets", "contact", - "additional_paths", - "variables", "extra_properties", ], ) @@ -68,8 +66,6 @@ def test_user_field_present_when_serialized(self, fake_class, value): "field", [ "description", - "additional_paths", - "variables", "extra_properties", ], ) From fecc594f109a9e251244b059e6b3f7b10c38580a Mon Sep 17 00:00:00 2001 From: mishaschwartz <4380924+mishaschwartz@users.noreply.github.com> Date: Wed, 10 Jun 2026 13:30:33 -0400 Subject: [PATCH 2/2] fix stac export --- marble_api/versions/v1/data_request/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/marble_api/versions/v1/data_request/models.py b/marble_api/versions/v1/data_request/models.py index 452cf61..0f39c9f 100644 --- a/marble_api/versions/v1/data_request/models.py +++ b/marble_api/versions/v1/data_request/models.py @@ -137,7 +137,7 @@ def stac_item(self) -> Item: "bbox": None, "properties": dict(self.extra_properties), # TODO: add more "links": self.links.model_dump(), - "assets": self.assets.model_dump(), + "assets": {key: asset.model_dump() for key, asset in self.assets.items()}, } # STAC spec recommends including datetime even if using start_datetime and end_datetime