eodash_catalog 0.0.16__tar.gz → 0.0.18__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 eodash_catalog might be problematic. Click here for more details.
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/.bumpversion.cfg +1 -1
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/PKG-INFO +1 -1
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/ruff.toml +1 -1
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/src/eodash_catalog/__about__.py +1 -1
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/src/eodash_catalog/endpoints.py +26 -5
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/src/eodash_catalog/generate_indicators.py +28 -26
- eodash_catalog-0.0.18/src/eodash_catalog/sh_endpoint.py +30 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/src/eodash_catalog/stac_handling.py +3 -3
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/src/eodash_catalog/utils.py +16 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/tests/test_generate.py +2 -2
- eodash_catalog-0.0.16/src/eodash_catalog/sh_endpoint.py +0 -22
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/.github/workflows/ci.yml +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/.github/workflows/python-publish.yml +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/.gitignore +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/.vscode/extensions.json +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/.vscode/settings.json +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/LICENSE.txt +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/README.md +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/pyproject.toml +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/requirements.txt +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/src/eodash_catalog/__init__.py +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/src/eodash_catalog/duration.py +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/src/eodash_catalog/thumbnails.py +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/tests/__init__.py +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/tests/test-data/regional_forecast.json +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/tests/testing-catalogs/testing.yaml +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/tests/testing-collections/test_CROPOMAT1.yaml +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/tests/testing-collections/test_see_solar_energy.yaml +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/tests/testing-collections/test_tif_demo_1.yaml +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/tests/testing-collections/test_tif_demo_2.yaml +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/tests/testing-collections/test_wms_no_time.yaml +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/tests/testing-indicators/test_indicator.yaml +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/tests/testing-layers/baselayers.yaml +0 -0
- {eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/tests/testing-layers/overlays.yaml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: eodash_catalog
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.18
|
|
4
4
|
Summary: This package is intended to help create a compatible STAC catalog for the eodash dashboard client. It supports configuration of multiple endpoint types for information extraction.
|
|
5
5
|
Project-URL: Documentation, https://github.com/eodash/eodash_catalog#readme
|
|
6
6
|
Project-URL: Issues, https://github.com/eodash/eodash_catalog/issues
|
|
@@ -4,7 +4,7 @@ import os
|
|
|
4
4
|
import sys
|
|
5
5
|
import uuid
|
|
6
6
|
from collections.abc import Callable
|
|
7
|
-
from datetime import datetime, timedelta
|
|
7
|
+
from datetime import datetime, timedelta, timezone
|
|
8
8
|
from itertools import groupby
|
|
9
9
|
from operator import itemgetter
|
|
10
10
|
|
|
@@ -27,6 +27,7 @@ from eodash_catalog.utils import (
|
|
|
27
27
|
create_geojson_from_bbox,
|
|
28
28
|
create_geojson_point,
|
|
29
29
|
generate_veda_cog_link,
|
|
30
|
+
replace_with_env_variables,
|
|
30
31
|
retrieveExtentFromWMSWMTS,
|
|
31
32
|
)
|
|
32
33
|
|
|
@@ -293,7 +294,7 @@ def handle_collection_only(
|
|
|
293
294
|
catalog, collection_config["Name"], collection_config, catalog_config, endpoint_config
|
|
294
295
|
)
|
|
295
296
|
times = get_collection_times_from_config(endpoint_config)
|
|
296
|
-
if len(times) > 0
|
|
297
|
+
if len(times) > 0:
|
|
297
298
|
for t in times:
|
|
298
299
|
item = Item(
|
|
299
300
|
id=t,
|
|
@@ -473,7 +474,7 @@ def handle_SH_endpoint(
|
|
|
473
474
|
catalog: Catalog,
|
|
474
475
|
options: Options,
|
|
475
476
|
) -> Collection:
|
|
476
|
-
token = get_SH_token()
|
|
477
|
+
token = get_SH_token(endpoint_config)
|
|
477
478
|
headers = {"Authorization": f"Bearer {token}"}
|
|
478
479
|
endpoint_config["EndPoint"] = "https://services.sentinel-hub.com/api/v1/catalog/1.0.0/"
|
|
479
480
|
# Overwrite collection id with type, such as ZARR or BYOC
|
|
@@ -509,8 +510,21 @@ def handle_WMS_endpoint(
|
|
|
509
510
|
version=endpoint_config.get("Version", "1.1.1"),
|
|
510
511
|
wmts=wmts,
|
|
511
512
|
)
|
|
513
|
+
# optionally filter time results
|
|
514
|
+
if query := endpoint_config.get("Query"):
|
|
515
|
+
datetime_query = [times[0], times[-1]]
|
|
516
|
+
if start := query.get("Start"):
|
|
517
|
+
datetime_query[0] = parser.isoparse(start).replace(tzinfo=timezone.utc)
|
|
518
|
+
if end := query.get("End"):
|
|
519
|
+
datetime_query[1] = parser.isoparse(end).replace(tzinfo=timezone.utc)
|
|
520
|
+
# filter times based on query Start/End
|
|
521
|
+
times = [
|
|
522
|
+
datetime_str
|
|
523
|
+
for datetime_str in times
|
|
524
|
+
if datetime_query[0] <= parser.isoparse(datetime_str) < datetime_query[1]
|
|
525
|
+
]
|
|
512
526
|
# Create an item per time to allow visualization in stac clients
|
|
513
|
-
if len(times) > 0
|
|
527
|
+
if len(times) > 0:
|
|
514
528
|
for t in times:
|
|
515
529
|
item = Item(
|
|
516
530
|
id=t,
|
|
@@ -567,6 +581,10 @@ def add_visualization_info(
|
|
|
567
581
|
instanceId = os.getenv("SH_INSTANCE_ID")
|
|
568
582
|
if "InstanceId" in endpoint_config:
|
|
569
583
|
instanceId = endpoint_config["InstanceId"]
|
|
584
|
+
if env_id := endpoint_config.get("CustomSHEnvId"):
|
|
585
|
+
# special handling for custom environment
|
|
586
|
+
# (will take SH_INSTANCE_ID_{env_id}) as ENV VAR
|
|
587
|
+
instanceId = os.getenv(f"SH_INSTANCE_ID_{env_id}")
|
|
570
588
|
extra_fields: dict[str, list[str] | dict[str, str]] = {
|
|
571
589
|
"wms:layers": [endpoint_config["LayerId"]],
|
|
572
590
|
"role": ["data"],
|
|
@@ -604,10 +622,13 @@ def add_visualization_info(
|
|
|
604
622
|
media_type = "image/jpeg"
|
|
605
623
|
if "MediaType" in endpoint_config:
|
|
606
624
|
media_type = endpoint_config["MediaType"]
|
|
625
|
+
endpoint_url = endpoint_config["EndPoint"]
|
|
626
|
+
# custom replacing of all ENV VARS present as template in URL as {VAR}
|
|
627
|
+
endpoint_url = replace_with_env_variables(endpoint_url)
|
|
607
628
|
stac_object.add_link(
|
|
608
629
|
Link(
|
|
609
630
|
rel="wms",
|
|
610
|
-
target=
|
|
631
|
+
target=endpoint_url,
|
|
611
632
|
media_type=media_type,
|
|
612
633
|
title=collection_config["Name"],
|
|
613
634
|
extra_fields=extra_fields,
|
|
@@ -88,6 +88,8 @@ def process_catalog_file(file_path: str, options: Options):
|
|
|
88
88
|
)
|
|
89
89
|
else:
|
|
90
90
|
print(f"Warning: neither collection nor indicator found for {collection}")
|
|
91
|
+
if "MapProjection" in catalog_config:
|
|
92
|
+
catalog.extra_fields["eodash:mapProjection"] = catalog_config["MapProjection"]
|
|
91
93
|
|
|
92
94
|
strategy = TemplateLayoutStrategy(item_template="${collection}/${year}")
|
|
93
95
|
# expecting that the catalog will be hosted online, self url should correspond to that
|
|
@@ -196,64 +198,64 @@ def process_collection_file(
|
|
|
196
198
|
with open(file_path) as f:
|
|
197
199
|
collection_config: dict = yaml.load(f, Loader=SafeLoader)
|
|
198
200
|
if "Resources" in collection_config:
|
|
199
|
-
for
|
|
201
|
+
for endpoint_config in collection_config["Resources"]:
|
|
200
202
|
collection = None
|
|
201
|
-
if
|
|
203
|
+
if endpoint_config["Name"] == "Sentinel Hub":
|
|
202
204
|
collection = handle_SH_endpoint(
|
|
203
|
-
catalog_config,
|
|
205
|
+
catalog_config, endpoint_config, collection_config, catalog, options
|
|
204
206
|
)
|
|
205
|
-
elif
|
|
207
|
+
elif endpoint_config["Name"] == "Sentinel Hub WMS":
|
|
206
208
|
collection = handle_SH_WMS_endpoint(
|
|
207
|
-
catalog_config,
|
|
209
|
+
catalog_config, endpoint_config, collection_config, catalog
|
|
208
210
|
)
|
|
209
|
-
elif
|
|
211
|
+
elif endpoint_config["Name"] == "GeoDB":
|
|
210
212
|
collection = handle_GeoDB_endpoint(
|
|
211
|
-
catalog_config,
|
|
213
|
+
catalog_config, endpoint_config, collection_config, catalog
|
|
212
214
|
)
|
|
213
|
-
elif
|
|
215
|
+
elif endpoint_config["Name"] == "VEDA":
|
|
214
216
|
collection = handle_VEDA_endpoint(
|
|
215
|
-
catalog_config,
|
|
217
|
+
catalog_config, endpoint_config, collection_config, catalog, options
|
|
216
218
|
)
|
|
217
|
-
elif
|
|
219
|
+
elif endpoint_config["Name"] == "marinedatastore":
|
|
218
220
|
collection = handle_WMS_endpoint(
|
|
219
|
-
catalog_config,
|
|
221
|
+
catalog_config, endpoint_config, collection_config, catalog, wmts=True
|
|
220
222
|
)
|
|
221
|
-
elif
|
|
223
|
+
elif endpoint_config["Name"] == "xcube":
|
|
222
224
|
collection = handle_xcube_endpoint(
|
|
223
|
-
catalog_config,
|
|
225
|
+
catalog_config, endpoint_config, collection_config, catalog
|
|
224
226
|
)
|
|
225
|
-
elif
|
|
227
|
+
elif endpoint_config["Name"] == "WMS":
|
|
226
228
|
collection = handle_WMS_endpoint(
|
|
227
|
-
catalog_config,
|
|
229
|
+
catalog_config, endpoint_config, collection_config, catalog
|
|
228
230
|
)
|
|
229
|
-
elif
|
|
231
|
+
elif endpoint_config["Name"] == "JAXA_WMTS_PALSAR":
|
|
230
232
|
# somewhat one off creation of individual WMTS layers as individual items
|
|
231
233
|
collection = handle_WMS_endpoint(
|
|
232
|
-
catalog_config,
|
|
234
|
+
catalog_config, endpoint_config, collection_config, catalog, wmts=True
|
|
233
235
|
)
|
|
234
|
-
elif
|
|
236
|
+
elif endpoint_config["Name"] == "Collection-only":
|
|
235
237
|
collection = handle_collection_only(
|
|
236
|
-
catalog_config,
|
|
238
|
+
catalog_config, endpoint_config, collection_config, catalog
|
|
237
239
|
)
|
|
238
|
-
elif
|
|
240
|
+
elif endpoint_config["Name"] == "Custom-Endpoint":
|
|
239
241
|
collection = handle_custom_endpoint(
|
|
240
242
|
catalog_config,
|
|
241
|
-
|
|
243
|
+
endpoint_config,
|
|
242
244
|
collection_config,
|
|
243
245
|
catalog,
|
|
244
246
|
)
|
|
245
|
-
elif
|
|
247
|
+
elif endpoint_config["Name"] in ["COG source", "GeoJSON source"]:
|
|
246
248
|
collection = handle_raw_source(
|
|
247
|
-
catalog_config,
|
|
249
|
+
catalog_config, endpoint_config, collection_config, catalog
|
|
248
250
|
)
|
|
249
251
|
else:
|
|
250
252
|
raise ValueError("Type of Resource is not supported")
|
|
251
253
|
if collection:
|
|
252
254
|
add_single_item_if_collection_empty(collection)
|
|
253
|
-
add_projection_info(
|
|
254
|
-
add_to_catalog(collection, catalog,
|
|
255
|
+
add_projection_info(endpoint_config, collection)
|
|
256
|
+
add_to_catalog(collection, catalog, endpoint_config, collection_config)
|
|
255
257
|
else:
|
|
256
|
-
raise Exception(f"No collection was generated for resource {
|
|
258
|
+
raise Exception(f"No collection was generated for resource {endpoint_config}")
|
|
257
259
|
elif "Subcollections" in collection_config:
|
|
258
260
|
# if no endpoint is specified we check for definition of subcollections
|
|
259
261
|
parent_collection = get_or_create_collection(
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from oauthlib.oauth2 import BackendApplicationClient
|
|
4
|
+
from requests_oauthlib import OAuth2Session
|
|
5
|
+
|
|
6
|
+
SH_TOKEN_URL = "https://services.sentinel-hub.com/oauth/token"
|
|
7
|
+
_token_cache: dict[str, str] = {}
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_SH_token(endpoint_config: dict) -> str:
|
|
11
|
+
# Your client credentials
|
|
12
|
+
client_id = os.getenv("SH_CLIENT_ID", "")
|
|
13
|
+
client_secret = os.getenv("SH_CLIENT_SECRET", "")
|
|
14
|
+
if env_id := endpoint_config.get("CustomSHEnvId"):
|
|
15
|
+
client_id = os.getenv(f"SH_CLIENT_ID_{env_id}", "")
|
|
16
|
+
client_secret = os.getenv(f"SH_CLIENT_SECRET_{env_id}", "")
|
|
17
|
+
if client_id in _token_cache:
|
|
18
|
+
return _token_cache[client_id]
|
|
19
|
+
# Create a session
|
|
20
|
+
client = BackendApplicationClient(client_id=client_id)
|
|
21
|
+
oauth = OAuth2Session(client=client)
|
|
22
|
+
# Get token for the session
|
|
23
|
+
token = oauth.fetch_token(
|
|
24
|
+
token_url=SH_TOKEN_URL,
|
|
25
|
+
client_secret=client_secret,
|
|
26
|
+
)
|
|
27
|
+
access_token = token["access_token"]
|
|
28
|
+
_token_cache[client_id] = access_token
|
|
29
|
+
|
|
30
|
+
return access_token
|
|
@@ -347,7 +347,7 @@ def add_base_overlay_info(
|
|
|
347
347
|
collection.add_link(create_web_map_link(layer, role="overlay"))
|
|
348
348
|
|
|
349
349
|
|
|
350
|
-
def add_extra_fields(stac_object: Collection |
|
|
350
|
+
def add_extra_fields(stac_object: Collection | Link, collection_config: dict) -> None:
|
|
351
351
|
if "yAxis" in collection_config:
|
|
352
352
|
stac_object.extra_fields["yAxis"] = collection_config["yAxis"]
|
|
353
353
|
if "Themes" in collection_config:
|
|
@@ -379,7 +379,7 @@ def add_extra_fields(stac_object: Collection | Catalog | Link, collection_config
|
|
|
379
379
|
if "Other" in collection_config["DataSource"]:
|
|
380
380
|
stac_object.extra_fields["otherSources"] = collection_config["DataSource"]["Other"]
|
|
381
381
|
if "MapProjection" in collection_config:
|
|
382
|
-
stac_object.extra_fields["mapProjection"] = collection_config["MapProjection"]
|
|
382
|
+
stac_object.extra_fields["eodash:mapProjection"] = collection_config["MapProjection"]
|
|
383
383
|
|
|
384
384
|
|
|
385
385
|
def get_collection_times_from_config(endpoint_config: dict) -> list[str]:
|
|
@@ -416,6 +416,6 @@ def add_projection_info(
|
|
|
416
416
|
# so we are taking over the DataProjection as is and deal with it in the eodash client
|
|
417
417
|
# in a non-standard compliant way
|
|
418
418
|
# https://github.com/proj4js/proj4js/issues/400
|
|
419
|
-
stac_object.extra_fields["proj4_def"] = proj
|
|
419
|
+
stac_object.extra_fields["eodash:proj4_def"] = proj
|
|
420
420
|
else:
|
|
421
421
|
raise Exception(f"Incorrect type of proj definition {proj}")
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import os
|
|
1
2
|
import re
|
|
2
3
|
import threading
|
|
3
4
|
import uuid
|
|
@@ -252,3 +253,18 @@ def add_single_item_if_collection_empty(collection: Collection) -> None:
|
|
|
252
253
|
end_datetime=datetime.now(),
|
|
253
254
|
)
|
|
254
255
|
collection.add_item(item)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def replace_with_env_variables(s: str) -> str:
|
|
259
|
+
# Define the regex pattern to find text within curly brackets
|
|
260
|
+
pattern = r"\{(\w+)\}"
|
|
261
|
+
|
|
262
|
+
# Define the replacement function
|
|
263
|
+
def replacer(match):
|
|
264
|
+
# Extract the variable name from the match
|
|
265
|
+
var_name = match.group(1)
|
|
266
|
+
# Get the environment variable value, if it doesn't exist, keep the original placeholder
|
|
267
|
+
return os.getenv(var_name, match.group(0))
|
|
268
|
+
|
|
269
|
+
# Use re.sub with the replacement function
|
|
270
|
+
return re.sub(pattern, replacer, s)
|
|
@@ -100,7 +100,7 @@ def test_indicator_map_projection_added(catalog_output_folder):
|
|
|
100
100
|
with open(os.path.join(root_collection_path, "collection.json")) as fp:
|
|
101
101
|
indicator_json = json.load(fp)
|
|
102
102
|
# test that collection has map projection defined
|
|
103
|
-
assert indicator_json["mapProjection"] == 3035
|
|
103
|
+
assert indicator_json["eodash:mapProjection"] == 3035
|
|
104
104
|
|
|
105
105
|
|
|
106
106
|
def test_baselayers_and_overlays_added(catalog_output_folder):
|
|
@@ -184,4 +184,4 @@ def test_baselayer_with_custom_projection_added(catalog_output_folder):
|
|
|
184
184
|
# overwrites default_baselayers, so there is just 1
|
|
185
185
|
assert len(baselayer_links) == 1
|
|
186
186
|
# test that custom proj4 definition is added to link
|
|
187
|
-
assert baselayer_links[0]["proj4_def"]["name"] == "ORTHO:680500"
|
|
187
|
+
assert baselayer_links[0]["eodash:proj4_def"]["name"] == "ORTHO:680500"
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
|
|
3
|
-
from oauthlib.oauth2 import BackendApplicationClient
|
|
4
|
-
from requests_oauthlib import OAuth2Session
|
|
5
|
-
|
|
6
|
-
SH_TOKEN_URL = "https://services.sentinel-hub.com/oauth/token"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def get_SH_token() -> str:
|
|
10
|
-
# Your client credentials
|
|
11
|
-
client_id = os.getenv("SH_CLIENT_ID")
|
|
12
|
-
client_secret = os.getenv("SH_CLIENT_SECRET")
|
|
13
|
-
# Create a session
|
|
14
|
-
client = BackendApplicationClient(client_id=client_id)
|
|
15
|
-
oauth = OAuth2Session(client=client)
|
|
16
|
-
# Get token for the session
|
|
17
|
-
token = oauth.fetch_token(
|
|
18
|
-
token_url=SH_TOKEN_URL,
|
|
19
|
-
client_secret=client_secret,
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
return token["access_token"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/tests/testing-collections/test_CROPOMAT1.yaml
RENAMED
|
File without changes
|
{eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/tests/testing-collections/test_see_solar_energy.yaml
RENAMED
|
File without changes
|
{eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/tests/testing-collections/test_tif_demo_1.yaml
RENAMED
|
File without changes
|
{eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/tests/testing-collections/test_tif_demo_2.yaml
RENAMED
|
File without changes
|
{eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/tests/testing-collections/test_wms_no_time.yaml
RENAMED
|
File without changes
|
{eodash_catalog-0.0.16 → eodash_catalog-0.0.18}/tests/testing-indicators/test_indicator.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|