Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring Preload API #12

Merged
merged 153 commits into from
Jan 21, 2025
Merged
Changes from 1 commit
Commits
Show all changes
153 commits
Select commit Hold shift + click to select a range
4082cab
Implement initial methods in clms.py
b-yogesh Nov 4, 2024
a55d133
Refactor code
b-yogesh Nov 7, 2024
52b1e2a
Refactor code again
b-yogesh Nov 7, 2024
31ccd70
Implement get_data_ids generator
b-yogesh Nov 7, 2024
b124ef1
Tiny typo fix
b-yogesh Nov 7, 2024
39d8b37
Implement has_data
b-yogesh Nov 7, 2024
3b34c3a
Initial version of describe_data (not working entirely)
b-yogesh Nov 7, 2024
70a0456
Implement describe_data
b-yogesh Nov 8, 2024
c075479
Implement get_open_data_params_schema
b-yogesh Nov 8, 2024
49cd69b
Implemented access token class
b-yogesh Nov 8, 2024
4ffa9ab
Implemented access token class
b-yogesh Nov 8, 2024
f8ccbfb
[In progress] - open_data implementation
b-yogesh Nov 11, 2024
94ff10d
[In progress] - open_data implementation - implemented _prepare_downl…
b-yogesh Nov 12, 2024
26a6322
[In progress] - open_data implementation - more impl.
b-yogesh Nov 12, 2024
f6645f2
[In progress] - open_data implementation - more impl.
b-yogesh Nov 14, 2024
7951b2e
Update make_api_request
b-yogesh Nov 15, 2024
e950bb7
temporary bbox and crs handling
b-yogesh Nov 15, 2024
5ccede3
fix condition
b-yogesh Nov 15, 2024
24e93d1
fix get_data_store_params_schema
b-yogesh Nov 15, 2024
2e5f46f
Add constants
b-yogesh Nov 15, 2024
fc938bc
Refactoring
b-yogesh Nov 15, 2024
76169d4
Add schema for preload_data
b-yogesh Nov 15, 2024
d680129
Remove error message truncation
b-yogesh Nov 15, 2024
a91bd5c
Update get_metadata method
b-yogesh Nov 15, 2024
8aa6014
Add initial unsupported datasets check
b-yogesh Nov 15, 2024
13febb6
Raise exceptions for unsupported data and add preload params schema
b-yogesh Nov 18, 2024
63ba00c
Update schema methods
b-yogesh Nov 18, 2024
a049218
Add TODOs
b-yogesh Nov 19, 2024
a6ccac0
Implement first TODO: change data_id def
b-yogesh Nov 19, 2024
3a1c329
Implement first TODO: add include_attr bool impl
b-yogesh Nov 19, 2024
efc0c16
Fix has_data and describe_data
b-yogesh Nov 19, 2024
d4810bd
[WIP] queue download refactor
b-yogesh Nov 19, 2024
e821dd2
[WIP] refactor existing code into preload and clms classes
b-yogesh Nov 20, 2024
6d640f2
[WIP] implement queue downloads.
b-yogesh Nov 22, 2024
5fbd5aa
[WIP] Further impl. preload
b-yogesh Nov 25, 2024
7926ce4
[WIP] Further impl. preload
b-yogesh Nov 26, 2024
d064097
[WIP] Working download impl.
b-yogesh Nov 27, 2024
50b4c52
[WIP] Add initial cancel handler
b-yogesh Nov 27, 2024
faaec47
[WIP] Add initial cancel handler
b-yogesh Nov 29, 2024
20e44b4
[WIP] Refactoring
b-yogesh Dec 2, 2024
167baf7
[WIP] Improved download data
b-yogesh Dec 2, 2024
3ea8e7f
[WIP] Improved download data + merging
b-yogesh Dec 3, 2024
0be046b
Finish implementation
b-yogesh Dec 5, 2024
16ee337
Added tests for utils.py
b-yogesh Dec 5, 2024
e793038
Added tests for api_token.py
b-yogesh Dec 5, 2024
3abef8e
Refactor clms.py
b-yogesh Dec 6, 2024
425780d
Add docstrings clms.py
b-yogesh Dec 6, 2024
db902a3
Add tests for clms.py
b-yogesh Dec 6, 2024
3e3ce73
add preload const
b-yogesh Dec 6, 2024
5d7125d
Refactor
b-yogesh Dec 6, 2024
dceb47d
Add Docstrings and Type Annotations
b-yogesh Dec 6, 2024
7dbdb4b
Add example notebook
b-yogesh Dec 6, 2024
0d4018d
Minor fixes
b-yogesh Dec 6, 2024
865ead4
Add missing docs
b-yogesh Dec 6, 2024
3e1b545
Fix tests
b-yogesh Dec 10, 2024
975e498
Update error message
b-yogesh Dec 10, 2024
2176db7
Modify list to iterator in get_data_ids
b-yogesh Dec 10, 2024
715d1cf
Update CLMSDataStoreTutorial.ipynb
b-yogesh Dec 10, 2024
c7c79a8
Update README.md
b-yogesh Dec 10, 2024
a88eaf9
Create unittest.yml
b-yogesh Dec 10, 2024
70188bd
Add test_cache_manager.py
b-yogesh Dec 10, 2024
56fcf42
Add test_token_handler.py
b-yogesh Dec 10, 2024
65a271f
Rename .github/unittest.yml to .github/workflows/unittest.yml
b-yogesh Dec 10, 2024
7a36783
Add test_processor.py
b-yogesh Dec 10, 2024
d98c712
Merge remote-tracking branch 'origin/yogesh_preload-data' into yogesh…
b-yogesh Dec 10, 2024
ef40d9a
Update env
b-yogesh Dec 10, 2024
1c7888b
Remove redundant api class
b-yogesh Dec 10, 2024
4546279
Update pyproject.toml
b-yogesh Dec 10, 2024
f91ecd1
add ipywidgets
b-yogesh Dec 10, 2024
2e2250a
fix test_clms.py
b-yogesh Dec 10, 2024
dd3229a
Add CLMS url as constant
b-yogesh Dec 10, 2024
5b0eda2
Fix tests
b-yogesh Dec 10, 2024
a7a612d
Update README.md
b-yogesh Dec 10, 2024
b9c9e03
Update README.md
b-yogesh Dec 11, 2024
dc622e9
Update CLMSDataStoreTutorial.ipynb
b-yogesh Dec 11, 2024
f3efb86
Update .gitignore
b-yogesh Dec 11, 2024
0850fb6
Add numpy for tests
b-yogesh Dec 11, 2024
8ebf8f7
Add missing license text
b-yogesh Dec 11, 2024
7243361
Apply suggestions from code review
b-yogesh Dec 12, 2024
36583c4
Rename classes and fix tests
b-yogesh Dec 12, 2024
78c8943
Convert file_store and cache to properties
b-yogesh Dec 12, 2024
da3928e
Remove test_store.py
b-yogesh Dec 12, 2024
54e2f7f
Remove None return doc
b-yogesh Dec 12, 2024
02f0261
Improve docstrings
b-yogesh Dec 12, 2024
bdb362d
Update README.md
b-yogesh Dec 12, 2024
b637c77
Move functions away from utils to respective files
b-yogesh Dec 12, 2024
cc44bdb
Move constants to their respective classes
b-yogesh Dec 12, 2024
f178dce
Improve make_api_request
b-yogesh Dec 13, 2024
b30329c
Improve make_api_request #2
b-yogesh Dec 13, 2024
bb57381
Improve tests
b-yogesh Dec 13, 2024
706c6df
Datastore to MutableDataStore
b-yogesh Dec 13, 2024
0c49099
WIP [New preload API refactoring]
b-yogesh Dec 30, 2024
96be05b
WIP [New preload API refactoring - part 2]
b-yogesh Jan 2, 2025
26c030a
WIP [New preload API refactoring - update tests]
b-yogesh Jan 2, 2025
e58be16
update xcube version
b-yogesh Jan 2, 2025
16feebf
Add further tests
b-yogesh Jan 3, 2025
27ab2ef
Remove init comments
b-yogesh Jan 6, 2025
eba6439
Ready for release
b-yogesh Jan 6, 2025
8840570
Update download_manager.py and add more tests
b-yogesh Jan 6, 2025
def671b
Merge branch 'refs/heads/yogesh_preload-data' into yogesh_preload-data-2
b-yogesh Jan 6, 2025
0f654ab
[WIP] Further Refactoring
b-yogesh Jan 6, 2025
836c34f
[WIP] Update tests
b-yogesh Jan 6, 2025
725ffeb
[WIP] Delete CacheManager
b-yogesh Jan 6, 2025
e71f845
[WIP] Update tests
b-yogesh Jan 7, 2025
4c55eb0
[WIP] Update store.py
b-yogesh Jan 7, 2025
5dad841
[WIP] Update tests - cov 92
b-yogesh Jan 7, 2025
2ff4818
[WIP] Add cassettes for test_store.py
b-yogesh Jan 8, 2025
f34808e
[WIP] Update and add more tests cov-96
b-yogesh Jan 8, 2025
febae11
[WIP] Add more cassettes
b-yogesh Jan 8, 2025
df7d512
[WIP] More refactoring
b-yogesh Jan 8, 2025
b5ef6a4
[WIP] More refactoring
b-yogesh Jan 9, 2025
ed5fb0a
[WIP] Update workflow to include xcube repo install
b-yogesh Jan 9, 2025
6f59ab6
[WIP] Update notebook
b-yogesh Jan 9, 2025
125c390
[WIP] Add --no-deps
b-yogesh Jan 9, 2025
90b0236
[WIP] update unittest.yml
b-yogesh Jan 9, 2025
74bd076
[WIP] update unittest.yml
b-yogesh Jan 9, 2025
7b41350
[WIP] debug unittest.yml
b-yogesh Jan 9, 2025
7ad24c1
[WIP] debug unittest.yml
b-yogesh Jan 9, 2025
a27810f
[WIP] debug unittest.yml
b-yogesh Jan 9, 2025
4a59a54
[WIP] debug unittest.yml
b-yogesh Jan 9, 2025
084a3ba
[WIP] debug unittest.yml
b-yogesh Jan 9, 2025
ea5299f
[WIP] add requests in deps
b-yogesh Jan 9, 2025
687da65
[WIP] add fsspec, pyproj in deps
b-yogesh Jan 9, 2025
b694e48
[WIP] update env.yml
b-yogesh Jan 9, 2025
efa0002
[WIP]update unittest.yml to include all xcube deps in the env...yml
b-yogesh Jan 10, 2025
99cb1cd
[WIP] update env.yml and pyproject.toml
b-yogesh Jan 10, 2025
c91130e
[WIP] add ipywidgets
b-yogesh Jan 10, 2025
970bca6
[WIP] update CHANGES.md and README.md
b-yogesh Jan 10, 2025
ed8a8c3
[WIP] minor update to download_manager.py
b-yogesh Jan 10, 2025
0809ecb
[WIP] remove debug statements from workflow
b-yogesh Jan 10, 2025
958d766
Final refactoring
b-yogesh Jan 10, 2025
b894586
Add xcube back in workflow
b-yogesh Jan 10, 2025
e8056d9
copyright 2024 -> 2025
b-yogesh Jan 10, 2025
c782891
copyright 2024 -> 2025
b-yogesh Jan 10, 2025
d5e50b5
Update based on reviewer's comments
b-yogesh Jan 15, 2025
15fe1ea
Update based on reviewer's comments, pt. 2
b-yogesh Jan 16, 2025
0173b25
Add missing cassette
b-yogesh Jan 16, 2025
3aa8cfa
Update notebook + use protocol for data opener ids
b-yogesh Jan 16, 2025
c8994d2
Update for better notifications, and removing close() when user cance…
b-yogesh Jan 16, 2025
1a2914d
Multiple imports -> single imports per line
b-yogesh Jan 17, 2025
268f2ff
update based on reviewers comments
b-yogesh Jan 17, 2025
4eeb990
Remove tqdm
b-yogesh Jan 17, 2025
51504a4
add dynamic chunk sizes
b-yogesh Jan 17, 2025
9edb5e4
Update get_data_ids method args type
b-yogesh Jan 20, 2025
bc484f9
Fix tests
b-yogesh Jan 20, 2025
702003a
Update notebook
b-yogesh Jan 20, 2025
b1a5241
Remove redundant method
b-yogesh Jan 20, 2025
14946d2
Add spaces after the header
b-yogesh Jan 20, 2025
39bd4bf
Update notebook
b-yogesh Jan 20, 2025
5f61c45
Update notebook
b-yogesh Jan 20, 2025
d02292f
Remove tqdm dep
b-yogesh Jan 20, 2025
4f8f885
Update CHANGES.md
b-yogesh Jan 20, 2025
cfda06c
Update CHANGES.md
b-yogesh Jan 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Update README.md
b-yogesh committed Dec 10, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit a7a612d4651682996e33f42a3454cf83e0b95df9
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# xcube-clms

[![Unittest xcube-clms](https://github.com/xcube-dev/xcube-clms/actions/workflows/unittest.yml/badge.svg)](https://github.com/xcube-dev/xcube-clms/actions/workflows/unittest.yml)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![License](https://img.shields.io/github/license/dcs4cop/xcube-smos)](https://github.com/xcube-dev/xcube-clms/blob/main/LICENSE)


Unchanged files with check annotations Beta

LOG.error("Token refresh failed: ", e)
raise e
else:
LOG.info("Current token valid. Reusing it.")

Check warning on line 77 in xcube_clms/api_token_handler.py

Codecov / codecov/patch

xcube_clms/api_token_handler.py#L77

Added line #L77 was not covered by tests
return self.api_token
f"got {data_id}"
)
if not self.file_store:
raise ValueError(

Check warning on line 118 in xcube_clms/clms.py

Codecov / codecov/patch

xcube_clms/clms.py#L118

Added line #L118 was not covered by tests
"File store does not exist yet. Please preload "
"data first using the preload_data() method."
)
data_id_file = os.listdir(cache_entry)
if len(data_id_file) != 1:
LOG.warning(

Check warning on line 130 in xcube_clms/clms.py

Codecov / codecov/patch

xcube_clms/clms.py#L130

Added line #L130 was not covered by tests
f"Expected 1 file in the folder {cache_entry}, "
f"got {len(data_id_file)}. Opening the first file."
)
time_range = (item.get(START_TIME_KEY), item.get(END_TIME_KEY))
if len(crs) > 1:
LOG.warning(

Check warning on line 189 in xcube_clms/clms.py

Codecov / codecov/patch

xcube_clms/clms.py#L189

Added line #L189 was not covered by tests
f"Expected 1 crs, got {len(crs)}. Outputting the first element."
)
Raises:
ValueError: If any data ID is invalid.
"""
data_id_maps = {

Check warning on line 211 in xcube_clms/clms.py

Codecov / codecov/patch

xcube_clms/clms.py#L211

Added line #L211 was not covered by tests
data_id: {
ITEM_KEY: self._access_item(data_id),
PRODUCT_KEY: self._access_item(data_id.split(DATA_ID_SEPARATOR)[0]),
}
for data_id in data_ids
}
self._preload_data.initiate_preload(data_id_maps)

Check warning on line 218 in xcube_clms/clms.py

Codecov / codecov/patch

xcube_clms/clms.py#L218

Added line #L218 was not covered by tests
def _create_data_ids(
self,
"""
dataset = self._get_item(data_id)
if len(dataset) != 1:
raise ValueError(

Check warning on line 296 in xcube_clms/clms.py

Codecov / codecov/patch

xcube_clms/clms.py#L296

Added line #L296 was not covered by tests
f"Expected one dataset for data_id: {data_id}, found"
f" {len(dataset)}."
)
LEVEL = logging.INFO
LOG.setLevel(LEVEL)
if not LOG.hasHandlers():
handler = logging.StreamHandler()
handler.setLevel(LEVEL)
formatter = logging.Formatter(

Check warning on line 113 in xcube_clms/constants.py

Codecov / codecov/patch

xcube_clms/constants.py#L111-L113

Added lines #L111 - L113 were not covered by tests
"%(name)s - %(asctime)s - %(levelname)s - %(message)s"
)
handler.setFormatter(formatter)
LOG.addHandler(handler)

Check warning on line 117 in xcube_clms/constants.py

Codecov / codecov/patch

xcube_clms/constants.py#L116-L117

Added lines #L116 - L117 were not covered by tests
# DataOpener IDs
DATA_OPENER_IDS = (
Raises:
AssertionError: If the dataset is unsupported.
"""
self._token_handler.refresh_token()

Check warning on line 114 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L114

Added line #L114 was not covered by tests
# This is to make sure that there are pre-packaged files available for
# download. Without this, the API throws the following error: Error,
# We check for path and source based on the API code here:
# https://github.com/eea/clms.downloadtool/blob/master/clms/downloadtool/api/services/datarequest_post/post.py#L177-L196
path = item.get(PATH_KEY, "")
source = item.get(SOURCE_KEY, "")

Check warning on line 123 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L122-L123

Added lines #L122 - L123 were not covered by tests
if (path == "") and (source == ""):
LOG.warning(f"No prepackaged downloadable items available for {data_id}")

Check warning on line 126 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L125-L126

Added lines #L125 - L126 were not covered by tests
# This is to make sure that we do not send requests for currently for
# unsupported datasets.
full_source = (

Check warning on line 131 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L131

Added line #L131 was not covered by tests
product.get(DATASET_DOWNLOAD_INFORMATION_KEY)
.get(ITEMS_KEY)[0]
.get(FULL_SOURCE_KEY, "")
)
assert full_source not in NOT_SUPPORTED_LIST, (

Check warning on line 137 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L137

Added line #L137 was not covered by tests
f"This data product: {product[TITLE_KEY]} is not yet supported in "
f"this plugin yet."
)
status, task_id = self.get_current_requests_status(

Check warning on line 142 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L142

Added line #L142 was not covered by tests
dataset_id=product[UID_KEY], file_id=item[ID_KEY]
)
if status == COMPLETE or status == PENDING:
LOG.info(

Check warning on line 147 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L146-L147

Added lines #L146 - L147 were not covered by tests
f"Download request with task id {task_id} "
f"{'already completed' if status == 'COMPLETE'
else 'is in queue'} for data id: {data_id}"
)
return task_id
if status == UNDEFINED:
LOG.info(

Check warning on line 154 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L152-L154

Added lines #L152 - L154 were not covered by tests
f"Download request does not exists or has expired for "
f"data id:"
f" {data_id}"
)
if status == CANCELLED:
LOG.info(

Check warning on line 161 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L160-L161

Added lines #L160 - L161 were not covered by tests
f"Download request was cancelled for "
f"data id:"
f" {data_id}. Re-requesting now."
)
download_request_url, headers, json = self._prepare_download_request(

Check warning on line 167 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L167

Added line #L167 was not covered by tests
data_id, item, product
)
response_data = make_api_request(

Check warning on line 171 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L171

Added line #L171 was not covered by tests
method="POST", url=download_request_url, headers=headers, json=json
)
response = get_response_of_type(response_data, JSON_TYPE)
task_ids = response.get(TASK_IDS_KEY)
assert (

Check warning on line 176 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L174-L176

Added lines #L174 - L176 were not covered by tests
len(task_ids) == 1
), f"Expected API response with 1 task_id, got {len(task_ids)}"
task_id = task_ids[0].get(TASK_ID_KEY)
LOG.info(f"Download Requested with Task ID : {task_id}")
return task_id

Check warning on line 181 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L179-L181

Added lines #L179 - L181 were not covered by tests
def get_download_url(self, task_id: str) -> tuple[str, int]:
"""
Raises:
Exception: If the task has not completed or no download URL is available.
"""
self._token_handler.refresh_token()

Check warning on line 196 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L196

Added line #L196 was not covered by tests
headers = ACCEPT_HEADER.copy()
headers.update(get_authorization_header(self._api_token))

Check warning on line 199 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L198-L199

Added lines #L198 - L199 were not covered by tests
url = build_api_url(self._url, TASK_STATUS_ENDPOINT, datasets_request=False)
response_data = make_api_request(url=url, headers=headers)
response = get_response_of_type(response_data, JSON_TYPE)

Check warning on line 203 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L201-L203

Added lines #L201 - L203 were not covered by tests
for key in response:
if key == task_id:
status = response[key][STATUS_KEY]
if status in STATUS_COMPLETE:
return (

Check warning on line 209 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L205-L209

Added lines #L205 - L209 were not covered by tests
response[key][DOWNLOAD_URL_KEY],
response[key]["FileSize"],
)
else:
raise Exception(

Check warning on line 214 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L214

Added line #L214 was not covered by tests
f"Task ID {task_id} has not yet finished. No download url available yet."
)
tuple[str, dict, dict]: A tuple containing the request URL,
headers, and JSON payload.
"""
LOG.info(f"Preparing download request for {data_id}")

Check warning on line 233 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L233

Added line #L233 was not covered by tests
dataset_id = product[UID_KEY]
file_id = item[ID_KEY]
json = get_dataset_download_info(

Check warning on line 237 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L235-L237

Added lines #L235 - L237 were not covered by tests
dataset_id=dataset_id,
file_id=file_id,
)
url = build_api_url(self._url, DOWNLOAD_ENDPOINT, datasets_request=False)
if not self._api_token:
self._token_handler.refresh_token()
headers = ACCEPT_HEADER.copy()
headers.update(CONTENT_TYPE_HEADER)
headers.update(get_authorization_header(self._api_token))

Check warning on line 246 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L241-L246

Added lines #L241 - L246 were not covered by tests
return url, headers, json

Check warning on line 248 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L248

Added line #L248 was not covered by tests
def get_current_requests_status(
self,
Notes:
"""
self._token_handler.refresh_token()
headers = ACCEPT_HEADER.copy()
headers.update(get_authorization_header(self._api_token))

Check warning on line 277 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L275-L277

Added lines #L275 - L277 were not covered by tests
url = build_api_url(self._url, TASK_STATUS_ENDPOINT, datasets_request=False)
response_data = make_api_request(url=url, headers=headers)
response = get_response_of_type(response_data, JSON_TYPE)

Check warning on line 281 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L279-L281

Added lines #L279 - L281 were not covered by tests
status_priority = {

Check warning on line 283 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L283

Added line #L283 was not covered by tests
"Finished_ok": 1, # Complete
"Queued": 2, # Pending
"In_progress": 2, # Pending
"Cancelled": 3, # Cancelled
}
latest_entries = {status: {} for status in status_priority.keys()}

Check warning on line 290 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L290

Added line #L290 was not covered by tests
for key in response:
status = response[key][STATUS_KEY]
datasets = response[key][DATASETS_KEY]
requested_data_id = datasets[0][DATASET_ID_KEY]
requested_file_id = datasets[0][FILE_ID_KEY]
timestamp = (

Check warning on line 297 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L292-L297

Added lines #L292 - L297 were not covered by tests
response[key][DOWNLOAD_AVAILABLE_TIME_KEY]
if status in {"Finished_ok", "Cancelled"}
else None
) # Only get timestamp for Completed or Cancelled
condition = (

Check warning on line 302 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L302

Added line #L302 was not covered by tests
((dataset_id == requested_data_id) and (file_id == requested_file_id))
if dataset_id
else (key == task_id)
)
if condition:
current_entry = {

Check warning on line 308 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L307-L308

Added lines #L307 - L308 were not covered by tests
"status": status,
"key": key,
"timestamp": timestamp,
"response": response[key],
}
if status in latest_entries:
existing_entry = latest_entries[status]
if not existing_entry or (

Check warning on line 317 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L315-L317

Added lines #L315 - L317 were not covered by tests
timestamp and (timestamp > existing_entry.get("timestamp", ""))
):
latest_entries[status] = current_entry

Check warning on line 320 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L320

Added line #L320 was not covered by tests
for status in sorted(

Check warning on line 322 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L322

Added line #L322 was not covered by tests
status_priority, key=lambda s: status_priority[s], reverse=False
):
latest_entry = latest_entries[status]
if latest_entry:
key = latest_entry["key"]
entry_response = latest_entry["response"]
if status in STATUS_COMPLETE:
if not has_expired(entry_response[DOWNLOAD_AVAILABLE_TIME_KEY]):
return COMPLETE, key
elif status in STATUS_PENDING:
return PENDING, key
elif status in STATUS_CANCELLED:
return CANCELLED, key

Check warning on line 335 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L325-L335

Added lines #L325 - L335 were not covered by tests
return UNDEFINED, ""

Check warning on line 337 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L337

Added line #L337 was not covered by tests
def download_data(
self, download_url: str, file_size: int, task_id: str, data_id: str
task_id: Task ID associated with the dataset.
data_id: Unique identifier of the dataset.
"""
LOG.info(f"Downloading zip file from {download_url}")

Check warning on line 352 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L352

Added line #L352 was not covered by tests
response = make_api_request(download_url, timeout=600, stream=True)
chunk_size = 1024 * 1024 # 1 MB chunks

Check warning on line 355 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L354-L355

Added lines #L354 - L355 were not covered by tests
with tempfile.NamedTemporaryFile(mode="wb", delete=True) as temp_file:
temp_file_path = temp_file.name
LOG.info(f"Temporary file created at {temp_file_path}")

Check warning on line 359 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L357-L359

Added lines #L357 - L359 were not covered by tests
progress_bar = tqdm(

Check warning on line 361 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L361

Added line #L361 was not covered by tests
response.iter_content(chunk_size=chunk_size),
desc=f"Downloading zip file for task: {task_id}",
total=file_size // chunk_size,
unit_scale=True,
)
for chunk in progress_bar:
temp_file.write(chunk)
progress_bar.update(len(chunk))
del chunk
progress_bar.close()

Check warning on line 372 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L368-L372

Added lines #L368 - L372 were not covered by tests
fs = fsspec.filesystem("zip", fo=temp_file_path)
zip_contents = fs.ls(RESULTS)
actual_zip_file = None
if len(zip_contents) == 1:
if ".zip" in zip_contents[0][FILENAME_KEY]:
actual_zip_file = zip_contents[0]
elif len(zip_contents) > 1:
LOG.warn("Cannot handle more than one zip files at the moment.")

Check warning on line 381 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L374-L381

Added lines #L374 - L381 were not covered by tests
else:
LOG.warn("No downloadable zip file found inside.")
if actual_zip_file:
LOG.info(

Check warning on line 385 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L383-L385

Added lines #L383 - L385 were not covered by tests
f"Found one zip file "
f"{actual_zip_file.get(ORIGINAL_FILENAME_KEY)}."
)
with fs.open(actual_zip_file[NAME_KEY], "rb") as f:
zip_fs = fsspec.filesystem("zip", fo=f)

Check warning on line 390 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L389-L390

Added lines #L389 - L390 were not covered by tests
geo_files = DownloadTaskManager._find_geo_in_dir(

Check warning on line 392 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L392

Added line #L392 was not covered by tests
"/",
zip_fs,
)
if geo_files:
target_folder = os.path.join(self.path, data_id + "/").__str__()
os.makedirs(

Check warning on line 398 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L396-L398

Added lines #L396 - L398 were not covered by tests
os.path.dirname(target_folder),
exist_ok=True,
)
for geo_file in tqdm(

Check warning on line 402 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L402

Added line #L402 was not covered by tests
geo_files,
desc="Extracting geo files for task_id {task_id}",
):
try:
with zip_fs.open(geo_file, "rb") as source_file:
geo_file_name = geo_file.split("/")[-1]
geo_file_path = os.path.join(

Check warning on line 409 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L406-L409

Added lines #L406 - L409 were not covered by tests
target_folder, geo_file_name
)
with open(

Check warning on line 412 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L412

Added line #L412 was not covered by tests
geo_file_path,
"wb",
) as dest_file:
for chunk in tqdm(

Check warning on line 416 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L416

Added line #L416 was not covered by tests
iter(
lambda: source_file.read(chunk_size),
b"",
),
desc=f"Extracting geo file {geo_file_name}",
):
dest_file.write(chunk)
LOG.info(

Check warning on line 424 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L423-L424

Added lines #L423 - L424 were not covered by tests
f"The file {geo_file_name} has been successfully "
f"downloaded to {geo_file_path}"
)
except OSError as e:
raise OSError(f"Error occurred while writing data. {e}")
except UnicodeDecodeError as e:
raise ValueError(

Check warning on line 431 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L428-L431

Added lines #L428 - L431 were not covered by tests
f"Decoding error: {e}. File might not be text "
f"or encoding is incorrect."
)
except Exception as e:
raise Exception(f"An unexpected error occurred: {e}")

Check warning on line 436 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L435-L436

Added lines #L435 - L436 were not covered by tests
else:
raise FileNotFoundError(

Check warning on line 439 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L439

Added line #L439 was not covered by tests
"No file found in the downloaded zip file to load"
)
in `GEO_FILE_EXTS`.
- Logs details of each discovered geo file.
"""
geo_file: list[str] = []
contents = zip_fs.ls(path)
for item in contents:
if zip_fs.isdir(item[NAME_KEY]):
geo_file.extend(

Check warning on line 466 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L462-L466

Added lines #L462 - L466 were not covered by tests
DownloadTaskManager._find_geo_in_dir(
item[NAME_KEY],
zip_fs,
)
)
else:
if item[NAME_KEY].endswith(GEO_FILE_EXTS):
LOG.info(f"Found geo file: {item[NAME_KEY]}")
filename = item[NAME_KEY]
geo_file.append(filename)
return geo_file

Check warning on line 477 in xcube_clms/download_manager.py

Codecov / codecov/patch

xcube_clms/download_manager.py#L473-L477

Added lines #L473 - L477 were not covered by tests
we use the item and product keys mapped to their data ids to
preload the data.
"""
self.refresh_cache()

Check warning on line 92 in xcube_clms/preload.py

Codecov / codecov/patch

xcube_clms/preload.py#L92

Added line #L92 was not covered by tests
# We create a status event for each of the tasks so that we can
# signal the thread that it can proceed further from the queue.
for data_id_map_key in data_id_maps.keys():
self._task_control[data_id_map_key] = {

Check warning on line 96 in xcube_clms/preload.py

Codecov / codecov/patch

xcube_clms/preload.py#L95-L96

Added lines #L95 - L96 were not covered by tests
"status_event": threading.Event(),
}
executor = ThreadPoolExecutor()
for data_id_map in data_id_maps.items():
executor.submit(

Check warning on line 102 in xcube_clms/preload.py

Codecov / codecov/patch

xcube_clms/preload.py#L100-L102

Added lines #L100 - L102 were not covered by tests
self._initiate_preload,
data_id_map,
self._task_control[data_id_map[0]]["status_event"],
status_event: Event to manage task status and the visibility of
the spinner.
"""
data_id = data_id_map[0]
if data_id in self.view_cache().keys():
LOG.info(f"The data for {data_id} is already cached at {self.path}")
return

Check warning on line 124 in xcube_clms/preload.py

Codecov / codecov/patch

xcube_clms/preload.py#L121-L124

Added lines #L121 - L124 were not covered by tests
task_id = self._download_manager.request_download(

Check warning on line 126 in xcube_clms/preload.py

Codecov / codecov/patch

xcube_clms/preload.py#L126

Added line #L126 was not covered by tests
data_id=data_id,
item=data_id_map[1].get("item"),
product=data_id_map[1].get("product"),
)
spinner_thread = threading.Thread(

Check warning on line 132 in xcube_clms/preload.py

Codecov / codecov/patch

xcube_clms/preload.py#L132

Added line #L132 was not covered by tests
target=spinner, args=(status_event, f"{task_id}")
)
status_event.set()
spinner_thread.start()

Check warning on line 136 in xcube_clms/preload.py

Codecov / codecov/patch

xcube_clms/preload.py#L135-L136

Added lines #L135 - L136 were not covered by tests
while status_event.is_set():
status, _ = self._download_manager.get_current_requests_status(

Check warning on line 139 in xcube_clms/preload.py

Codecov / codecov/patch

xcube_clms/preload.py#L138-L139

Added lines #L138 - L139 were not covered by tests
task_id=task_id
)
if status == COMPLETE:
LOG.info(f"Status: {status} for {data_id} with task ID {task_id}.")
status_event.clear()
spinner_thread.join()
download_url, file_size = self._download_manager.get_download_url(

Check warning on line 146 in xcube_clms/preload.py

Codecov / codecov/patch

xcube_clms/preload.py#L142-L146

Added lines #L142 - L146 were not covered by tests
task_id
)
self.download_data(download_url, file_size, task_id, data_id)
self._file_processor.postprocess(data_id)
if status in PENDING:
LOG.info(

Check warning on line 152 in xcube_clms/preload.py

Codecov / codecov/patch

xcube_clms/preload.py#L149-L152

Added lines #L149 - L152 were not covered by tests
f"Status: {status} for {data_id} with task ID {task_id}. Will "
f"recheck status in "
f"{RETRY_TIMEOUT} seconds"
)
if status in CANCELLED:
LOG.info(

Check warning on line 158 in xcube_clms/preload.py

Codecov / codecov/patch

xcube_clms/preload.py#L157-L158

Added lines #L157 - L158 were not covered by tests
f"Status: {status} for {data_id} with task ID {task_id}. Exiting now"
)
status_event.clear()
spinner_thread.join()
return

Check warning on line 163 in xcube_clms/preload.py

Codecov / codecov/patch

xcube_clms/preload.py#L161-L163

Added lines #L161 - L163 were not covered by tests
time.sleep(RETRY_TIMEOUT)

Check warning on line 165 in xcube_clms/preload.py

Codecov / codecov/patch

xcube_clms/preload.py#L165

Added line #L165 was not covered by tests
def download_data(
self, download_url: str, file_size: int, task_id: str, data_id: str
task_id: Task ID of the download request.
data_id: Identifier of the data being downloaded.
"""
self._download_manager.download_data(download_url, file_size, task_id, data_id)

Check warning on line 181 in xcube_clms/preload.py

Codecov / codecov/patch

xcube_clms/preload.py#L181

Added line #L181 was not covered by tests
def view_cache(self) -> dict[str, str]:
"""
Returns:
dict: Cached map.
"""
return self._cache_manager.get_cache()

Check warning on line 190 in xcube_clms/preload.py

Codecov / codecov/patch

xcube_clms/preload.py#L190

Added line #L190 was not covered by tests
def refresh_cache(self) -> None:
"""
Refreshes the cache map.
"""
self._cache_manager.refresh_cache()

Check warning on line 196 in xcube_clms/preload.py

Codecov / codecov/patch

xcube_clms/preload.py#L196

Added line #L196 was not covered by tests
"supported."
)
return
self._merge_and_save(en_map, data_id)
if self.cleanup:
cleanup_dir(target_folder)

Check warning on line 85 in xcube_clms/processor.py

Codecov / codecov/patch

xcube_clms/processor.py#L83-L85

Added lines #L83 - L85 were not covered by tests
def _prepare_merge(
self, files: list[str], data_id: str
from typing import Tuple, Iterator, Container, Any, Union
import xarray as xr
from xcube.core.store import (

Check warning on line 25 in xcube_clms/store.py

Codecov / codecov/patch

xcube_clms/store.py#L25

Added line #L25 was not covered by tests
DataDescriptor,
DataStore,
DataTypeLike,
)
from .clms import CLMS
from .constants import DATA_OPENER_IDS
from .utils import assert_valid_data_type

Check warning on line 40 in xcube_clms/store.py

Codecov / codecov/patch

xcube_clms/store.py#L39-L40

Added lines #L39 - L40 were not covered by tests
class CLMSDataStore(DataStore, ABC):
plugin."""
def __init__(self, **clms_kwargs):
self._clms = CLMS(**clms_kwargs)

Check warning on line 48 in xcube_clms/store.py

Codecov / codecov/patch

xcube_clms/store.py#L48

Added line #L48 was not covered by tests
@classmethod
def get_data_store_params_schema(cls) -> JsonObjectSchema:
credentials_params = dict(

Check warning on line 52 in xcube_clms/store.py

Codecov / codecov/patch

xcube_clms/store.py#L52

Added line #L52 was not covered by tests
client_id=JsonStringSchema(),
issued=JsonStringSchema(),
private_key=JsonStringSchema(),
@classmethod
def get_data_types(cls) -> Tuple[str, ...]:
return (DATASET_TYPE.alias,)

Check warning on line 84 in xcube_clms/store.py

Codecov / codecov/patch

xcube_clms/store.py#L84

Added line #L84 was not covered by tests
def get_data_types_for_data(self, data_id: str) -> Tuple[str, ...]:
return self.get_data_types()

Check warning on line 87 in xcube_clms/store.py

Codecov / codecov/patch

xcube_clms/store.py#L87

Added line #L87 was not covered by tests
def get_data_ids(
self,
data_type: DataTypeLike = None,
include_attrs: Container[str] | bool | None = None,
) -> Union[Iterator[str], Iterator[tuple[str, dict[str, Any]]]]:
assert_valid_data_type(data_type)
data_ids = self._clms.get_data_ids(include_attrs)
for data_id in data_ids:
if ((include_attrs is not None) and (include_attrs != False)) or (

Check warning on line 97 in xcube_clms/store.py

Codecov / codecov/patch

xcube_clms/store.py#L94-L97

Added lines #L94 - L97 were not covered by tests
include_attrs == True
):
yield data_id[0], data_id[1]

Check warning on line 100 in xcube_clms/store.py

Codecov / codecov/patch

xcube_clms/store.py#L100

Added line #L100 was not covered by tests
else:
yield data_id

Check warning on line 102 in xcube_clms/store.py

Codecov / codecov/patch

xcube_clms/store.py#L102

Added line #L102 was not covered by tests
def has_data(self, data_id: str, data_type: DataTypeLike = None) -> bool:
return self._clms.has_data(data_id, data_type)

Check warning on line 105 in xcube_clms/store.py

Codecov / codecov/patch

xcube_clms/store.py#L104-L105

Added lines #L104 - L105 were not covered by tests
def describe_data(
self, data_id: str, data_type: DataTypeLike = None
) -> DataDescriptor:
assert_valid_data_type(data_type)
metadata = self._clms.get_extent(data_id)
return DatasetDescriptor(data_id, **metadata)

Check warning on line 112 in xcube_clms/store.py

Codecov / codecov/patch

xcube_clms/store.py#L110-L112

Added lines #L110 - L112 were not covered by tests
def get_data_opener_ids(
self, data_id: str = None, data_type: DataTypeLike = None
) -> Tuple[str, ...]:
return DATA_OPENER_IDS

Check warning on line 117 in xcube_clms/store.py

Codecov / codecov/patch

xcube_clms/store.py#L117

Added line #L117 was not covered by tests
def get_open_data_params_schema(
self, data_id: str = None, opener_id: str = None
) -> JsonObjectSchema:
# We do not support any open_data_params yet
return JsonObjectSchema()

Check warning on line 123 in xcube_clms/store.py

Codecov / codecov/patch

xcube_clms/store.py#L123

Added line #L123 was not covered by tests
def open_data(
self,
resolution: str = "",
**open_params,
) -> xr.Dataset:
return self._clms.open_data(data_id)

Check warning on line 133 in xcube_clms/store.py

Codecov / codecov/patch

xcube_clms/store.py#L133

Added line #L133 was not covered by tests
def search_data(
self, data_type: DataTypeLike = None, **search_params
) -> JsonObjectSchema:
pass
def preload_data(self, *data_ids: str, **preload_params):
schema = self.get_preload_params_schema()
schema.validate_instance(preload_params)
return self._clms.preload_data(*data_ids, **preload_params)

Check warning on line 149 in xcube_clms/store.py

Codecov / codecov/patch

xcube_clms/store.py#L146-L149

Added lines #L146 - L149 were not covered by tests
@classmethod
def get_preload_params_schema(cls):
return JsonObjectSchema(additional_properties=False)

Check warning on line 153 in xcube_clms/store.py

Codecov / codecov/patch

xcube_clms/store.py#L151-L153

Added lines #L151 - L153 were not covered by tests
DataStoreError: Error, if *data_type* is not
supported by the store.
"""
if not is_valid_data_type(data_type):
raise DataStoreError(

Check warning on line 63 in xcube_clms/utils.py

Codecov / codecov/patch

xcube_clms/utils.py#L62-L63

Added lines #L62 - L63 were not covered by tests
f"Data type must be {DATASET_TYPE.alias!r} or but got {data_type!r}."
)
Returns:
True if *data_type* is supported by the store, otherwise False
"""
return data_type is None or DATASET_TYPE.is_super_type_of(data_type)

Check warning on line 78 in xcube_clms/utils.py

Codecov / codecov/patch

xcube_clms/utils.py#L78

Added line #L78 was not covered by tests
ResponseType = Literal["json", "text", "bytes"]