cloudnet-api-client 0.6.0__tar.gz → 0.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cloudnet_api_client-0.6.0 → cloudnet_api_client-0.7.0}/CHANGELOG.md +5 -0
- {cloudnet_api_client-0.6.0 → cloudnet_api_client-0.7.0}/PKG-INFO +3 -2
- {cloudnet_api_client-0.6.0 → cloudnet_api_client-0.7.0}/README.md +2 -1
- {cloudnet_api_client-0.6.0 → cloudnet_api_client-0.7.0}/cloudnet_api_client/client.py +23 -3
- {cloudnet_api_client-0.6.0 → cloudnet_api_client-0.7.0}/cloudnet_api_client/dl.py +13 -2
- cloudnet_api_client-0.7.0/cloudnet_api_client/version.py +1 -0
- cloudnet_api_client-0.6.0/cloudnet_api_client/version.py +0 -1
- {cloudnet_api_client-0.6.0 → cloudnet_api_client-0.7.0}/.github/workflows/publish.yml +0 -0
- {cloudnet_api_client-0.6.0 → cloudnet_api_client-0.7.0}/.github/workflows/test.yml +0 -0
- {cloudnet_api_client-0.6.0 → cloudnet_api_client-0.7.0}/.gitignore +0 -0
- {cloudnet_api_client-0.6.0 → cloudnet_api_client-0.7.0}/.pre-commit-config.yaml +0 -0
- {cloudnet_api_client-0.6.0 → cloudnet_api_client-0.7.0}/LICENSE +0 -0
- {cloudnet_api_client-0.6.0 → cloudnet_api_client-0.7.0}/cloudnet_api_client/__init__.py +0 -0
- {cloudnet_api_client-0.6.0 → cloudnet_api_client-0.7.0}/cloudnet_api_client/containers.py +0 -0
- {cloudnet_api_client-0.6.0 → cloudnet_api_client-0.7.0}/cloudnet_api_client/py.typed +0 -0
- {cloudnet_api_client-0.6.0 → cloudnet_api_client-0.7.0}/cloudnet_api_client/utils.py +0 -0
- {cloudnet_api_client-0.6.0 → cloudnet_api_client-0.7.0}/pyproject.toml +0 -0
|
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## 0.7.0 – 2025-05-06
|
|
9
|
+
|
|
10
|
+
- Validate checksum optionally
|
|
11
|
+
- Make site optional
|
|
12
|
+
|
|
8
13
|
## 0.6.0 – 2025-04-22
|
|
9
14
|
|
|
10
15
|
- Fix datetime parsing for Python 3.10
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cloudnet-api-client
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Cloudnet API client
|
|
5
5
|
Author-email: Simo Tukiainen <simo.tukiainen@fmi.fi>
|
|
6
6
|
License-File: LICENSE
|
|
@@ -65,7 +65,7 @@ Parameters:
|
|
|
65
65
|
|
|
66
66
|
| name | type | default | example |
|
|
67
67
|
| ------------------- | --------------------------- | ------- | ---------------------------------------------------- |
|
|
68
|
-
| site_id | `str`
|
|
68
|
+
| site_id | `str` or `list[str]` | `None` | "hyytiala" |
|
|
69
69
|
| date | `str` or `date` | `None` | "2024-01-01" |
|
|
70
70
|
| date_from | `str` or `date` | `None` | "2025-01-01" |
|
|
71
71
|
| date_to | `str` or `date` | `None` | "2025-01-01" |
|
|
@@ -158,6 +158,7 @@ Parameters:
|
|
|
158
158
|
| output_directory | `PathLike` or `str` | |
|
|
159
159
|
| concurrency_limit | `int` | 5 |
|
|
160
160
|
| progress | `bool` or `None` | `None` |
|
|
161
|
+
| validate_checksum | `bool` | `False` |
|
|
161
162
|
|
|
162
163
|
There's also an asynchronous version of this function:
|
|
163
164
|
`cloudnet_api_client.adownload`. It's useful for usage inside Jupyter notebook.
|
|
@@ -38,7 +38,7 @@ Parameters:
|
|
|
38
38
|
|
|
39
39
|
| name | type | default | example |
|
|
40
40
|
| ------------------- | --------------------------- | ------- | ---------------------------------------------------- |
|
|
41
|
-
| site_id | `str`
|
|
41
|
+
| site_id | `str` or `list[str]` | `None` | "hyytiala" |
|
|
42
42
|
| date | `str` or `date` | `None` | "2024-01-01" |
|
|
43
43
|
| date_from | `str` or `date` | `None` | "2025-01-01" |
|
|
44
44
|
| date_to | `str` or `date` | `None` | "2025-01-01" |
|
|
@@ -131,6 +131,7 @@ Parameters:
|
|
|
131
131
|
| output_directory | `PathLike` or `str` | |
|
|
132
132
|
| concurrency_limit | `int` | 5 |
|
|
133
133
|
| progress | `bool` or `None` | `None` |
|
|
134
|
+
| validate_checksum | `bool` | `False` |
|
|
134
135
|
|
|
135
136
|
There's also an asynchronous version of this function:
|
|
136
137
|
`cloudnet_api_client.adownload`. It's useful for usage inside Jupyter notebook.
|
|
@@ -85,7 +85,7 @@ class APIClient:
|
|
|
85
85
|
|
|
86
86
|
def metadata(
|
|
87
87
|
self,
|
|
88
|
-
site_id:
|
|
88
|
+
site_id: QueryParam = None,
|
|
89
89
|
date: DateParam = None,
|
|
90
90
|
date_from: DateParam = None,
|
|
91
91
|
date_to: DateParam = None,
|
|
@@ -108,6 +108,9 @@ class APIClient:
|
|
|
108
108
|
_add_date_params(
|
|
109
109
|
params, date, date_from, date_to, updated_at, updated_at_from, updated_at_to
|
|
110
110
|
)
|
|
111
|
+
|
|
112
|
+
_check_params(params, ("showLegacy",))
|
|
113
|
+
|
|
111
114
|
no_instrument = not instrument_id or instrument_pid
|
|
112
115
|
if no_instrument and (not product and model_id):
|
|
113
116
|
files_res = []
|
|
@@ -129,7 +132,7 @@ class APIClient:
|
|
|
129
132
|
|
|
130
133
|
def raw_metadata(
|
|
131
134
|
self,
|
|
132
|
-
site_id:
|
|
135
|
+
site_id: QueryParam = None,
|
|
133
136
|
date: DateParam = None,
|
|
134
137
|
date_from: DateParam = None,
|
|
135
138
|
date_to: DateParam = None,
|
|
@@ -181,6 +184,9 @@ class APIClient:
|
|
|
181
184
|
_add_date_params(
|
|
182
185
|
params, date, date_from, date_to, updated_at, updated_at_from, updated_at_to
|
|
183
186
|
)
|
|
187
|
+
|
|
188
|
+
_check_params(params)
|
|
189
|
+
|
|
184
190
|
res = self._get_response("raw-model-files", params)
|
|
185
191
|
return _build_raw_model_meta_objects(res)
|
|
186
192
|
|
|
@@ -190,9 +196,16 @@ class APIClient:
|
|
|
190
196
|
output_directory: str | PathLike,
|
|
191
197
|
concurrency_limit: int = 5,
|
|
192
198
|
progress: bool | None = None,
|
|
199
|
+
validate_checksum: bool = False,
|
|
193
200
|
) -> list[Path]:
|
|
194
201
|
return asyncio.run(
|
|
195
|
-
self.adownload(
|
|
202
|
+
self.adownload(
|
|
203
|
+
metadata,
|
|
204
|
+
output_directory,
|
|
205
|
+
concurrency_limit,
|
|
206
|
+
progress,
|
|
207
|
+
validate_checksum,
|
|
208
|
+
)
|
|
196
209
|
)
|
|
197
210
|
|
|
198
211
|
async def adownload(
|
|
@@ -201,6 +214,7 @@ class APIClient:
|
|
|
201
214
|
output_directory: str | PathLike,
|
|
202
215
|
concurrency_limit: int = 5,
|
|
203
216
|
progress: bool | None = None,
|
|
217
|
+
validate_checksum: bool = False,
|
|
204
218
|
) -> list[Path]:
|
|
205
219
|
disable_progress = not progress if progress is not None else None
|
|
206
220
|
output_directory = Path(output_directory).resolve()
|
|
@@ -211,6 +225,7 @@ class APIClient:
|
|
|
211
225
|
output_directory,
|
|
212
226
|
concurrency_limit,
|
|
213
227
|
disable_progress,
|
|
228
|
+
validate_checksum,
|
|
214
229
|
)
|
|
215
230
|
|
|
216
231
|
@staticmethod
|
|
@@ -495,3 +510,8 @@ def _make_session() -> requests.Session:
|
|
|
495
510
|
|
|
496
511
|
def _parse_datetime(dt: str) -> datetime.datetime:
|
|
497
512
|
return datetime.datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S.%fZ")
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
def _check_params(params: dict, ignore: tuple = ()) -> None:
|
|
516
|
+
if sum(1 for key, value in params.items() if key not in ignore and value) == 0:
|
|
517
|
+
raise TypeError("At least one of the parameters must be set.")
|
|
@@ -20,7 +20,9 @@ async def download_files(
|
|
|
20
20
|
output_path: Path,
|
|
21
21
|
concurrency_limit: int,
|
|
22
22
|
disable_progress: bool | None,
|
|
23
|
+
validate_checksum: bool = False,
|
|
23
24
|
) -> list[Path]:
|
|
25
|
+
file_exists = _checksum_matches if validate_checksum else _size_and_name_matches
|
|
24
26
|
semaphore = asyncio.Semaphore(concurrency_limit)
|
|
25
27
|
full_paths = []
|
|
26
28
|
async with aiohttp.ClientSession() as session:
|
|
@@ -29,7 +31,7 @@ async def download_files(
|
|
|
29
31
|
download_url = f"{base_url}{meta.download_url.split('/api/')[-1]}"
|
|
30
32
|
destination = output_path / meta.download_url.split("/")[-1]
|
|
31
33
|
full_paths.append(destination)
|
|
32
|
-
if destination.exists() and
|
|
34
|
+
if destination.exists() and file_exists(meta, destination):
|
|
33
35
|
logging.debug(f"Already downloaded: {destination}")
|
|
34
36
|
continue
|
|
35
37
|
task = asyncio.create_task(
|
|
@@ -97,8 +99,17 @@ async def _download_file(
|
|
|
97
99
|
logging.debug(f"Downloaded: {destination}")
|
|
98
100
|
|
|
99
101
|
|
|
100
|
-
def
|
|
102
|
+
def _checksum_matches(
|
|
101
103
|
meta: ProductMetadata | RawMetadata | RawModelMetadata, destination: Path
|
|
102
104
|
) -> bool:
|
|
103
105
|
fun = utils.sha256sum if isinstance(meta, ProductMetadata) else utils.md5sum
|
|
104
106
|
return fun(destination) == meta.checksum
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _size_and_name_matches(
|
|
110
|
+
meta: ProductMetadata | RawMetadata | RawModelMetadata, destination: Path
|
|
111
|
+
) -> bool:
|
|
112
|
+
return (
|
|
113
|
+
destination.stat().st_size == meta.size
|
|
114
|
+
and destination.name == meta.download_url.split("/")[-1]
|
|
115
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.7.0"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.6.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|