datacosmos 0.0.2__tar.gz → 0.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of datacosmos might be problematic. Click here for more details.

Files changed (56) hide show
  1. {datacosmos-0.0.2/datacosmos.egg-info → datacosmos-0.0.4}/PKG-INFO +4 -2
  2. datacosmos-0.0.4/README.md +368 -0
  3. {datacosmos-0.0.2 → datacosmos-0.0.4}/config/config.py +56 -28
  4. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/stac/collection/collection_client.py +6 -2
  5. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/stac/collection/models/collection_update.py +1 -0
  6. datacosmos-0.0.4/datacosmos/stac/constants/__init__.py +1 -0
  7. datacosmos-0.0.4/datacosmos/stac/constants/satellite_name_mapping.py +20 -0
  8. datacosmos-0.0.4/datacosmos/stac/enums/__init__.py +1 -0
  9. datacosmos-0.0.4/datacosmos/stac/enums/processing_level.py +15 -0
  10. datacosmos-0.0.4/datacosmos/stac/enums/product_type.py +11 -0
  11. datacosmos-0.0.4/datacosmos/stac/enums/season.py +14 -0
  12. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/stac/item/item_client.py +11 -4
  13. datacosmos-0.0.4/datacosmos/stac/item/models/asset.py +23 -0
  14. datacosmos-0.0.4/datacosmos/stac/item/models/catalog_search_parameters.py +132 -0
  15. datacosmos-0.0.4/datacosmos/stac/item/models/datacosmos_item.py +55 -0
  16. datacosmos-0.0.4/datacosmos/stac/item/models/eo_band.py +15 -0
  17. datacosmos-0.0.4/datacosmos/stac/item/models/raster_band.py +17 -0
  18. datacosmos-0.0.4/datacosmos/uploader/__init__.py +1 -0
  19. datacosmos-0.0.4/datacosmos/uploader/dataclasses/__init__.py +1 -0
  20. datacosmos-0.0.4/datacosmos/uploader/dataclasses/upload_path.py +93 -0
  21. datacosmos-0.0.4/datacosmos/uploader/datacosmos_uploader.py +106 -0
  22. datacosmos-0.0.4/datacosmos/utils/constants.py +16 -0
  23. datacosmos-0.0.4/datacosmos/utils/missions.py +27 -0
  24. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/utils/url.py +23 -0
  25. {datacosmos-0.0.2 → datacosmos-0.0.4/datacosmos.egg-info}/PKG-INFO +4 -2
  26. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos.egg-info/SOURCES.txt +17 -0
  27. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos.egg-info/requires.txt +1 -0
  28. {datacosmos-0.0.2 → datacosmos-0.0.4}/pyproject.toml +3 -2
  29. datacosmos-0.0.2/README.md +0 -257
  30. {datacosmos-0.0.2 → datacosmos-0.0.4}/LICENSE.md +0 -0
  31. {datacosmos-0.0.2 → datacosmos-0.0.4}/config/__init__.py +0 -0
  32. {datacosmos-0.0.2 → datacosmos-0.0.4}/config/models/__init__.py +0 -0
  33. {datacosmos-0.0.2 → datacosmos-0.0.4}/config/models/m2m_authentication_config.py +0 -0
  34. {datacosmos-0.0.2 → datacosmos-0.0.4}/config/models/url.py +0 -0
  35. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/__init__.py +0 -0
  36. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/datacosmos_client.py +0 -0
  37. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/exceptions/__init__.py +0 -0
  38. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/exceptions/datacosmos_exception.py +0 -0
  39. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/stac/__init__.py +0 -0
  40. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/stac/collection/__init__.py +0 -0
  41. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/stac/collection/models/__init__.py +0 -0
  42. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/stac/item/__init__.py +0 -0
  43. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/stac/item/models/__init__.py +0 -0
  44. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/stac/item/models/item_update.py +0 -0
  45. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/stac/item/models/search_parameters.py +0 -0
  46. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/stac/stac_client.py +0 -0
  47. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/utils/__init__.py +0 -0
  48. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/utils/http_response/__init__.py +0 -0
  49. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/utils/http_response/check_api_response.py +0 -0
  50. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/utils/http_response/models/__init__.py +0 -0
  51. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/utils/http_response/models/datacosmos_error.py +0 -0
  52. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos/utils/http_response/models/datacosmos_response.py +0 -0
  53. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos.egg-info/dependency_links.txt +0 -0
  54. {datacosmos-0.0.2 → datacosmos-0.0.4}/datacosmos.egg-info/top_level.txt +0 -0
  55. {datacosmos-0.0.2 → datacosmos-0.0.4}/setup.cfg +0 -0
  56. {datacosmos-0.0.2 → datacosmos-0.0.4}/tests/test_pass.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: datacosmos
3
- Version: 0.0.2
3
+ Version: 0.0.4
4
4
  Summary: A library for interacting with DataCosmos from Python code
5
5
  Author-email: Open Cosmos <support@open-cosmos.com>
6
6
  Classifier: Programming Language :: Python :: 3
@@ -13,6 +13,7 @@ Requires-Dist: oauthlib==3.2.0
13
13
  Requires-Dist: requests-oauthlib==1.3.1
14
14
  Requires-Dist: pydantic==2.10.6
15
15
  Requires-Dist: pystac==1.12.1
16
+ Requires-Dist: pyyaml==6.0.2
16
17
  Provides-Extra: dev
17
18
  Requires-Dist: black==22.3.0; extra == "dev"
18
19
  Requires-Dist: ruff==0.9.5; extra == "dev"
@@ -20,3 +21,4 @@ Requires-Dist: pytest==7.2.0; extra == "dev"
20
21
  Requires-Dist: bandit[toml]==1.7.4; extra == "dev"
21
22
  Requires-Dist: isort==5.11.4; extra == "dev"
22
23
  Requires-Dist: pydocstyle==6.1.1; extra == "dev"
24
+ Dynamic: license-file
@@ -0,0 +1,368 @@
1
+ # DataCosmos SDK
2
+
3
+ ## Overview
4
+
5
+ The **DataCosmos SDK** enables Open Cosmos customers to interact with the **DataCosmos APIs** for efficient data management and retrieval. It provides authentication handling, HTTP request utilities, and a client for interacting with the **STAC API** (SpatioTemporal Asset Catalog).
6
+
7
+ ## Installation
8
+
9
+ Install the SDK using **pip**:
10
+
11
+ ```sh
12
+ pip install datacosmos=={version}
13
+ ```
14
+
15
+ ## Initializing the Client
16
+
17
+ To start using the SDK, initialize the client. The easiest way to do this is by loading the configuration from a YAML file. Alternatively, you can manually instantiate the Config object or use environment variables.
18
+
19
+ ### Default Initialization (Recommended)
20
+
21
+ By default, the client loads configuration from a YAML file (`config/config.yaml`).
22
+
23
+ ```python
24
+ from datacosmos.datacosmos_client import DatacosmosClient
25
+
26
+ client = DatacosmosClient()
27
+ ```
28
+
29
+ ### Loading from YAML (Recommended)
30
+
31
+ Create a YAML file (`config/config.yaml`) with the following content:
32
+
33
+ ```yaml
34
+ authentication:
35
+ client_id: {client_id}
36
+ client_secret: {client_secret}
37
+ ```
38
+
39
+ The client will automatically read this file when initialized.
40
+
41
+ ### Loading from Environment Variables
42
+
43
+ Set the following environment variables:
44
+
45
+ ```sh
46
+ export OC_AUTH_CLIENT_ID={client_id}
47
+ export OC_AUTH_CLIENT_SECRET={client_secret}
48
+ ```
49
+
50
+ The client will automatically read these values when initialized.
51
+
52
+ ### Manual Instantiation
53
+
54
+ If manually instantiating `Config`, default values are now applied where possible.
55
+
56
+ ```python
57
+ from config.config import Config
58
+ from config.models.m2m_authentication_config import M2MAuthenticationConfig
59
+ from config.models.url import URL
60
+
61
+ config = Config(
62
+ authentication=M2MAuthenticationConfig(
63
+ client_id="your-client-id",
64
+ client_secret="your-client-secret"
65
+ )
66
+ )
67
+
68
+ client = DatacosmosClient(config=config)
69
+ ```
70
+
71
+ ### Configuration Options and Defaults
72
+
73
+ | Setting | Default Value | Override Method |
74
+ |------------------------------|-------------------------------------------------|----------------|
75
+ | `authentication.type` | `m2m` | YAML / ENV |
76
+ | `authentication.client_id` | _Required in manual instantiation_ | YAML / ENV |
77
+ | `authentication.client_secret` | _Required in manual instantiation_ | YAML / ENV |
78
+ | `stac.protocol` | `https` | YAML / ENV |
79
+ | `stac.host` | `app.open-cosmos.com` | YAML / ENV |
80
+ | `stac.port` | `443` | YAML / ENV |
81
+ | `stac.path` | `/api/data/v0/stac` | YAML / ENV |
82
+ | `datacosmos_cloud_storage.protocol` | `https` | YAML / ENV |
83
+ | `datacosmos_cloud_storage.host` | `app.open-cosmos.com` | YAML / ENV |
84
+ | `datacosmos_cloud_storage.port` | `443` | YAML / ENV |
85
+ | `datacosmos_cloud_storage.path` | `/api/data/v0/storage` | YAML / ENV |
86
+ | `mission_id` | `0` | YAML / ENV |
87
+ | `environment` | `test` | YAML / ENV |
88
+
89
+ ## STAC Client
90
+
91
+ The `STACClient` enables interaction with the STAC API, allowing for searching, retrieving, creating, updating, and deleting STAC items and collections.
92
+
93
+ ### Initialize STACClient
94
+
95
+ ```python
96
+ from datacosmos.datacosmos_client import DatacosmosClient
97
+ from datacosmos.stac.stac_client import STACClient
98
+
99
+ client = DatacosmosClient()
100
+ stac_client = STACClient(client)
101
+ ```
102
+
103
+ ### STACClient Methods
104
+
105
+ #### 1. **Search Items**
106
+ ```python
107
+ from datacosmos.stac.item.models.catalog_search_parameters import CatalogSearchParameters
108
+ from datacosmos.datacosmos_client import DatacosmosClient
109
+ from datacosmos.stac.stac_client import STACClient
110
+
111
+ client = DatacosmosClient()
112
+ stac_client = STACClient(client)
113
+
114
+ params = CatalogSearchParameters(
115
+ start_date="2/9/2025",
116
+ end_date="2/9/2025",
117
+ satellite=["MANTIS"],
118
+ product_type=["Satellite"],
119
+ processing_level=["L1A"]
120
+ )
121
+
122
+ items = list(stac_client.search_items(parameters=params, project_id="your-project-id"))
123
+ ```
124
+
125
+ #### 2. **Fetch a Single Item**
126
+ ```python
127
+ from datacosmos.datacosmos_client import DatacosmosClient
128
+ from datacosmos.stac.stac_client import STACClient
129
+
130
+ client = DatacosmosClient()
131
+ stac_client = STACClient(client)
132
+
133
+ item = stac_client.fetch_item(item_id="example-item", collection_id="example-collection")
134
+ ```
135
+
136
+ #### 3. **Fetch All Items in a Collection**
137
+ ```python
138
+ from datacosmos.datacosmos_client import DatacosmosClient
139
+ from datacosmos.stac.stac_client import STACClient
140
+
141
+ client = DatacosmosClient()
142
+ stac_client = STACClient(client)
143
+
144
+ items = stac_client.fetch_collection_items(collection_id="example-collection")
145
+ ```
146
+
147
+ #### 4. **Create a New STAC Item**
148
+ ```python
149
+ from pystac import Item, Asset
150
+ from datetime import datetime
151
+
152
+ from datacosmos.datacosmos_client import DatacosmosClient
153
+ from datacosmos.stac.stac_client import STACClient
154
+
155
+ client = DatacosmosClient()
156
+ stac_client = STACClient(client)
157
+
158
+ stac_item = Item(
159
+ id="new-item",
160
+ geometry={"type": "Point", "coordinates": [102.0, 0.5]},
161
+ bbox=[101.0, 0.0, 103.0, 1.0],
162
+ datetime=datetime.utcnow(),
163
+ properties={},
164
+ collection="example-collection"
165
+ )
166
+
167
+ stac_item.add_asset(
168
+ "image",
169
+ Asset(
170
+ href="https://example.com/sample-image.tiff",
171
+ media_type="image/tiff",
172
+ roles=["data"],
173
+ title="Sample Image"
174
+ )
175
+ )
176
+
177
+ stac_client.create_item(collection_id="example-collection", item=stac_item)
178
+ ```
179
+
180
+ #### 5. **Update an Existing STAC Item**
181
+ ```python
182
+ from datacosmos.stac.models.item_update import ItemUpdate
183
+ from pystac import Asset, Link
184
+
185
+ from datacosmos.datacosmos_client import DatacosmosClient
186
+ from datacosmos.stac.stac_client import STACClient
187
+
188
+ client = DatacosmosClient()
189
+ stac_client = STACClient(client)
190
+
191
+ update_payload = ItemUpdate(
192
+ properties={
193
+ "new_property": "updated_value",
194
+ "datetime": "2024-11-10T14:58:00Z"
195
+ },
196
+ assets={
197
+ "image": Asset(
198
+ href="https://example.com/updated-image.tiff",
199
+ media_type="image/tiff"
200
+ )
201
+ },
202
+ links=[
203
+ Link(rel="self", target="https://example.com/updated-image.tiff")
204
+ ],
205
+ geometry={
206
+ "type": "Point",
207
+ "coordinates": [10, 20]
208
+ },
209
+ bbox=[10.0, 20.0, 30.0, 40.0]
210
+ )
211
+
212
+ stac_client.update_item(item_id="new-item", collection_id="example-collection", update_data=update_payload)
213
+ ```
214
+
215
+ #### 6. **Delete an Item**
216
+ ```python
217
+
218
+ from datacosmos.datacosmos_client import DatacosmosClient
219
+ from datacosmos.stac.stac_client import STACClient
220
+
221
+ client = DatacosmosClient()
222
+ stac_client = STACClient(client)
223
+
224
+ stac_client.delete_item(item_id="new-item", collection_id="example-collection")
225
+ ```
226
+
227
+ #### 7. Fetch a Collection
228
+
229
+ ```python
230
+
231
+ from datacosmos.datacosmos_client import DatacosmosClient
232
+ from datacosmos.stac.stac_client import STACClient
233
+
234
+ client = DatacosmosClient()
235
+ stac_client = STACClient(client)
236
+
237
+ collection = stac_client.fetch_collection("test-collection")
238
+ ```
239
+
240
+ #### 8. Fetch All Collections
241
+
242
+ ```python
243
+
244
+ from datacosmos.datacosmos_client import DatacosmosClient
245
+ from datacosmos.stac.stac_client import STACClient
246
+
247
+ client = DatacosmosClient()
248
+ stac_client = STACClient(client)
249
+
250
+ collections = list(stac_client.fetch_all_collections())
251
+ ```
252
+
253
+ #### 9. Create a Collection
254
+
255
+ ```python
256
+ from pystac import Collection
257
+
258
+ from datacosmos.datacosmos_client import DatacosmosClient
259
+ from datacosmos.stac.stac_client import STACClient
260
+
261
+ client = DatacosmosClient()
262
+ stac_client = STACClient(client)
263
+
264
+ new_collection = Collection(
265
+ id="test-collection",
266
+ title="Test Collection",
267
+ description="This is a test collection",
268
+ license="proprietary",
269
+ extent={
270
+ "spatial": {"bbox": [[-180, -90, 180, 90]]},
271
+ "temporal": {"interval": [["2023-01-01T00:00:00Z", None]]},
272
+ },
273
+ )
274
+
275
+ stac_client.create_collection(new_collection)
276
+ ```
277
+
278
+ #### 10. Update a Collection
279
+
280
+ ```python
281
+ from datacosmos.stac.collection.models.collection_update import CollectionUpdate
282
+
283
+ from datacosmos.datacosmos_client import DatacosmosClient
284
+ from datacosmos.stac.stac_client import STACClient
285
+
286
+ client = DatacosmosClient()
287
+ stac_client = STACClient(client)
288
+
289
+ update_data = CollectionUpdate(
290
+ title="Updated Collection Title",
291
+ description="Updated description",
292
+ )
293
+
294
+ stac_client.update_collection("test-collection", update_data)
295
+ ```
296
+
297
+ #### 11. Delete a Collection
298
+
299
+ ```python
300
+
301
+ from datacosmos.datacosmos_client import DatacosmosClient
302
+ from datacosmos.stac.stac_client import STACClient
303
+
304
+ client = DatacosmosClient()
305
+ stac_client = STACClient(client)
306
+
307
+ stac_client.delete_collection("test-collection")
308
+ ```
309
+
310
+ ### Uploading Files and Registering STAC Items
311
+
312
+ You can use the `DatacosmosUploader` class to upload files to the DataCosmos cloud storage and register a STAC item.
313
+
314
+ #### Upload Files and Register STAC Item
315
+
316
+ ```python
317
+ from datacosmos.uploader.datacosmos_uploader import DatacosmosUploader
318
+
319
+ from datacosmos.datacosmos_client import DatacosmosClient
320
+
321
+ client = DatacosmosClient()
322
+
323
+ uploader = DatacosmosUploader(client)
324
+ item_json_file_path = "/path/to/stac_item.json"
325
+ uploader.upload_and_register_item(item_json_file_path)
326
+ ```
327
+
328
+ ## Error Handling
329
+
330
+ Use `try-except` blocks to handle API errors gracefully:
331
+
332
+ ```python
333
+ try:
334
+ data = client.get_data("dataset_id")
335
+ print(data)
336
+ except Exception as e:
337
+ print(f"An error occurred: {e}")
338
+ ```
339
+
340
+ ## Contributing
341
+
342
+ To contribute:
343
+
344
+ 1. Fork the repository.
345
+ 2. Create a feature branch.
346
+ 3. Submit a pull request.
347
+
348
+ ### Development Setup
349
+
350
+ Use `uv` for dependency management:
351
+
352
+ ```sh
353
+ pip install uv
354
+ uv venv
355
+ uv pip install -r pyproject.toml .[dev]
356
+ source .venv/bin/activate
357
+ ```
358
+
359
+ Before making changes, run:
360
+
361
+ ```sh
362
+ black .
363
+ isort .
364
+ ruff check .
365
+ pydocstyle .
366
+ bandit -r -c pyproject.toml .
367
+ pytest
368
+ ```
@@ -6,7 +6,7 @@ and supports environment variable-based overrides.
6
6
  """
7
7
 
8
8
  import os
9
- from typing import ClassVar, Optional
9
+ from typing import ClassVar, Literal, Optional
10
10
 
11
11
  import yaml
12
12
  from pydantic import field_validator
@@ -27,6 +27,9 @@ class Config(BaseSettings):
27
27
 
28
28
  authentication: Optional[M2MAuthenticationConfig] = None
29
29
  stac: Optional[URL] = None
30
+ datacosmos_cloud_storage: Optional[URL] = None
31
+ mission_id: int = 0
32
+ environment: Literal["local", "test", "prod"] = "test"
30
33
 
31
34
  DEFAULT_AUTH_TYPE: ClassVar[str] = "m2m"
32
35
  DEFAULT_AUTH_TOKEN_URL: ClassVar[str] = "https://login.open-cosmos.com/oauth/token"
@@ -77,7 +80,20 @@ class Config(BaseSettings):
77
80
  path=os.getenv("OC_STAC_PATH", "/api/data/v0/stac"),
78
81
  )
79
82
 
80
- return cls(authentication=authentication_config, stac=stac_config)
83
+ datacosmos_cloud_storage_config = URL(
84
+ protocol=os.getenv("DC_CLOUD_STORAGE_PROTOCOL", "https"),
85
+ host=os.getenv("DC_CLOUD_STORAGE_HOST", "app.open-cosmos.com"),
86
+ port=int(os.getenv("DC_CLOUD_STORAGE_PORT", "443")),
87
+ path=os.getenv("DC_CLOUD_STORAGE_PATH", "/api/data/v0/storage"),
88
+ )
89
+
90
+ return cls(
91
+ authentication=authentication_config,
92
+ stac=stac_config,
93
+ datacosmos_cloud_storage=datacosmos_cloud_storage_config,
94
+ mission_id=int(os.getenv("MISSION_ID", "0")),
95
+ environment=os.getenv("ENVIRONMENT", "test"),
96
+ )
81
97
 
82
98
  @field_validator("authentication", mode="before")
83
99
  @classmethod
@@ -96,7 +112,7 @@ class Config(BaseSettings):
96
112
  ValueError: If authentication is missing or required fields are not set.
97
113
  """
98
114
  if not auth_data:
99
- cls.raise_missing_auth_error()
115
+ return cls.apply_auth_defaults(M2MAuthenticationConfig())
100
116
 
101
117
  auth = cls.parse_auth_config(auth_data)
102
118
  auth = cls.apply_auth_defaults(auth)
@@ -105,34 +121,24 @@ class Config(BaseSettings):
105
121
  return auth
106
122
 
107
123
  @staticmethod
108
- def raise_missing_auth_error():
109
- """Raise an error when authentication is missing."""
110
- raise ValueError(
111
- "M2M authentication is required. Provide it via:\n"
112
- "1. Explicit instantiation (Config(authentication=...))\n"
113
- "2. A YAML config file (config.yaml)\n"
114
- "3. Environment variables (OC_AUTH_CLIENT_ID, OC_AUTH_CLIENT_SECRET, etc.)"
115
- )
116
-
117
- @staticmethod
118
- def parse_auth_config(auth_data: dict) -> M2MAuthenticationConfig:
119
- """Convert dictionary input to M2MAuthenticationConfig object."""
120
- return (
121
- M2MAuthenticationConfig(**auth_data)
122
- if isinstance(auth_data, dict)
123
- else auth_data
124
- )
125
-
126
- @classmethod
127
- def apply_auth_defaults(
128
- cls, auth: M2MAuthenticationConfig
129
- ) -> M2MAuthenticationConfig:
124
+ def apply_auth_defaults(auth: M2MAuthenticationConfig) -> M2MAuthenticationConfig:
130
125
  """Apply default authentication values if they are missing."""
131
- auth.type = auth.type or cls.DEFAULT_AUTH_TYPE
132
- auth.token_url = auth.token_url or cls.DEFAULT_AUTH_TOKEN_URL
133
- auth.audience = auth.audience or cls.DEFAULT_AUTH_AUDIENCE
126
+ auth.type = auth.type or Config.DEFAULT_AUTH_TYPE
127
+ auth.token_url = auth.token_url or Config.DEFAULT_AUTH_TOKEN_URL
128
+ auth.audience = auth.audience or Config.DEFAULT_AUTH_AUDIENCE
134
129
  return auth
135
130
 
131
+ @classmethod
132
+ def parse_auth_config(cls, auth_data: dict) -> M2MAuthenticationConfig:
133
+ """Parse authentication config from a dictionary."""
134
+ return M2MAuthenticationConfig(
135
+ type=auth_data.get("type", cls.DEFAULT_AUTH_TYPE),
136
+ token_url=auth_data.get("token_url", cls.DEFAULT_AUTH_TOKEN_URL),
137
+ audience=auth_data.get("audience", cls.DEFAULT_AUTH_AUDIENCE),
138
+ client_id=auth_data.get("client_id"),
139
+ client_secret=auth_data.get("client_secret"),
140
+ )
141
+
136
142
  @staticmethod
137
143
  def check_required_auth_fields(auth: M2MAuthenticationConfig):
138
144
  """Ensure required fields (client_id, client_secret) are provided."""
@@ -165,3 +171,25 @@ class Config(BaseSettings):
165
171
  path="/api/data/v0/stac",
166
172
  )
167
173
  return stac_config
174
+
175
+ @field_validator("datacosmos_cloud_storage", mode="before")
176
+ @classmethod
177
+ def validate_datacosmos_cloud_storage(
178
+ cls, datacosmos_cloud_storage_config: Optional[URL]
179
+ ) -> URL:
180
+ """Ensure datacosmos cloud storage configuration has a default if not explicitly set.
181
+
182
+ Args:
183
+ datacosmos_cloud_storage_config (Optional[URL]): The datacosmos cloud storage config to validate.
184
+
185
+ Returns:
186
+ URL: The validated datacosmos cloud storage configuration.
187
+ """
188
+ if datacosmos_cloud_storage_config is None:
189
+ return URL(
190
+ protocol="https",
191
+ host="app.open-cosmos.com",
192
+ port=443,
193
+ path="/api/data/v0/storage",
194
+ )
195
+ return datacosmos_cloud_storage_config
@@ -6,6 +6,7 @@ from pystac import Collection, Extent, SpatialExtent, TemporalExtent
6
6
  from pystac.utils import str_to_datetime
7
7
 
8
8
  from datacosmos.datacosmos_client import DatacosmosClient
9
+ from datacosmos.exceptions.datacosmos_exception import DatacosmosException
9
10
  from datacosmos.stac.collection.models.collection_update import CollectionUpdate
10
11
  from datacosmos.utils.http_response.check_api_response import check_api_response
11
12
 
@@ -145,5 +146,8 @@ class CollectionClient:
145
146
  """
146
147
  try:
147
148
  return next_href.split("?")[1].split("=")[-1]
148
- except (IndexError, AttributeError):
149
- raise InvalidRequest(f"Failed to parse pagination token from {next_href}")
149
+ except (IndexError, AttributeError) as e:
150
+ raise DatacosmosException(
151
+ f"Failed to parse pagination token from {next_href}",
152
+ response=e.response,
153
+ ) from e
@@ -2,6 +2,7 @@
2
2
 
3
3
  Allows partial updates where only the provided fields are modified.
4
4
  """
5
+
5
6
  from typing import Any, Dict, List, Optional
6
7
 
7
8
  from pydantic import BaseModel, Field
@@ -0,0 +1 @@
1
+ """Constants for STAC."""
@@ -0,0 +1,20 @@
1
+ """Satellite name mapping."""
2
+
3
+ SATELLITE_NAME_MAPPING = {
4
+ "GEOSAT-2": "2014-033D",
5
+ "SUPERVIEW-1-01": "2016-083A",
6
+ "SUPERVIEW-1-02": "2016-083B",
7
+ "SUPERVIEW-1-03": "2018-002A",
8
+ "SUPERVIEW-1-04": "2018-002B",
9
+ "MANTIS": "2023-174B",
10
+ "MENUT": "2023-001B",
11
+ "HAMMER": "2024-043BC",
12
+ "HAMMER-EM": "COSPAR-HAMMER-EM-TBD",
13
+ "Alisio": "2023-185M",
14
+ "Platero": "2023-174G",
15
+ "PHISAT-2": "2024-149C",
16
+ "PHISAT-2 EM": "COSPAR-PHISAT2-EM-TBD",
17
+ "Sentinel-2A": "2015-028A",
18
+ "Sentinel-2B": "2017-013A",
19
+ "Sentinel-2C": "2024-157A",
20
+ }
@@ -0,0 +1 @@
1
+ """Enums for STAC."""
@@ -0,0 +1,15 @@
1
+ """Level enum class."""
2
+
3
+ from enum import Enum
4
+
5
+
6
+ class ProcessingLevel(Enum):
7
+ """Enum class for the processing levels of the data."""
8
+
9
+ L0 = "L0"
10
+ L1A = "L1A"
11
+ L2A = "L2A"
12
+ L1B = "L1B"
13
+ L1C = "L1C"
14
+ L1D = "L1D"
15
+ L3 = "L3"
@@ -0,0 +1,11 @@
1
+ """Product type enum class."""
2
+
3
+ from enum import Enum
4
+
5
+
6
+ class ProductType(str, Enum):
7
+ """Different product types."""
8
+
9
+ SATELLITE = "Satellite"
10
+ VECTOR = "Vector"
11
+ INSIGHT = "Insight"
@@ -0,0 +1,14 @@
1
+ """Season enum class."""
2
+
3
+ from enum import Enum
4
+
5
+
6
+ class Season(str, Enum):
7
+ """Different Open Cosmos seasons."""
8
+
9
+ SUMMER = "Summer"
10
+ WINTER = "Winter"
11
+ AUTUMN = "Autumn"
12
+ SPRING = "Spring"
13
+ RAINY = "Rainy"
14
+ DRY = "Dry"
@@ -9,6 +9,10 @@ from pystac import Item
9
9
 
10
10
  from datacosmos.datacosmos_client import DatacosmosClient
11
11
  from datacosmos.exceptions.datacosmos_exception import DatacosmosException
12
+ from datacosmos.stac.item.models.catalog_search_parameters import (
13
+ CatalogSearchParameters,
14
+ )
15
+ from datacosmos.stac.item.models.datacosmos_item import DatacosmosItem
12
16
  from datacosmos.stac.item.models.item_update import ItemUpdate
13
17
  from datacosmos.stac.item.models.search_parameters import SearchParameters
14
18
  from datacosmos.utils.http_response.check_api_response import check_api_response
@@ -58,20 +62,23 @@ class ItemClient:
58
62
 
59
63
  return self.search_items(parameters)
60
64
 
61
- def search_items(self, parameters: SearchParameters) -> Generator[Item, None, None]:
65
+ def search_items(
66
+ self, parameters: CatalogSearchParameters, project_id: str
67
+ ) -> Generator[Item, None, None]:
62
68
  """Query the STAC catalog using the POST endpoint with filtering and pagination.
63
69
 
64
70
  Args:
65
- parameters (SearchParameters): The search parameters.
71
+ parameters (CatalogSearchParameters): The search parameters.
66
72
 
67
73
  Yields:
68
74
  Item: Parsed STAC item.
69
75
  """
70
76
  url = self.base_url.with_suffix("/search")
71
- body = parameters.model_dump(by_alias=True, exclude_none=True)
77
+ parameters_query = parameters.to_query()
78
+ body = {"project": project_id, "limit": 50, "query": parameters_query}
72
79
  return self._paginate_items(url, body)
73
80
 
74
- def create_item(self, collection_id: str, item: Item) -> None:
81
+ def create_item(self, collection_id: str, item: Item | DatacosmosItem) -> None:
75
82
  """Create a new STAC item in a specified collection.
76
83
 
77
84
  Args:
@@ -0,0 +1,23 @@
1
+ """Model representing a datacosmos item asset."""
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+ from datacosmos.stac.item.models.eo_band import EoBand
6
+ from datacosmos.stac.item.models.raster_band import RasterBand
7
+
8
+
9
+ class Asset(BaseModel):
10
+ """Model representing a datacosmos item asset."""
11
+
12
+ href: str
13
+ title: str
14
+ description: str
15
+ type: str
16
+ roles: list[str] | None
17
+ eo_bands: list[EoBand] | None = Field(default=None, alias="eo:bands")
18
+ raster_bands: list[RasterBand] | None = Field(default=None, alias="raster:bands")
19
+
20
+ class Config:
21
+ """Pydantic configuration."""
22
+
23
+ populate_by_name = True