eodash_catalog 0.1.13__tar.gz → 0.2.0__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.

Files changed (39) hide show
  1. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/.bumpversion.cfg +1 -1
  2. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/Dockerfile +1 -1
  3. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/PKG-INFO +1 -1
  4. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/src/eodash_catalog/__about__.py +1 -1
  5. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/src/eodash_catalog/endpoints.py +37 -5
  6. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/src/eodash_catalog/generate_indicators.py +17 -3
  7. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/src/eodash_catalog/stac_handling.py +7 -8
  8. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/src/eodash_catalog/utils.py +4 -2
  9. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/tests/test_generate.py +1 -1
  10. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/.dockerignore +0 -0
  11. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/.github/workflows/ci.yml +0 -0
  12. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/.github/workflows/python-publish.yml +0 -0
  13. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/.gitignore +0 -0
  14. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/.vscode/extensions.json +0 -0
  15. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/.vscode/settings.json +0 -0
  16. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/LICENSE.txt +0 -0
  17. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/README.md +0 -0
  18. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/pyproject.toml +0 -0
  19. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/requirements.txt +0 -0
  20. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/ruff.toml +0 -0
  21. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/src/eodash_catalog/__init__.py +0 -0
  22. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/src/eodash_catalog/duration.py +0 -0
  23. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/src/eodash_catalog/sh_endpoint.py +0 -0
  24. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/src/eodash_catalog/thumbnails.py +0 -0
  25. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/tests/__init__.py +0 -0
  26. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/tests/test-data/regional_forecast.json +0 -0
  27. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/tests/test_geoparquet.py +0 -0
  28. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/tests/testing-catalogs/testing-json.json +0 -0
  29. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/tests/testing-catalogs/testing.yaml +0 -0
  30. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/tests/testing-collections/test_CROPOMAT1.yaml +0 -0
  31. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/tests/testing-collections/test_locations_processing.json +0 -0
  32. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/tests/testing-collections/test_see_solar_energy.yaml +0 -0
  33. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/tests/testing-collections/test_tif_demo_1.yaml +0 -0
  34. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/tests/testing-collections/test_tif_demo_1_json.json +0 -0
  35. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/tests/testing-collections/test_tif_demo_2.yaml +0 -0
  36. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/tests/testing-collections/test_wms_no_time.yaml +0 -0
  37. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/tests/testing-indicators/test_indicator.yaml +0 -0
  38. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/tests/testing-layers/baselayers.yaml +0 -0
  39. {eodash_catalog-0.1.13 → eodash_catalog-0.2.0}/tests/testing-layers/overlays.yaml +0 -0
@@ -1,5 +1,5 @@
1
1
  [bumpversion]
2
- current_version = 0.1.13
2
+ current_version = 0.2.0
3
3
  commit = True
4
4
  tag = True
5
5
  parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+)\.(?P<build>\d+))?
@@ -29,4 +29,4 @@ RUN eodash_catalog --help
29
29
 
30
30
  CMD ["eodash_catalog"]
31
31
 
32
- LABEL version="0.1.13"
32
+ LABEL version="0.2.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eodash_catalog
3
- Version: 0.1.13
3
+ Version: 0.2.0
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
@@ -1,4 +1,4 @@
1
1
  # SPDX-FileCopyrightText: 2024-present Daniel Santillan <daniel.santillan@eox.at>
2
2
  #
3
3
  # SPDX-License-Identifier: MIT
4
- __version__ = "0.1.13"
4
+ __version__ = "0.2.0"
@@ -9,7 +9,7 @@ from itertools import groupby
9
9
  from operator import itemgetter
10
10
 
11
11
  import requests
12
- from pystac import Asset, Catalog, Collection, Item, Link, SpatialExtent, Summaries
12
+ from pystac import Asset, Catalog, Collection, Item, Link, SpatialExtent, Summaries, TemporalExtent
13
13
  from pystac_client import Client
14
14
  from shapely import wkt
15
15
  from shapely.geometry import mapping
@@ -31,6 +31,7 @@ from eodash_catalog.utils import (
31
31
  filter_time_entries,
32
32
  format_datetime_to_isostring_zulu,
33
33
  generate_veda_cog_link,
34
+ merge_bboxes,
34
35
  parse_datestring_to_tz_aware_datetime,
35
36
  replace_with_env_variables,
36
37
  retrieveExtentFromWCS,
@@ -499,6 +500,7 @@ def handle_GeoDB_endpoint(
499
500
  sorted_locations = sorted(response, key=itemgetter("aoi_id"))
500
501
  cities = []
501
502
  countries = []
503
+ input_data = endpoint_config.get("InputData")
502
504
  for key, value in groupby(sorted_locations, key=itemgetter("aoi_id")):
503
505
  # Finding min and max values for date
504
506
  values = list(value)
@@ -535,7 +537,6 @@ def handle_GeoDB_endpoint(
535
537
  locations_collection = get_or_create_collection(
536
538
  collection, key, sc_config, catalog_config, endpoint_config
537
539
  )
538
- input_data = endpoint_config.get("InputData")
539
540
  if input_data:
540
541
  for v in values:
541
542
  # add items based on inputData fields for each time step available in values
@@ -598,9 +599,16 @@ def handle_GeoDB_endpoint(
598
599
  # add_visualization_info(
599
600
  # item, collection_config, endpoint_config, file_url=first_match.get("FileUrl")
600
601
  # )
602
+ locations_collection.update_extent_from_items()
603
+ else:
604
+ # set spatial extent from geodb
605
+ locations_collection.extent.spatial.bboxes = [bbox]
606
+ # set time extent from geodb
607
+ individual_datetimes = [datetime.fromisoformat(v["time"]) for v in values]
608
+ time_extent = [min(individual_datetimes), max(individual_datetimes)]
609
+ locations_collection.extent.temporal = TemporalExtent([time_extent])
601
610
  locations_collection.extra_fields["subcode"] = key
602
611
  link = collection.add_child(locations_collection)
603
- locations_collection.update_extent_from_items()
604
612
  # collection.update_extent_from_items()
605
613
  # bubble up information we want to the link
606
614
  link.extra_fields["id"] = key
@@ -623,8 +631,32 @@ def handle_GeoDB_endpoint(
623
631
  add_collection_information(catalog_config, collection, collection_config)
624
632
  add_example_info(collection, collection_config, endpoint_config, catalog_config)
625
633
  collection.extra_fields["locations"] = True
626
-
627
- collection.update_extent_from_items()
634
+ if not input_data:
635
+ # we have no items, extents of collection need to be updated manually
636
+ merged_bbox = merge_bboxes(
637
+ [
638
+ c_child.extent.spatial.bboxes[0]
639
+ for c_child in collection.get_children()
640
+ if isinstance(c_child, Collection)
641
+ ]
642
+ )
643
+ collection.extent.spatial.bboxes = [merged_bbox]
644
+ # Add bbox extents from children
645
+ for c_child in collection.get_children():
646
+ if isinstance(c_child, Collection) and merged_bbox != c_child.extent.spatial.bboxes[0]:
647
+ collection.extent.spatial.bboxes.append(c_child.extent.spatial.bboxes[0])
648
+ # set time extent of collection
649
+ individual_datetimes = []
650
+ for c_child in collection.get_children():
651
+ if isinstance(c_child, Collection) and isinstance(
652
+ c_child.extent.temporal.intervals[0], list
653
+ ):
654
+ individual_datetimes.extend(c_child.extent.temporal.intervals[0]) # type: ignore
655
+ time_extent = [min(individual_datetimes), max(individual_datetimes)]
656
+ collection.extent.temporal = TemporalExtent([time_extent])
657
+ else:
658
+ # we can update from items
659
+ collection.update_extent_from_items()
628
660
  collection.summaries = Summaries(
629
661
  {
630
662
  "cities": cities,
@@ -6,11 +6,12 @@ Indicator generator to harvest information from endpoints and generate catalog
6
6
 
7
7
  import os
8
8
  import time
9
+ from datetime import datetime
9
10
  from typing import Any
10
11
 
11
12
  import click
12
13
  from dotenv import load_dotenv
13
- from pystac import Catalog, CatalogType, Collection, Link, Summaries
14
+ from pystac import Catalog, CatalogType, Collection, Link, Summaries, TemporalExtent
14
15
  from pystac.layout import TemplateLayoutStrategy
15
16
  from pystac.validation import validate_all
16
17
  from structlog import get_logger
@@ -39,6 +40,7 @@ from eodash_catalog.utils import (
39
40
  Options,
40
41
  RaisingThread,
41
42
  add_single_item_if_collection_empty,
43
+ iter_len_at_least,
42
44
  merge_bboxes,
43
45
  read_config_file,
44
46
  recursive_save,
@@ -180,8 +182,9 @@ def process_indicator_file(
180
182
  # we assume that collection files can also be loaded directly
181
183
  process_collection_file(catalog_config, file_path, parent_indicator, options)
182
184
  add_collection_information(catalog_config, parent_indicator, indicator_config, True)
185
+ if iter_len_at_least(parent_indicator.get_items(recursive=True), 1):
186
+ parent_indicator.update_extent_from_items()
183
187
  # get shared extent of all of the collections
184
- # we do not want to use update_extent_from_items() because
185
188
  # they might have OverwriteBBox and that would discard it for indicator
186
189
  merged_bbox = merge_bboxes(
187
190
  [
@@ -195,6 +198,17 @@ def process_indicator_file(
195
198
  for c_child in parent_indicator.get_children():
196
199
  if isinstance(c_child, Collection) and merged_bbox != c_child.extent.spatial.bboxes[0]:
197
200
  parent_indicator.extent.spatial.bboxes.append(c_child.extent.spatial.bboxes[0])
201
+ # aggregate all time extents from the child collections and make it a indicator extent
202
+ individual_datetimes: list[datetime] = []
203
+ for c_child in parent_indicator.get_children():
204
+ if isinstance(c_child, Collection) and isinstance(
205
+ c_child.extent.temporal.intervals[0], list
206
+ ):
207
+ individual_datetimes.extend(c_child.extent.temporal.intervals[0]) # type: ignore
208
+ # filter out None
209
+ individual_datetimes = list(filter(lambda x: x is not None, individual_datetimes))
210
+ time_extent = [min(individual_datetimes), max(individual_datetimes)]
211
+ parent_indicator.extent.temporal = TemporalExtent([time_extent])
198
212
  # extract collection information and add it to summary indicator level
199
213
  extract_indicator_info(parent_indicator)
200
214
  add_process_info(parent_indicator, catalog_config, indicator_config)
@@ -276,7 +290,7 @@ def process_collection_file(
276
290
  else:
277
291
  raise ValueError("Type of Resource is not supported")
278
292
  if collection:
279
- add_single_item_if_collection_empty(collection)
293
+ add_single_item_if_collection_empty(endpoint_config, collection)
280
294
  add_projection_info(endpoint_config, collection)
281
295
  add_to_catalog(collection, catalog, endpoint_config, collection_config, disable)
282
296
  else:
@@ -106,8 +106,8 @@ def create_service_link(endpoint_config: dict, catalog_config: dict) -> Link:
106
106
  extra_fields["eox:flatstyle"] = []
107
107
  for flatstyle_config in endpoint_config["Flatstyle"]:
108
108
  flatstyle_obj = {
109
- "Identifier": flatstyle_config.get("Identifier"),
110
- "Url": get_full_url(flatstyle_config.get("Url"), catalog_config),
109
+ "id": flatstyle_config.get("Identifier"),
110
+ "url": get_full_url(flatstyle_config.get("Url"), catalog_config),
111
111
  }
112
112
  extra_fields["eox:flatstyle"].append(flatstyle_obj)
113
113
  else:
@@ -363,18 +363,17 @@ def add_process_info(collection: Collection, catalog_config: dict, collection_co
363
363
  },
364
364
  )
365
365
  collection.add_link(sl)
366
+ has_geodb = any(
367
+ item.get("Name") == "GeoDB" for item in collection_config.get("Resources", [])
368
+ )
366
369
  # adding additional service links
367
- if collection_config["Name"] == "GeoDB" and collection_config.get("Process", {}).get(
368
- "EndPoints"
369
- ):
370
+ if has_geodb and collection_config.get("Process", {}).get("EndPoints"):
370
371
  for endpoint in collection_config["Process"]["EndPoints"]:
371
372
  collection.add_link(create_service_link(endpoint, catalog_config))
372
373
 
373
374
  # for geodb collections now based on locations, we want to make sure
374
375
  # also manually defined processes are added to the collection
375
- if collection_config["Name"] == "GeoDB" and collection_config.get("Process", {}).get(
376
- "VegaDefinition"
377
- ):
376
+ if has_geodb and collection_config.get("Process", {}).get("VegaDefinition"):
378
377
  collection.extra_fields["eodash:vegadefinition"] = get_full_url(
379
378
  collection_config["Process"]["VegaDefinition"], catalog_config
380
379
  )
@@ -335,14 +335,14 @@ class Options:
335
335
  collections: list[str]
336
336
 
337
337
 
338
- def add_single_item_if_collection_empty(collection: Collection) -> None:
338
+ def add_single_item_if_collection_empty(endpoint_config: dict, collection: Collection) -> None:
339
339
  for link in collection.links:
340
340
  if link.rel in [RelType.CHILD, RelType.ITEM]:
341
341
  break
342
342
  else:
343
343
  item = Item(
344
344
  id=str(uuid.uuid4()),
345
- bbox=[-180, -85, 180, 85],
345
+ bbox=[-180.0, -90.0, 180.0, 90.0],
346
346
  properties={},
347
347
  geometry=None,
348
348
  datetime=datetime(1970, 1, 1, 0, 0, 0, tzinfo=pytztimezone("UTC")),
@@ -350,6 +350,8 @@ def add_single_item_if_collection_empty(collection: Collection) -> None:
350
350
  end_datetime=datetime.now(tz=pytztimezone("UTC")),
351
351
  )
352
352
  collection.add_item(item)
353
+ if not endpoint_config.get("OverwriteBBox"):
354
+ collection.update_extent_from_items()
353
355
 
354
356
 
355
357
  def replace_with_env_variables(s: str) -> str:
@@ -105,7 +105,7 @@ def test_collection_no_wms_has_a_single_item(catalog_output_folder):
105
105
  with open(os.path.join(root_collection_path, "collection.json")) as fp:
106
106
  collection_json = json.load(fp)
107
107
  # test that custom bbox is set
108
- assert [-180, -85, 180, 85] in collection_json["extent"]["spatial"]["bbox"]
108
+ assert [-180.0, -90.0, 180.0, 90.0] in collection_json["extent"]["spatial"]["bbox"]
109
109
  # test that time interval is 1970-today
110
110
  assert collection_json["extent"]["temporal"]["interval"][0][0] == start_date
111
111
  assert (