dafab-client 2.2.4__tar.gz → 2.2.6__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.
Files changed (106) hide show
  1. {dafab_client-2.2.4 → dafab_client-2.2.6}/PKG-INFO +1 -1
  2. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/overridden_rucio_client.py +2 -2
  3. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/rse/translation.py +1 -1
  4. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/example_notebooks/dafab_simple_user_workflows.ipynb +100 -46
  5. dafab_client-2.2.6/dafab_client/example_notebooks/dafab_simple_user_workflows.py +322 -0
  6. dafab_client-2.2.6/dafab_client/helpers/file_management/Insertion/upload_file_of_scope_name.py +72 -0
  7. dafab_client-2.2.6/dafab_client/helpers/file_management/Retrieval/download_file_of_scope_name.py +82 -0
  8. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/file_management/Workflows/manage_derived_assets.py +164 -78
  9. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client.egg-info/PKG-INFO +1 -1
  10. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client.egg-info/SOURCES.txt +1 -0
  11. {dafab_client-2.2.4 → dafab_client-2.2.6}/pyproject.toml +1 -1
  12. dafab_client-2.2.4/dafab_client/helpers/file_management/Insertion/upload_file_of_scope_name.py +0 -142
  13. dafab_client-2.2.4/dafab_client/helpers/file_management/Retrieval/download_file_of_scope_name.py +0 -150
  14. {dafab_client-2.2.4 → dafab_client-2.2.6}/MANIFEST.in +0 -0
  15. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/__init__.py +0 -0
  16. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/__init__.py +0 -0
  17. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/client/__init__.py +0 -0
  18. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/client/accountclient.py +0 -0
  19. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/client/baseclient.py +0 -0
  20. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/client/client.py +0 -0
  21. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/client/credentialclient.py +0 -0
  22. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/client/didclient.py +0 -0
  23. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/client/downloadclient.py +0 -0
  24. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/client/pingclient.py +0 -0
  25. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/client/replicaclient.py +0 -0
  26. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/client/rseclient.py +0 -0
  27. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/client/scopeclient.py +0 -0
  28. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/client/uploadclient.py +0 -0
  29. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/common/cache.py +0 -0
  30. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/common/checksum.py +0 -0
  31. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/common/client.py +0 -0
  32. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/common/config.py +0 -0
  33. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/common/constants.py +0 -0
  34. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/common/constraints.py +0 -0
  35. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/common/didtype.py +0 -0
  36. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/common/exception.py +0 -0
  37. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/common/extra.py +0 -0
  38. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/common/filter.py +0 -0
  39. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/common/logging.py +0 -0
  40. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/common/pcache.py +0 -0
  41. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/common/plugins.py +0 -0
  42. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/common/types.py +0 -0
  43. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/common/utils.py +0 -0
  44. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/core/rse.py +0 -0
  45. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/dafab_lib.py +0 -0
  46. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/global_utils.py +0 -0
  47. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/rse/__init__.py +0 -0
  48. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/rse/protocols/__init__.py +0 -0
  49. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/rse/protocols/gfal.py +0 -0
  50. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/rse/protocols/protocol.py +0 -0
  51. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/rse/protocols/webdav.py +0 -0
  52. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/rse/rsemanager.py +0 -0
  53. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/secrets/user_dafab/config +0 -0
  54. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/secrets/user_dafab/rucio_ca_bundle.pem +0 -0
  55. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/_rucio/version.py +0 -0
  56. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/example_notebooks/dafab_dasi_workflows.ipynb +0 -0
  57. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/example_notebooks/dafab_operator_workflows.ipynb +0 -0
  58. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/example_notebooks/dafab_skim_workflows.ipynb +0 -0
  59. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/System/check_available_accounts.py +0 -0
  60. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/System/check_storage.py +0 -0
  61. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/__init__.py +0 -0
  62. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/check_server_health.py +0 -0
  63. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/container_management/ensure_container.py +0 -0
  64. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/container_management/list_containers.py +0 -0
  65. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/dataset_management/ensure_dataset.py +0 -0
  66. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/dataset_management/list_datasets.py +0 -0
  67. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/dataset_management/scope_management.py +0 -0
  68. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/db_bootstrap/account_manager.py +0 -0
  69. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/demo_imports.py +0 -0
  70. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/did_management/operations.py +0 -0
  71. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/file_management/Deletion/delete_file_of_scope_name.py +0 -0
  72. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/file_management/Deletion/delete_replica_of_scope_name.py +0 -0
  73. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/file_management/list_files.py +0 -0
  74. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/filtering/filter_by_bbox.py +0 -0
  75. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/filtering/filter_by_bbox_and_timerange.py +0 -0
  76. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/filtering/filter_by_enhanced_filter.py +0 -0
  77. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/filtering/filter_by_relationships.py +0 -0
  78. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/filtering/filter_by_timerange.py +0 -0
  79. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/filtering/mapper.py +0 -0
  80. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/metadata_management/Insertion/set_metadata.py +0 -0
  81. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/metadata_management/Operations/common.py +0 -0
  82. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/metadata_management/Operations/delete_metadata_for_did.py +0 -0
  83. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/metadata_management/Operations/insert_metadata_for_did.py +0 -0
  84. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/metadata_management/Operations/update_metadata_for_did.py +0 -0
  85. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/metadata_management/Operations/upsert_metadata_for_did.py +0 -0
  86. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/metadata_management/Patch/patch_metadata_for_dids.py +0 -0
  87. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/metadata_management/Preflight/validate_derived_item_file.py +0 -0
  88. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/metadata_management/Preflight/validate_facet_value_catalog_file.py +0 -0
  89. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/metadata_management/Preflight/validate_original_item_file.py +0 -0
  90. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/metadata_management/Retrieval/Complete/get_metadata_for_scope_name.py +0 -0
  91. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/metadata_management/Retrieval/Partial/get_single_metadata_for_scope_name.py +0 -0
  92. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/metadata_management/Workflows/sync_spatial_bbox_integrity.py +0 -0
  93. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/metadata_management/Workflows/update_derived_item.py +0 -0
  94. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/metadata_management/Workflows/update_original_item.py +0 -0
  95. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/metadata_management/document_api.py +0 -0
  96. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/resources/schemas/Schema_Copernicus_with_dafab.json +0 -0
  97. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/resources/schemas/Schema_DaFab_Facet_Value_Catalog.json +0 -0
  98. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/resources/schemas/dafab-smart_agriculture-item.schema.json +0 -0
  99. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/resources/schemas/dafab-water_analysis-item.schema.json +0 -0
  100. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/resources/schemas/dasi-original-item.schema.json +0 -0
  101. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client/helpers/runtime_paths.py +0 -0
  102. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client.egg-info/dependency_links.txt +0 -0
  103. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client.egg-info/requires.txt +0 -0
  104. {dafab_client-2.2.4 → dafab_client-2.2.6}/dafab_client.egg-info/top_level.txt +0 -0
  105. {dafab_client-2.2.4 → dafab_client-2.2.6}/readme.md +0 -0
  106. {dafab_client-2.2.4 → dafab_client-2.2.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dafab_client
3
- Version: 2.2.4
3
+ Version: 2.2.6
4
4
  Summary: DaFab helper client built on top of Rucio client modules.
5
5
  Author: DaFab
6
6
  License-Expression: Apache-2.0
@@ -63,10 +63,10 @@ class DevDownloadClient(DownloadClient):
63
63
 
64
64
  class DevUploadClient(UploadClient):
65
65
 
66
- def upload_file(self, fpath, pname, scope: str, rse: str):
66
+ def upload_file(self, fpath, pname, scope: str, rse: str, did_name: str | None = None):
67
67
 
68
68
  LOG.info(f"Uploading file for dataset_name: `{pname}`")
69
- filename = os.path.basename(fpath)
69
+ filename = did_name or os.path.basename(fpath)
70
70
 
71
71
  if rse == 'MELUXINA_S3':
72
72
  # Prepare the file dictionary for upload
@@ -197,7 +197,7 @@ class RSEDeterministicTranslation(PolicyPackageAlgorithms):
197
197
  del rse
198
198
  del rse_attrs
199
199
  del protocol_attrs
200
- hstr = hashlib.md5(f'demo:{name}'.encode('utf-8')).hexdigest()
200
+ hstr = hashlib.md5(f'{scope}:{name}'.encode('utf-8')).hexdigest()
201
201
  if scope.startswith('user') or scope.startswith('group'):
202
202
  scope = scope.replace('.', '/')
203
203
  return '%s/%s/%s/%s' % (scope, hstr[0:2], hstr[2:4], name)
@@ -56,46 +56,89 @@
56
56
  "cell_type": "code",
57
57
  "metadata": {},
58
58
  "source": [
59
- "# STAC scope for the DaFab catalog (e.g., \"dafab\" for production, \"demo\" for development).\n",
59
+ "# STAC scope for the DaFab catalog.\n",
60
60
  "STAC_SCOPE = \"dafab\"\n",
61
61
  "\n",
62
- "# Available collection in DaFab's unified-catalog: sentinel_2_l2a, water_analysis, smart_agriculture\n",
63
62
  "COLLECTION_ID = \"water_analysis\"\n",
64
- "\n",
65
- "# Top facet catalog ID in DaFab's unified-catalog: \"agriculture_season\", \"water_basin\", \"water_anomaly\"\n",
66
63
  "TOP_FACET_CATALOG_ID = \"water_basin\"\n",
67
- "\n",
68
- "# Facet value catalog ID in DaFab's unified-catalog: \"agriculture_season_winter\", \"agriculture_season_spring\", \"agriculture_season_summer\", \"agriculture_season_autumn\", \"water_anomaly_flood\", \"water_anomaly_drought\", \"water_anomaly_normal\", \"water_basin_ganges\".\n",
69
64
  "FACET_VALUE_CATALOG_ID = \"water_basin_ganges\"\n",
70
65
  "\n",
71
- "# Original item ID in DaFab's unified-catalog (e.g., \"S2A_45RYJ_20221205_0_L2A\").\n",
66
+ "# Source/original and derived pair used by relationship and metadata examples.\n",
72
67
  "ORIGINAL_ITEM_ID = \"S2A_45RYJ_20221205_0_L2A\"\n",
68
+ "DERIVED_ITEM_ID = \"S2A_31TEG_20220226_0_L2A_smart_agriculture_120\"\n",
69
+ "DERIVED_ASSET_KEY = \"dafab-field-boundaries\"\n",
73
70
  "\n",
74
- "# Derived item ID in DaFab's unified-catalog (e.g., \"S2A_45RYJ_20221205_0_L2A_water_analysis_100\", \"S2A_45RYJ_20221205_0_L2A_smart_agriculture_100\", ...).\n",
75
- "DERIVED_ITEM_ID = \"S2A_31TEG_20220226_0_L2A_smart_agriculture_120\" # \"S2A_45RYJ_20221205_0_L2A_water_analysis_100\" # \"S2A_31TEG_20220226_0_L2A_smart_agriculture_120\"\n",
71
+ "# Staged original Sentinel-2 asset published through Rucio.\n",
72
+ "STAGED_ORIGINAL_ITEM_ID = \"S2C_MSIL2A_20260218T105111_N0512_R051_T30TYN_20260218T145711\"\n",
73
+ "STAGED_ORIGINAL_ASSET_KEY = \"B11_20m\"\n",
76
74
  "\n",
77
- "# Asset key to resolve under `assets` of the selected derived item.\n",
78
- "DERIVED_ASSET_KEY = \"dafab-field-boundaries\"\n",
75
+ "# Ancillary raster examples stored in their own STAC scopes.\n",
76
+ "HAND_SCOPE = \"hand\"\n",
77
+ "HAND_ITEM_ID = \"Copernicus_DSM_COG_10_N00_00_E006_00_HAND\"\n",
78
+ "HAND_ASSET_KEY = \"data\"\n",
79
+ "\n",
80
+ "WORLDCOVER_SCOPE = \"worldcover\"\n",
81
+ "WORLDCOVER_ITEM_ID = \"ESA_WorldCover_10m_2021_v200_N51E003_Map\"\n",
82
+ "WORLDCOVER_ASSET_KEY = \"Map\"\n",
79
83
  "\n",
80
- "# Local download directory used by the asset download examples below.\n",
81
84
  "ASSET_DOWNLOAD_DIR = \"demo-data/downloads\"\n",
82
85
  "\n",
83
- "# Start datetime (inclusive) used by Q1/Q3 filter examples.\n",
84
- "FILTER_START_DATETIME = \"2020-01-01T00:00:00Z\"\n",
86
+ "ASSET_EXAMPLES = [\n",
87
+ " {\n",
88
+ " \"label\": \"original-sentinel-2\",\n",
89
+ " \"scope\": STAC_SCOPE,\n",
90
+ " \"item_id\": STAGED_ORIGINAL_ITEM_ID,\n",
91
+ " \"asset_key\": STAGED_ORIGINAL_ASSET_KEY,\n",
92
+ " \"downloadable\": True,\n",
93
+ " },\n",
94
+ " {\n",
95
+ " \"label\": \"derived-dafab\",\n",
96
+ " \"scope\": STAC_SCOPE,\n",
97
+ " \"item_id\": DERIVED_ITEM_ID,\n",
98
+ " \"asset_key\": DERIVED_ASSET_KEY,\n",
99
+ " \"downloadable\": False,\n",
100
+ " },\n",
101
+ " {\n",
102
+ " \"label\": \"hand\",\n",
103
+ " \"scope\": HAND_SCOPE,\n",
104
+ " \"item_id\": HAND_ITEM_ID,\n",
105
+ " \"asset_key\": HAND_ASSET_KEY,\n",
106
+ " \"downloadable\": True,\n",
107
+ " },\n",
108
+ " {\n",
109
+ " \"label\": \"worldcover\",\n",
110
+ " \"scope\": WORLDCOVER_SCOPE,\n",
111
+ " \"item_id\": WORLDCOVER_ITEM_ID,\n",
112
+ " \"asset_key\": WORLDCOVER_ASSET_KEY,\n",
113
+ " \"downloadable\": True,\n",
114
+ " },\n",
115
+ "]\n",
85
116
  "\n",
86
- "# End datetime (inclusive) used by Q1/Q3 filter examples.\n",
87
- "FILTER_END_DATETIME = \"2020-12-31T23:59:59Z\"\n",
117
+ "DOWNLOADABLE_ASSET_EXAMPLES = [example for example in ASSET_EXAMPLES if example[\"downloadable\"]]\n",
88
118
  "\n",
89
- "# Bounding box [min_long, min_lat, max_long, max_lat] used by Q2/Q3 filter examples.\n",
119
+ "FILTER_START_DATETIME = \"2020-01-01T00:00:00Z\"\n",
120
+ "FILTER_END_DATETIME = \"2020-12-31T23:59:59Z\"\n",
90
121
  "FILTER_BBOX = [-0.6, 19.7, 96.6, 54.2]\n",
91
- "\n",
92
- "# Minimum number of fields used by the Q4 nested metadata filter example.\n",
93
- "SMART_AGRICULTURE_MIN_FIELDS = 100000"
122
+ "SMART_AGRICULTURE_MIN_FIELDS = 100000\n"
94
123
  ],
95
124
  "id": "c90eef0876e76811",
96
125
  "outputs": [],
97
126
  "execution_count": null
98
127
  },
128
+ {
129
+ "cell_type": "markdown",
130
+ "metadata": {},
131
+ "source": [
132
+ "### 1.1 Asset Example Classes\n",
133
+ "| Example | Scope | Item | Asset key | Best use |\n",
134
+ "|---|---|---|---|---|\n",
135
+ "| Original Sentinel-2 | `dafab` | `STAGED_ORIGINAL_ITEM_ID` | `STAGED_ORIGINAL_ASSET_KEY` | Original DASI product assets published through Rucio. |\n",
136
+ "| Derived DaFab | `dafab` | `DERIVED_ITEM_ID` | `DERIVED_ASSET_KEY` | Derived item relationships and metadata. |\n",
137
+ "| HAND | `hand` | `HAND_ITEM_ID` | `HAND_ASSET_KEY` | Terrain ancillary raster. |\n",
138
+ "| WorldCover | `worldcover` | `WORLDCOVER_ITEM_ID` | `WORLDCOVER_ASSET_KEY` | Land-cover ancillary raster. |\n"
139
+ ],
140
+ "id": "asset-example-classes"
141
+ },
99
142
  {
100
143
  "cell_type": "markdown",
101
144
  "metadata": {},
@@ -699,9 +742,9 @@
699
742
  "metadata": {},
700
743
  "source": [
701
744
  "print(dc.extract_metadata_value(\n",
702
- " value_path=\"/assets/dafab-field-boundaries/href\",\n",
745
+ " value_path=f\"/assets/{DERIVED_ASSET_KEY}/href\",\n",
703
746
  " pname=DERIVED_ITEM_ID,\n",
704
- "))"
747
+ "))\n"
705
748
  ],
706
749
  "id": "393130cb6c97ad38",
707
750
  "outputs": [],
@@ -724,14 +767,14 @@
724
767
  " \"/id\",\n",
725
768
  " \"/collection\",\n",
726
769
  " \"/properties/datetime\",\n",
727
- " \"/assets/dafab-field-boundaries/href\",\n",
770
+ " f\"/assets/{DERIVED_ASSET_KEY}/href\",\n",
728
771
  "]\n",
729
772
  "derived_item_partial_subset = dc.get_bulk_metadata(\n",
730
773
  " DERIVED_ITEM_ID,\n",
731
774
  " scope=STAC_SCOPE,\n",
732
775
  " paths=PARTIAL_METADATA_PATHS,\n",
733
776
  ")\n",
734
- "print(dc.as_json(derived_item_partial_subset))"
777
+ "print(dc.as_json(derived_item_partial_subset))\n"
735
778
  ],
736
779
  "id": "1849a6c900bcd821",
737
780
  "outputs": [],
@@ -823,9 +866,8 @@
823
866
  "cell_type": "markdown",
824
867
  "metadata": {},
825
868
  "source": [
826
- "## 25. Download Asset Using Stable Link\n",
827
- "- URL-first mode: use a known stable DaFab asset URL and download directly from it.\n",
828
- "- Best when the caller already has the stable link (for example from search results, copied links, or external clients).\n"
869
+ "## 25. Download Original Asset Using Stable Link\n",
870
+ "URL-first mode: build the stable resolver URL for a staged original asset, then download directly from it.\n"
829
871
  ],
830
872
  "id": "1ed656e29fa0f2f4"
831
873
  },
@@ -833,10 +875,10 @@
833
875
  "cell_type": "code",
834
876
  "metadata": {},
835
877
  "source": [
836
- "# Get automatically the download href based on a derived id and its asset destination (e.g. https://dafab.cern.ch/stac/assets/dafab/items/S2A_30TYN_20200311_1_L2A_smart_agriculture_120/dafab-field-boundaries)\n",
837
878
  "stable_asset_href = dc.build_stable_asset_href(\n",
838
- " item_id=DERIVED_ITEM_ID,\n",
839
- " asset_key=DERIVED_ASSET_KEY,\n",
879
+ " item_id=STAGED_ORIGINAL_ITEM_ID,\n",
880
+ " asset_key=STAGED_ORIGINAL_ASSET_KEY,\n",
881
+ " scope=STAC_SCOPE,\n",
840
882
  ")\n",
841
883
  "\n",
842
884
  "stable_asset_download = dc.download_asset_from_stable_href(\n",
@@ -844,7 +886,7 @@
844
886
  " destination_dir=ASSET_DOWNLOAD_DIR,\n",
845
887
  " overwrite=True,\n",
846
888
  ")\n",
847
- "print(dc.as_json(stable_asset_download))"
889
+ "print(dc.as_json(stable_asset_download))\n"
848
890
  ],
849
891
  "id": "28500ca4defac451",
850
892
  "outputs": [],
@@ -854,9 +896,8 @@
854
896
  "cell_type": "markdown",
855
897
  "metadata": {},
856
898
  "source": [
857
- "## 26. Download Asset By Item And Asset Key\n",
858
- "- Metadata-first mode: provide item id + asset key, resolve `assets.<asset_key>` from metadata, then download.\n",
859
- "- Best when the caller does not already have the stable URL and wants lookup + download in one helper call.\n"
899
+ "## 26. Download Original Asset By Item And Asset Key\n",
900
+ "Metadata-first mode: provide item id + asset key, resolve the asset entry, then download.\n"
860
901
  ],
861
902
  "id": "ba01c4c5f0c41828"
862
903
  },
@@ -865,12 +906,13 @@
865
906
  "metadata": {},
866
907
  "source": [
867
908
  "item_asset_download = dc.download_item_asset(\n",
868
- " item_id=DERIVED_ITEM_ID,\n",
869
- " asset_key=DERIVED_ASSET_KEY,\n",
909
+ " item_id=STAGED_ORIGINAL_ITEM_ID,\n",
910
+ " asset_key=STAGED_ORIGINAL_ASSET_KEY,\n",
911
+ " scope=STAC_SCOPE,\n",
870
912
  " destination_dir=ASSET_DOWNLOAD_DIR,\n",
871
913
  " overwrite=True,\n",
872
914
  ")\n",
873
- "print(dc.as_json(item_asset_download))"
915
+ "print(dc.as_json(item_asset_download))\n"
874
916
  ],
875
917
  "id": "c93935596c2f03b6",
876
918
  "outputs": [],
@@ -880,8 +922,8 @@
880
922
  "cell_type": "markdown",
881
923
  "metadata": {},
882
924
  "source": [
883
- "## 27. Download All Assets Of a Derived Item\n",
884
- "Download all assets for a derived item in one call. The helper guards against original-item IDs and returns a per-asset status summary.\n"
925
+ "## 27. Inspect Downloadable Asset Entries By Example Class\n",
926
+ "This reports the selected asset entry for each downloadable reference class without downloading file content.\n"
885
927
  ],
886
928
  "id": "ebde8e85d32eae9d"
887
929
  },
@@ -889,13 +931,25 @@
889
931
  "cell_type": "code",
890
932
  "metadata": {},
891
933
  "source": [
892
- "all_derived_assets_download = dc.download_all_derived_item_assets(\n",
893
- " item_id=DERIVED_ITEM_ID,\n",
894
- " scope=STAC_SCOPE,\n",
895
- " destination_dir=ASSET_DOWNLOAD_DIR,\n",
896
- " overwrite=True,\n",
897
- ")\n",
898
- "print(dc.as_json(all_derived_assets_download))"
934
+ "asset_entry_reports = {}\n",
935
+ "for example in DOWNLOADABLE_ASSET_EXAMPLES:\n",
936
+ " report = dc.list_item_asset_entries(\n",
937
+ " example[\"item_id\"],\n",
938
+ " stac_namespace=example[\"scope\"],\n",
939
+ " check_storage=True,\n",
940
+ " )\n",
941
+ " selected = next(\n",
942
+ " (row for row in report.get(\"asset_entries\", []) if row.get(\"asset_key\") == example[\"asset_key\"]),\n",
943
+ " None,\n",
944
+ " )\n",
945
+ " asset_entry_reports[example[\"label\"]] = {\n",
946
+ " \"scope\": example[\"scope\"],\n",
947
+ " \"item_id\": example[\"item_id\"],\n",
948
+ " \"selected_asset\": selected,\n",
949
+ " \"metadata_asset_count\": report.get(\"metadata_asset_count\"),\n",
950
+ " \"attached_asset_count\": report.get(\"attached_asset_count\"),\n",
951
+ " }\n",
952
+ "print(dc.as_json(asset_entry_reports))\n"
899
953
  ],
900
954
  "id": "6756ebe6999c1925",
901
955
  "outputs": [],
@@ -0,0 +1,322 @@
1
+ import dafab_client as dc
2
+
3
+ # STAC scope for the DaFab catalog.
4
+ STAC_SCOPE = "dafab"
5
+
6
+ COLLECTION_ID = "water_analysis"
7
+ TOP_FACET_CATALOG_ID = "water_basin"
8
+ FACET_VALUE_CATALOG_ID = "water_basin_ganges"
9
+
10
+ # Source/original and derived pair used by relationship and metadata examples.
11
+ ORIGINAL_ITEM_ID = "S2A_45RYJ_20221205_0_L2A"
12
+ DERIVED_ITEM_ID = "S2A_31TEG_20220226_0_L2A_smart_agriculture_120"
13
+ DERIVED_ASSET_KEY = "dafab-field-boundaries"
14
+
15
+ # Staged original Sentinel-2 asset published through Rucio.
16
+ STAGED_ORIGINAL_ITEM_ID = "S2C_MSIL2A_20260218T105111_N0512_R051_T30TYN_20260218T145711"
17
+ STAGED_ORIGINAL_ASSET_KEY = "B11_20m"
18
+
19
+ # Ancillary raster examples stored in their own STAC scopes.
20
+ HAND_SCOPE = "hand"
21
+ HAND_ITEM_ID = "Copernicus_DSM_COG_10_N00_00_E006_00_HAND"
22
+ HAND_ASSET_KEY = "data"
23
+
24
+ WORLDCOVER_SCOPE = "worldcover"
25
+ WORLDCOVER_ITEM_ID = "ESA_WorldCover_10m_2021_v200_N51E003_Map"
26
+ WORLDCOVER_ASSET_KEY = "Map"
27
+
28
+ ASSET_DOWNLOAD_DIR = "demo-data/downloads"
29
+
30
+ ASSET_EXAMPLES = [
31
+ {
32
+ "label": "original-sentinel-2",
33
+ "scope": STAC_SCOPE,
34
+ "item_id": STAGED_ORIGINAL_ITEM_ID,
35
+ "asset_key": STAGED_ORIGINAL_ASSET_KEY,
36
+ "downloadable": True,
37
+ },
38
+ {
39
+ "label": "derived-dafab",
40
+ "scope": STAC_SCOPE,
41
+ "item_id": DERIVED_ITEM_ID,
42
+ "asset_key": DERIVED_ASSET_KEY,
43
+ "downloadable": False,
44
+ },
45
+ {
46
+ "label": "hand",
47
+ "scope": HAND_SCOPE,
48
+ "item_id": HAND_ITEM_ID,
49
+ "asset_key": HAND_ASSET_KEY,
50
+ "downloadable": True,
51
+ },
52
+ {
53
+ "label": "worldcover",
54
+ "scope": WORLDCOVER_SCOPE,
55
+ "item_id": WORLDCOVER_ITEM_ID,
56
+ "asset_key": WORLDCOVER_ASSET_KEY,
57
+ "downloadable": True,
58
+ },
59
+ ]
60
+
61
+ DOWNLOADABLE_ASSET_EXAMPLES = [example for example in ASSET_EXAMPLES if example["downloadable"]]
62
+
63
+ FILTER_START_DATETIME = "2020-01-01T00:00:00Z"
64
+ FILTER_END_DATETIME = "2020-12-31T23:59:59Z"
65
+ FILTER_BBOX = [-0.6, 19.7, 96.6, 54.2]
66
+ SMART_AGRICULTURE_MIN_FIELDS = 100000
67
+
68
+ dc.ping()
69
+
70
+ dc.whoami()
71
+
72
+ dc.list_stac_scopes()
73
+
74
+ dc.list_catalogs_and_collections()
75
+ # If you need structured records for downstream processing, use dc.get_catalogs_and_collections() instead.
76
+ print(f"Structured rows available via dc.get_catalogs_and_collections(): {len(dc.get_catalogs_and_collections())}")
77
+
78
+ # Enhanced filter payload for STAC records whose metadata type is "Collection".
79
+ COLLECTION_TYPE_FILTER = {
80
+ "filter": {
81
+ "type": "comparison",
82
+ "comparator": "equals",
83
+ "path": ["type"],
84
+ "value": "Collection",
85
+ "valueType": "string",
86
+ }
87
+ }
88
+
89
+ collection_type_item_ids = dc.get_items_by_enhanced_filter(COLLECTION_TYPE_FILTER, return_mode="ids")
90
+ print(collection_type_item_ids)
91
+
92
+ # Enhanced filter payload for STAC records whose metadata type is "Catalog".
93
+ CATALOG_TYPE_FILTER = {
94
+ "filter": {
95
+ "type": "comparison",
96
+ "comparator": "equals",
97
+ "path": ["type"],
98
+ "value": "Catalog",
99
+ "valueType": "string",
100
+ }
101
+ }
102
+
103
+ catalog_type_item_ids = dc.get_items_by_enhanced_filter(CATALOG_TYPE_FILTER, return_mode="ids")
104
+ print(catalog_type_item_ids)
105
+
106
+ item_rows = dc.get_items()
107
+ print([item["name"] for item in item_rows])
108
+ print(f"Structured rows available via dc.get_items(): {len(item_rows)}")
109
+
110
+ collection_item_ids = dc.get_item_ids_by_collection_field(COLLECTION_ID)
111
+ print(f"Collection: {COLLECTION_ID}")
112
+ print(collection_item_ids)
113
+
114
+ top_facet_item_ids = dc.get_item_ids_by_top_facet_catalog(TOP_FACET_CATALOG_ID)
115
+
116
+ print(f"Top facet catalog: {TOP_FACET_CATALOG_ID}")
117
+ print(top_facet_item_ids)
118
+
119
+ facet_value_item_ids = dc.get_item_ids_by_facet_value_catalog(FACET_VALUE_CATALOG_ID)
120
+
121
+ print(f"Facet value catalog: {FACET_VALUE_CATALOG_ID}")
122
+ print(facet_value_item_ids)
123
+
124
+ related_item_ids = dc.get_related_item_ids_from_original_item(ORIGINAL_ITEM_ID)
125
+
126
+ print(f"Original item: {ORIGINAL_ITEM_ID}")
127
+ print(related_item_ids)
128
+
129
+ source_original_item_ids = dc.get_source_original_item_ids_from_derived_item(DERIVED_ITEM_ID)
130
+
131
+ print(f"Derived item: {DERIVED_ITEM_ID}")
132
+ print(source_original_item_ids)
133
+
134
+ sibling_ids = dc.get_sibling_derived_item_ids(
135
+ ORIGINAL_ITEM_ID,
136
+ collection_id=COLLECTION_ID,
137
+ )
138
+
139
+ print(f"Original item: {ORIGINAL_ITEM_ID} | Sibling filter collection: {COLLECTION_ID}")
140
+ print(sibling_ids)
141
+
142
+ q1_item_ids = dc.get_items_by_timerange(
143
+ FILTER_START_DATETIME,
144
+ FILTER_END_DATETIME,
145
+ return_mode="ids",
146
+ )
147
+ print(q1_item_ids[:20])
148
+ print(f"Total matches: {len(q1_item_ids)}")
149
+
150
+ q2_item_ids = dc.get_items_by_bbox(
151
+ FILTER_BBOX[0],
152
+ FILTER_BBOX[1],
153
+ FILTER_BBOX[2],
154
+ FILTER_BBOX[3],
155
+ return_mode="ids",
156
+ )
157
+ print(q2_item_ids[:20])
158
+ print(f"Total matches: {len(q2_item_ids)}")
159
+
160
+ q3_item_ids = dc.get_items_by_bbox_and_timerange(
161
+ FILTER_BBOX,
162
+ [FILTER_START_DATETIME, FILTER_END_DATETIME],
163
+ return_mode="ids",
164
+ )
165
+ print(q3_item_ids[:20])
166
+ print(f"Total matches: {len(q3_item_ids)}")
167
+
168
+ Q4_COMPLEX_FILTER = {
169
+ "filter": {
170
+ "type": "logical",
171
+ "combinator": "and",
172
+ "filters": [
173
+ {
174
+ "type": "comparison",
175
+ "comparator": "equals",
176
+ "path": ["type"],
177
+ "value": "Feature",
178
+ "valueType": "string",
179
+ },
180
+ {
181
+ "type": "comparison",
182
+ "comparator": "equals",
183
+ "path": ["collection"],
184
+ "value": "smart_agriculture",
185
+ "valueType": "string",
186
+ },
187
+ {
188
+ "type": "comparison",
189
+ "comparator": "greaterThan",
190
+ "path": ["properties", "dafab:smart-agriculture", "number_of_fields"],
191
+ "value": SMART_AGRICULTURE_MIN_FIELDS,
192
+ "valueType": "number",
193
+ },
194
+ ],
195
+ }
196
+ }
197
+
198
+ q4_item_ids = dc.get_items_by_enhanced_filter(
199
+ Q4_COMPLEX_FILTER,
200
+ return_mode="ids",
201
+ )
202
+ print(q4_item_ids[:20])
203
+ print(f"Total matches: {len(q4_item_ids)}")
204
+
205
+ q4_item_ids_mode = dc.get_items_by_enhanced_filter(
206
+ Q4_COMPLEX_FILTER,
207
+ return_mode="ids",
208
+ )
209
+ q4_item_metadata_mode = dc.get_items_by_enhanced_filter(
210
+ Q4_COMPLEX_FILTER,
211
+ return_mode="metadata",
212
+ )
213
+
214
+ sample_asset_hrefs = [
215
+ item.get("assets", {}).get("dafab-field-boundaries", {}).get("href")
216
+ for item in q4_item_metadata_mode[:5]
217
+ ]
218
+
219
+ print(f"IDs mode count: {len(q4_item_ids_mode)}")
220
+ print(f"Metadata mode count: {len(q4_item_metadata_mode)}")
221
+ print(f"First IDs: {q4_item_ids_mode[:5]}")
222
+ print(f"First metadata asset hrefs (dafab-field-boundaries): {sample_asset_hrefs}")
223
+
224
+ q3_item_metadata = dc.get_items_by_bbox_and_timerange(
225
+ FILTER_BBOX,
226
+ [FILTER_START_DATETIME, FILTER_END_DATETIME],
227
+ return_mode="metadata",
228
+ )
229
+ print(f"Rendering {len(q3_item_metadata)} items to demo-data/filters/bbox_map.html")
230
+ dc.get_map(q3_item_metadata, draw_ids=False)
231
+
232
+ # STAC root catalog ID used as the top-level entrypoint for discovery.
233
+ ROOT_CATALOG_ID = "stac"
234
+ print(dc.extract_metadata_value(value_path="", pname=ROOT_CATALOG_ID))
235
+
236
+ # STAC collection ID in the DaFab catalog (e.g., "sentinel_2_l2a", "water_analysis", "smart_agriculture", ... )
237
+ STAC_COLLECTION_ID = "water_analysis"
238
+ print(dc.extract_metadata_value(value_path="", pname=STAC_COLLECTION_ID))
239
+
240
+ print(dc.extract_metadata_value(value_path="", pname=TOP_FACET_CATALOG_ID))
241
+
242
+ print(dc.extract_metadata_value(value_path="", pname=FACET_VALUE_CATALOG_ID))
243
+
244
+ print(dc.extract_metadata_value(value_path="", pname=ORIGINAL_ITEM_ID))
245
+
246
+ print(dc.extract_metadata_value(value_path="", pname=DERIVED_ITEM_ID))
247
+
248
+ print(dc.extract_metadata_value(
249
+ value_path=f"/assets/{DERIVED_ASSET_KEY}/href",
250
+ pname=DERIVED_ITEM_ID,
251
+ ))
252
+
253
+ PARTIAL_METADATA_PATHS = [
254
+ "/id",
255
+ "/collection",
256
+ "/properties/datetime",
257
+ f"/assets/{DERIVED_ASSET_KEY}/href",
258
+ ]
259
+ derived_item_partial_subset = dc.get_bulk_metadata(
260
+ DERIVED_ITEM_ID,
261
+ scope=STAC_SCOPE,
262
+ paths=PARTIAL_METADATA_PATHS,
263
+ )
264
+ print(dc.as_json(derived_item_partial_subset))
265
+
266
+ dc.list_storages()
267
+
268
+ print(dc.as_json(dc.check_storage(rse_name="MELUXINA_S3")))
269
+
270
+ derived_item_asset_availability = dc.list_item_asset_entries(
271
+ DERIVED_ITEM_ID,
272
+ check_storage=True,
273
+ )
274
+ print(dc.as_json(derived_item_asset_availability))
275
+
276
+ derived_item_asset_entries = dc.list_item_asset_entries(
277
+ DERIVED_ITEM_ID,
278
+ check_storage=False,
279
+ )
280
+ print(dc.as_json(derived_item_asset_entries))
281
+
282
+ stable_asset_href = dc.build_stable_asset_href(
283
+ item_id=STAGED_ORIGINAL_ITEM_ID,
284
+ asset_key=STAGED_ORIGINAL_ASSET_KEY,
285
+ scope=STAC_SCOPE,
286
+ )
287
+
288
+ stable_asset_download = dc.download_asset_from_stable_href(
289
+ stable_href=stable_asset_href,
290
+ destination_dir=ASSET_DOWNLOAD_DIR,
291
+ overwrite=True,
292
+ )
293
+ print(dc.as_json(stable_asset_download))
294
+
295
+ item_asset_download = dc.download_item_asset(
296
+ item_id=STAGED_ORIGINAL_ITEM_ID,
297
+ asset_key=STAGED_ORIGINAL_ASSET_KEY,
298
+ scope=STAC_SCOPE,
299
+ destination_dir=ASSET_DOWNLOAD_DIR,
300
+ overwrite=True,
301
+ )
302
+ print(dc.as_json(item_asset_download))
303
+
304
+ asset_entry_reports = {}
305
+ for example in DOWNLOADABLE_ASSET_EXAMPLES:
306
+ report = dc.list_item_asset_entries(
307
+ example["item_id"],
308
+ stac_namespace=example["scope"],
309
+ check_storage=True,
310
+ )
311
+ selected = next(
312
+ (row for row in report.get("asset_entries", []) if row.get("asset_key") == example["asset_key"]),
313
+ None,
314
+ )
315
+ asset_entry_reports[example["label"]] = {
316
+ "scope": example["scope"],
317
+ "item_id": example["item_id"],
318
+ "selected_asset": selected,
319
+ "metadata_asset_count": report.get("metadata_asset_count"),
320
+ "attached_asset_count": report.get("attached_asset_count"),
321
+ }
322
+ print(dc.as_json(asset_entry_reports))
@@ -0,0 +1,72 @@
1
+ import time
2
+ import traceback
3
+
4
+ from dafab_client._rucio.dafab_lib import upload_manager
5
+ from dafab_client._rucio.global_utils import setup_logger
6
+
7
+ LOG = setup_logger(__name__)
8
+
9
+
10
+ def upload_file(
11
+ fpath: str,
12
+ pname: str,
13
+ scope: str = 'dafab',
14
+ rse: str = 'MELUXINA_S3',
15
+ did_name: str | None = None,
16
+ ):
17
+ """
18
+ Upload a file to an RSE and register it in Rucio.
19
+
20
+ Parameters
21
+ ----------
22
+ fpath : str
23
+ Local filesystem path of the file to upload.
24
+ pname : str
25
+ Dataset DID name to attach the file to.
26
+ scope : str, optional
27
+ Rucio scope under which the file will be registered, by default ``'dafab'``.
28
+ rse : str, optional
29
+ Name of the Rucio Storage Element where the file will be uploaded, by default ``'MELUXINA_S3'``.
30
+ did_name : str, optional
31
+ FILE DID name to register. Defaults to the local file basename.
32
+
33
+ Notes
34
+ -----
35
+ The function retries failed uploads ``max_retries`` times with a pause of
36
+ ``retry_delay`` seconds between attempts.
37
+
38
+ Returns
39
+ -------
40
+ bool
41
+ ``True`` if the upload and registration succeed, ``False`` after all retries are exhausted.
42
+ """
43
+ max_retries = 1
44
+ retry_delay = 30 # seconds
45
+
46
+ for attempt in range(max_retries):
47
+ try:
48
+ # Get an uploader connection
49
+ uploader = upload_manager()
50
+
51
+ add_success = uploader.upload_file(fpath, pname, scope, rse, did_name=did_name)
52
+ if add_success:
53
+ LOG.result(f"The file '{fpath}' is now available on Rucio storage and indexed in catalog.\n")
54
+ return True
55
+ else:
56
+ LOG.warning(f"The upload of file '{fpath}' on Rucio storage did not finish normally.\n")
57
+ return False
58
+
59
+ except Exception as e:
60
+ LOG.warning(f"Attempt {attempt + 1}/{max_retries}: An unexpected error "
61
+ f"of type '{type(e).__name__}' occurred "
62
+ f"while uploading the file '{fpath}' on Rucio storage: {e}\n")
63
+
64
+ # Get the full traceback for debugging:
65
+ traceback.print_exc()
66
+
67
+ if attempt < max_retries - 1: # Don't sleep after the last attempt
68
+ LOG.warning(f"Retrying in {retry_delay} seconds...")
69
+ time.sleep(retry_delay)
70
+
71
+ LOG.warning("All retry attempts exhausted.")
72
+ return False