eodash_catalog 0.0.2__py3-none-any.whl → 0.0.4__py3-none-any.whl

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.

@@ -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.0.2"
4
+ __version__ = "0.0.4"
@@ -86,12 +86,26 @@ def process_catalog_file(file_path, options):
86
86
  catalog_type=CatalogType.RELATIVE_PUBLISHED,
87
87
  )
88
88
  for collection in process_collections:
89
- process_collection_file(
90
- config,
91
- "%s/%s.yaml" % (options.collectionsspath, collection),
92
- catalog,
93
- options,
94
- )
89
+ file_path = "%s/%s.yaml" % (options.collectionspath, collection)
90
+ if os.path.isfile(file_path):
91
+ # if collection file exists process it as indicator
92
+ # collection will be added as single collection to indicator
93
+ process_indicator_file(config, file_path, catalog, options)
94
+ else:
95
+ # if not try to see if indicator definition available
96
+ file_path = "%s/%s.yaml" % (options.indicatorspath, collection)
97
+ if os.path.isfile(file_path):
98
+ process_indicator_file(
99
+ config,
100
+ "%s/%s.yaml" % (options.indicatorspath, collection),
101
+ catalog,
102
+ options,
103
+ )
104
+ else:
105
+ print(
106
+ "Warning: neither collection nor indicator found for %s"
107
+ % collection
108
+ )
95
109
 
96
110
  strategy = TemplateLayoutStrategy(item_template="${collection}/${year}")
97
111
  catalog.normalize_hrefs(
@@ -117,6 +131,81 @@ def process_catalog_file(file_path, options):
117
131
  print("Issue validation collection: %s" % e)
118
132
 
119
133
 
134
+ def extract_indicator_info(parent_collection):
135
+ to_extract = [
136
+ "subcode",
137
+ "themes",
138
+ "keywords",
139
+ "satellite",
140
+ "sensor",
141
+ "cities",
142
+ "countries",
143
+ ]
144
+ summaries = {}
145
+ for key in to_extract:
146
+ summaries[key] = set()
147
+
148
+ for collection in parent_collection.get_collections():
149
+ for key in to_extract:
150
+ if key in collection.extra_fields:
151
+ param = collection.extra_fields[key]
152
+ if isinstance(param, list):
153
+ for p in param:
154
+ summaries[key].add(p)
155
+ else:
156
+ summaries[key].add(param)
157
+ # extract also summary information
158
+ if collection.summaries.lists:
159
+ if key in collection.summaries.lists:
160
+ for p in collection.summaries.lists[key]:
161
+ summaries[key].add(p)
162
+
163
+ for key in to_extract:
164
+ # convert all items back to a list
165
+ summaries[key] = list(summaries[key])
166
+ # remove empty ones
167
+ if len(summaries[key]) == 0:
168
+ del summaries[key]
169
+ parent_collection.summaries = Summaries(summaries)
170
+
171
+
172
+ def iter_len_at_least(i, n):
173
+ return sum(1 for _ in zip(range(n), i)) == n
174
+
175
+
176
+ def process_indicator_file(config, file_path, catalog, options):
177
+ with open(file_path) as f:
178
+ print("Processing indicator:", file_path)
179
+ data = yaml.load(f, Loader=SafeLoader)
180
+ parent_indicator, _ = get_or_create_collection(
181
+ catalog, data["Name"], data, config
182
+ )
183
+ if "Collections" in data:
184
+ for collection in data["Collections"]:
185
+ process_collection_file(
186
+ config,
187
+ "%s/%s.yaml" % (options.collectionspath, collection),
188
+ catalog,
189
+ options,
190
+ )
191
+ else:
192
+ # we assume that collection files can also be loaded directly
193
+ process_collection_file(config, file_path, parent_indicator, options)
194
+ add_collection_information(config, parent_indicator, data)
195
+ if iter_len_at_least(parent_indicator.get_items(recursive=True), 1):
196
+ parent_indicator.update_extent_from_items()
197
+ # Add bbox extents from children
198
+ for c_child in parent_indicator.get_children():
199
+ parent_indicator.extent.spatial.bboxes.append(
200
+ c_child.extent.spatial.bboxes[0]
201
+ )
202
+ # extract collection information and add it to summary indicator level
203
+ extract_indicator_info(parent_indicator)
204
+ # add baselayer and overview information to indicator collection
205
+ add_base_overlay_info(parent_indicator, config, data)
206
+ add_to_catalog(parent_indicator, catalog, None, data)
207
+
208
+
120
209
  def process_collection_file(config, file_path, catalog, options):
121
210
  print("Processing collection:", file_path)
122
211
  with open(file_path) as f:
@@ -167,7 +256,8 @@ def process_collection_file(config, file_path, catalog, options):
167
256
  countries.append(sub_coll_def["Country"])
168
257
  process_collection_file(
169
258
  config,
170
- "../collections/%s.yaml" % (sub_coll_def["Collection"]),
259
+ "%s/%s.yaml"
260
+ % (options.collectionspath, sub_coll_def["Collection"]),
171
261
  parent_collection,
172
262
  options,
173
263
  )
@@ -199,7 +289,8 @@ def process_collection_file(config, file_path, catalog, options):
199
289
  )
200
290
  process_collection_file(
201
291
  config,
202
- "../collections/%s.yaml" % (sub_coll_def["Collection"]),
292
+ "%s/%s.yaml"
293
+ % (options.collectionspath, sub_coll_def["Collection"]),
203
294
  tmp_catalog,
204
295
  options,
205
296
  )
@@ -279,6 +370,9 @@ def handle_WMS_endpoint(config, endpoint, data, catalog, wmts=False):
279
370
  properties={},
280
371
  geometry=None,
281
372
  datetime=parser.isoparse(t),
373
+ stac_extensions=[
374
+ "https://stac-extensions.github.io/web-map-links/v1.1.0/schema.json",
375
+ ],
282
376
  )
283
377
  add_visualization_info(item, data, endpoint, time=t)
284
378
  link = collection.add_item(item)
@@ -292,8 +386,6 @@ def handle_WMS_endpoint(config, endpoint, data, catalog, wmts=False):
292
386
  endpoint["OverwriteBBox"],
293
387
  ]
294
388
  )
295
-
296
- add_visualization_info(collection, data, endpoint)
297
389
  add_collection_information(config, collection, data)
298
390
  add_to_catalog(collection, catalog, endpoint, data)
299
391
 
@@ -332,6 +424,9 @@ def handle_SH_WMS_endpoint(config, endpoint, data, catalog):
332
424
  properties={},
333
425
  geometry=None,
334
426
  datetime=parser.isoparse(time),
427
+ stac_extensions=[
428
+ "https://stac-extensions.github.io/web-map-links/v1.1.0/schema.json",
429
+ ],
335
430
  )
336
431
  add_visualization_info(item, data, endpoint, time=time)
337
432
  item_link = collection.add_item(item)
@@ -439,11 +534,6 @@ def get_or_create_collection(catalog, collection_id, data, config, endpoint=None
439
534
  id=collection_id,
440
535
  title=data["Title"],
441
536
  description=description,
442
- stac_extensions=[
443
- "https://stac-extensions.github.io/web-map-links/v1.1.0/schema.json",
444
- "https://stac-extensions.github.io/example-links/v0.0.1/schema.json",
445
- "https://stac-extensions.github.io/scientific/v1.0.0/schema.json",
446
- ],
447
537
  extent=extent,
448
538
  )
449
539
  return (collection, times)
@@ -478,6 +568,8 @@ def add_to_catalog(collection, catalog, endpoint, data):
478
568
  link.extra_fields["title"] = collection.title
479
569
  link.extra_fields["code"] = data["EodashIdentifier"]
480
570
  link.extra_fields["id"] = data["Name"]
571
+ if "Themes" in data:
572
+ link.extra_fields["themes"] = data["Themes"]
481
573
  # Check for summaries and bubble up info
482
574
  if collection.summaries.lists:
483
575
  for sum in collection.summaries.lists:
@@ -504,6 +596,8 @@ def add_extra_fields(stac_object, data):
504
596
  stac_object.extra_fields["agency"] = data["Agency"]
505
597
  if "yAxis" in data:
506
598
  stac_object.extra_fields["yAxis"] = data["yAxis"]
599
+ if "EodashIdentifier" in data:
600
+ stac_object.extra_fields["subcode"] = data["EodashIdentifier"]
507
601
  if "DataSource" in data:
508
602
  if "Spaceborne" in data["DataSource"]:
509
603
  if "Sensor" in data["DataSource"]["Spaceborne"]:
@@ -693,6 +787,61 @@ def handle_STAC_based_endpoint(config, endpoint, data, catalog, options, headers
693
787
  add_to_catalog(root_collection, catalog, endpoint, data)
694
788
 
695
789
 
790
+ def add_base_overlay_info(collection, config, data):
791
+ # check if default base layers defined
792
+ if "default_base_layers" in config:
793
+ with open("%s.yaml" % config["default_base_layers"]) as f:
794
+ base_layers = yaml.load(f, Loader=SafeLoader)
795
+ for layer in base_layers:
796
+ collection.add_link(create_web_map_link(layer, role="baselayer"))
797
+ # check if default overlay layers defined
798
+ if "default_overlay_layers" in config:
799
+ with open("%s.yaml" % config["default_overlay_layers"]) as f:
800
+ overlay_layers = yaml.load(f, Loader=SafeLoader)
801
+ for layer in overlay_layers:
802
+ collection.add_link(create_web_map_link(layer, role="overlay"))
803
+ if "BaseLayers" in data:
804
+ for layer in data["BaseLayers"]:
805
+ collection.add_link(create_web_map_link(layer, role="baselayer"))
806
+ if "OverlayLayers" in data:
807
+ for layer in data["OverlayLayers"]:
808
+ collection.add_link(create_web_map_link(layer, role="overlay"))
809
+ # TODO: possibility to overwrite default base and overlay layers
810
+
811
+
812
+ def create_web_map_link(layer, role):
813
+ extra_fields = {
814
+ "roles": [role],
815
+ "id": layer["id"],
816
+ }
817
+ if "default" in layer and layer["default"]:
818
+ extra_fields["roles"].append("default")
819
+ if "visible" in layer and layer["visible"]:
820
+ extra_fields["roles"].append("visible")
821
+ if "visible" in layer and not layer["visible"]:
822
+ extra_fields["roles"].append("invisible")
823
+
824
+ match layer["protocol"]:
825
+ case "wms":
826
+ # handle wms special config options
827
+ extra_fields["wms:layers"] = layer["layers"]
828
+ if "styles" in layer:
829
+ extra_fields["wms:styles"] = layer["styles"]
830
+ # TODO: handle wms dimensions extra_fields["wms:dimensions"]
831
+ case "wmts":
832
+ extra_fields["wmts:layer"] = layer["layer"]
833
+ # TODO: handle wmts dimensions extra_fields["wmts:dimensions"]
834
+
835
+ wml = Link(
836
+ rel=layer["protocol"],
837
+ target=layer["url"],
838
+ media_type="image/png" if "media_type" not in layer else layer["media_type"],
839
+ title=layer["name"],
840
+ extra_fields=extra_fields,
841
+ )
842
+ return wml
843
+
844
+
696
845
  def add_example_info(stac_object, data, endpoint, config):
697
846
  if "Services" in data:
698
847
  for service in data["Services"]:
@@ -839,6 +988,7 @@ def add_visualization_info(stac_object, data, endpoint, file_url=None, time=None
839
988
  instanceId = endpoint["InstanceId"]
840
989
  extra_fields = {
841
990
  "wms:layers": [endpoint["LayerId"]],
991
+ "role": ["data"],
842
992
  }
843
993
  if time != None:
844
994
  if endpoint["Name"] == "Sentinel Hub WMS":
@@ -861,7 +1011,9 @@ def add_visualization_info(stac_object, data, endpoint, file_url=None, time=None
861
1011
  Link(
862
1012
  rel="wms",
863
1013
  target="https://services.sentinel-hub.com/ogc/wms/%s" % (instanceId),
864
- media_type="text/xml",
1014
+ media_type=(
1015
+ endpoint["MimeType"] if "MimeType" in endpoint else "image/png"
1016
+ ),
865
1017
  title=data["Name"],
866
1018
  extra_fields=extra_fields,
867
1019
  )
@@ -869,7 +1021,10 @@ def add_visualization_info(stac_object, data, endpoint, file_url=None, time=None
869
1021
  # elif resource["Name"] == "GeoDB":
870
1022
  # pass
871
1023
  elif endpoint["Name"] == "WMS":
872
- extra_fields = {"wms:layers": [endpoint["LayerId"]]}
1024
+ extra_fields = {
1025
+ "wms:layers": [endpoint["LayerId"]],
1026
+ "role": ["data"],
1027
+ }
873
1028
  if time != None:
874
1029
  extra_fields["wms:dimensions"] = {
875
1030
  "TIME": time,
@@ -921,7 +1076,10 @@ def add_visualization_info(stac_object, data, endpoint, file_url=None, time=None
921
1076
  )
922
1077
  elif endpoint["Type"] == "WMTSCapabilities":
923
1078
  target_url = "%s" % (endpoint.get("EndPoint"),)
924
- extra_fields = {"wmts:layer": endpoint.get("LayerId")}
1079
+ extra_fields = {
1080
+ "wmts:layer": endpoint.get("LayerId"),
1081
+ "role": ["data"],
1082
+ }
925
1083
  dimensions = {}
926
1084
  if time != None:
927
1085
  dimensions["time"] = time
@@ -974,6 +1132,7 @@ def add_visualization_info(stac_object, data, endpoint, file_url=None, time=None
974
1132
  "matchKey": endpoint["MatchKey"],
975
1133
  "timeKey": endpoint["TimeKey"],
976
1134
  "source": endpoint["Source"],
1135
+ "role": ["data"],
977
1136
  },
978
1137
  )
979
1138
  )
@@ -995,7 +1154,7 @@ def process_STACAPI_Endpoint(
995
1154
  collection, _ = get_or_create_collection(
996
1155
  catalog, endpoint["CollectionId"], data, config, endpoint
997
1156
  )
998
- add_visualization_info(collection, data, endpoint)
1157
+ # add_visualization_info(collection, data, endpoint)
999
1158
 
1000
1159
  api = Client.open(endpoint["EndPoint"], headers=headers)
1001
1160
  if bbox == None:
@@ -1317,7 +1476,8 @@ def add_collection_information(config, collection, data):
1317
1476
  @dataclass
1318
1477
  class Options:
1319
1478
  catalogspath: str
1320
- collectionsspath: str
1479
+ collectionspath: str
1480
+ indicatorspath: str
1321
1481
  outputpath: str
1322
1482
  vd: bool
1323
1483
  ni: bool
@@ -1326,23 +1486,35 @@ class Options:
1326
1486
 
1327
1487
 
1328
1488
  @click.command()
1489
+ @click.option(
1490
+ "--catalog",
1491
+ "-ctl",
1492
+ help="id of catalog configuration file to be used",
1493
+ default=None,
1494
+ )
1329
1495
  @click.option(
1330
1496
  "--catalogspath",
1331
1497
  "-ctp",
1332
1498
  help="path to catalog configuration files",
1333
- default="./catalogs/",
1499
+ default="catalogs",
1334
1500
  )
1335
1501
  @click.option(
1336
- "--collectionsspath",
1502
+ "--collectionspath",
1337
1503
  "-clp",
1338
1504
  help="path to collection configuration files",
1339
- default="./collections/",
1505
+ default="collections",
1506
+ )
1507
+ @click.option(
1508
+ "--indicatorspath",
1509
+ "-inp",
1510
+ help="path to indicator configuration files",
1511
+ default="indicators",
1340
1512
  )
1341
1513
  @click.option(
1342
1514
  "--outputpath",
1343
1515
  "-o",
1344
1516
  help="path where the generated catalogs will be saved",
1345
- default="./build/",
1517
+ default="build",
1346
1518
  )
1347
1519
  @click.option(
1348
1520
  "-vd",
@@ -1362,14 +1534,23 @@ class Options:
1362
1534
  nargs=-1,
1363
1535
  )
1364
1536
  def process_catalogs(
1365
- catalogspath, collectionsspath, outputpath, vd, ni, tn, collections
1537
+ catalog,
1538
+ catalogspath,
1539
+ collectionspath,
1540
+ indicatorspath,
1541
+ outputpath,
1542
+ vd,
1543
+ ni,
1544
+ tn,
1545
+ collections,
1366
1546
  ):
1367
1547
  """STAC generator and harvester:
1368
1548
  This library goes over configured endpoints extracting as much information
1369
1549
  as possible and generating a STAC catalog with the information"""
1370
1550
  options = Options(
1371
1551
  catalogspath=catalogspath,
1372
- collectionsspath=collectionsspath,
1552
+ collectionspath=collectionspath,
1553
+ indicatorspath=indicatorspath,
1373
1554
  outputpath=outputpath,
1374
1555
  vd=vd,
1375
1556
  ni=ni,
@@ -1380,9 +1561,12 @@ def process_catalogs(
1380
1561
  for file_name in os.listdir(catalogspath):
1381
1562
  file_path = os.path.join(catalogspath, file_name)
1382
1563
  if os.path.isfile(file_path):
1383
- tasks.append(
1384
- RaisingThread(target=process_catalog_file, args=(file_path, options))
1385
- )
1564
+ if catalog == None or os.path.splitext(file_name)[0] == catalog:
1565
+ tasks.append(
1566
+ RaisingThread(
1567
+ target=process_catalog_file, args=(file_path, options)
1568
+ )
1569
+ )
1386
1570
  tasks[-1].start()
1387
1571
  for task in tasks:
1388
1572
  task.join()
eodash_catalog/utils.py CHANGED
@@ -27,12 +27,7 @@ ISO8601_PERIOD_REGEX = re.compile(
27
27
 
28
28
  def create_geojson_point(lon, lat):
29
29
  point = {"type": "Point", "coordinates": [lon, lat]}
30
-
31
- feature = {"type": "Feature", "geometry": point, "properties": {}}
32
-
33
- feature_collection = {"type": "FeatureCollection", "features": [feature]}
34
-
35
- return feature_collection
30
+ return {"type": "Feature", "geometry": point, "properties": {}}
36
31
 
37
32
 
38
33
  def retrieveExtentFromWMSWMTS(capabilties_url, layer, wmts=False):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: eodash_catalog
3
- Version: 0.0.2
3
+ Version: 0.0.4
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
@@ -0,0 +1,11 @@
1
+ eodash_catalog/__about__.py,sha256=hgn7jZAxDHPEyGIDZxshBV5JuJm5npM7MNx5e6f2ljk,137
2
+ eodash_catalog/__init__.py,sha256=_W_9emPYf6FUqc0P8L2SmADx6hGSd7PlQV3yRmCk5uM,115
3
+ eodash_catalog/duration.py,sha256=6rxALD9MZS6rTE1AZgvjrABr7zwg8S-kLc_w9BltvY0,11007
4
+ eodash_catalog/generate_indicators.py,sha256=VblUlZVhlBdGr5YRVhyC177QuOD2GskyxW71ZtON0gY,60140
5
+ eodash_catalog/sh_endpoint.py,sha256=KyZGmVrjZOCIuJizmYSy8VSWrfqqn2r-Ggh_8Q-s2vI,581
6
+ eodash_catalog/utils.py,sha256=NbwqHE5Qhd3Fke_fbl3HY803qSKJJKP1atTNrGPO7KY,6097
7
+ eodash_catalog-0.0.4.dist-info/METADATA,sha256=HzWcdbs4KfhrNr7n6-5rPupFjJT4t6ENcKXjz2As8Oc,2156
8
+ eodash_catalog-0.0.4.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
9
+ eodash_catalog-0.0.4.dist-info/entry_points.txt,sha256=kuUQrDG1PtYd8kPjf5XM6H_NtQd9Ozwl0jjiGtAvZSM,87
10
+ eodash_catalog-0.0.4.dist-info/licenses/LICENSE.txt,sha256=oJCW5zQxnFD-J0hGz6Zh5Lkpdk1oAndmWhseTmV224E,1107
11
+ eodash_catalog-0.0.4.dist-info/RECORD,,
@@ -1,11 +0,0 @@
1
- eodash_catalog/__about__.py,sha256=cTzwMF0PAs7cIF-UCkp_XTlsxj_9LLhKjZkxXPGGSXY,137
2
- eodash_catalog/__init__.py,sha256=_W_9emPYf6FUqc0P8L2SmADx6hGSd7PlQV3yRmCk5uM,115
3
- eodash_catalog/duration.py,sha256=6rxALD9MZS6rTE1AZgvjrABr7zwg8S-kLc_w9BltvY0,11007
4
- eodash_catalog/generate_indicators.py,sha256=gTh2rRKAL1XkxMRdXoFKVLF-3InAW27ziu6bDn6a5DM,53345
5
- eodash_catalog/sh_endpoint.py,sha256=KyZGmVrjZOCIuJizmYSy8VSWrfqqn2r-Ggh_8Q-s2vI,581
6
- eodash_catalog/utils.py,sha256=tEzX5Nsy9yLpO0m9KWeMx0zRhEhCKStUq5Afche562w,6211
7
- eodash_catalog-0.0.2.dist-info/METADATA,sha256=3HXIEktGA9kyFzgdYWDVlbXuj4EZkfFM1_xLWTQ4H0s,2156
8
- eodash_catalog-0.0.2.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
9
- eodash_catalog-0.0.2.dist-info/entry_points.txt,sha256=kuUQrDG1PtYd8kPjf5XM6H_NtQd9Ozwl0jjiGtAvZSM,87
10
- eodash_catalog-0.0.2.dist-info/licenses/LICENSE.txt,sha256=oJCW5zQxnFD-J0hGz6Zh5Lkpdk1oAndmWhseTmV224E,1107
11
- eodash_catalog-0.0.2.dist-info/RECORD,,