ddsapi 0.6b0__tar.gz → 0.6b3__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.
- {ddsapi-0.6b0 → ddsapi-0.6b3}/PKG-INFO +6 -2
- {ddsapi-0.6b0 → ddsapi-0.6b3}/README.md +1 -1
- {ddsapi-0.6b0 → ddsapi-0.6b3}/ddsapi/api.py +134 -34
- ddsapi-0.6b3/ddsapi/cache.py +107 -0
- {ddsapi-0.6b0 → ddsapi-0.6b3}/ddsapi.egg-info/PKG-INFO +6 -2
- {ddsapi-0.6b0 → ddsapi-0.6b3}/ddsapi.egg-info/SOURCES.txt +4 -1
- {ddsapi-0.6b0 → ddsapi-0.6b3}/ddsapi.egg-info/requires.txt +1 -1
- {ddsapi-0.6b0 → ddsapi-0.6b3}/ddsapi.egg-info/top_level.txt +1 -0
- {ddsapi-0.6b0 → ddsapi-0.6b3}/setup.py +2 -2
- ddsapi-0.6b3/tests/__init__.py +0 -0
- ddsapi-0.6b3/tests/test_config.py +88 -0
- {ddsapi-0.6b0 → ddsapi-0.6b3}/LICENSE +0 -0
- {ddsapi-0.6b0 → ddsapi-0.6b3}/ddsapi/__init__.py +0 -0
- {ddsapi-0.6b0 → ddsapi-0.6b3}/ddsapi.egg-info/dependency_links.txt +0 -0
- {ddsapi-0.6b0 → ddsapi-0.6b3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ddsapi
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6b3
|
|
4
4
|
Summary: Python Client to access and download data from CMCC Data Delivery System (DDS)
|
|
5
5
|
Home-page: https://github.com/CMCC-Foundation/ddsapi-client/
|
|
6
6
|
Author: CMCC Data Delivery System Team
|
|
@@ -18,6 +18,10 @@ Classifier: Topic :: Scientific/Engineering :: Hydrology
|
|
|
18
18
|
Requires-Python: >=3.7
|
|
19
19
|
Description-Content-Type: text/markdown
|
|
20
20
|
License-File: LICENSE
|
|
21
|
+
Requires-Dist: netCDF4>=1.5.3
|
|
22
|
+
Requires-Dist: scipy>=1.5.2
|
|
23
|
+
Requires-Dist: requests>=2.23.0
|
|
24
|
+
Requires-Dist: xarray>=0.16.0
|
|
21
25
|
|
|
22
26
|
# DDSAPI-Client
|
|
23
27
|
Python Client to access and download data from [CMCC Data Delivery System (DDS)](https://dds.cmcc.it)
|
|
@@ -40,6 +44,6 @@ $ pip install ddsapi
|
|
|
40
44
|
To use the tool a file `$HOME/.ddsapirc` must be created as following
|
|
41
45
|
|
|
42
46
|
```bash
|
|
43
|
-
url: https://
|
|
47
|
+
url: https://ddshub.cmcc.it/api/v2
|
|
44
48
|
key: <api-key>
|
|
45
49
|
```
|
|
@@ -15,17 +15,30 @@ from __future__ import (
|
|
|
15
15
|
division,
|
|
16
16
|
print_function,
|
|
17
17
|
unicode_literals,
|
|
18
|
+
annotations
|
|
18
19
|
)
|
|
20
|
+
import dis
|
|
19
21
|
|
|
22
|
+
import pickle
|
|
20
23
|
import json
|
|
21
24
|
import time
|
|
22
25
|
import os
|
|
23
26
|
import logging
|
|
24
27
|
import requests
|
|
25
28
|
import zipfile
|
|
26
|
-
|
|
29
|
+
import shutil
|
|
30
|
+
from typing import Any, Union, Iterable
|
|
31
|
+
import urllib3
|
|
27
32
|
import xarray as xr
|
|
28
33
|
|
|
34
|
+
from .cache import CacheManager
|
|
35
|
+
|
|
36
|
+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
|
37
|
+
|
|
38
|
+
def str2bool(s: str, default: Any = False) -> bool:
|
|
39
|
+
if isinstance(s, str):
|
|
40
|
+
return s.lower() in ("1", "yes", "y", "true")
|
|
41
|
+
return default
|
|
29
42
|
|
|
30
43
|
def bytes_to_string(n):
|
|
31
44
|
u = ["", "K", "M", "G", "T", "P"]
|
|
@@ -149,6 +162,18 @@ class _Result:
|
|
|
149
162
|
def download(self, target=None):
|
|
150
163
|
self.debug("Downloading from %s", self._download_url)
|
|
151
164
|
return self._download(self._download_url, target)
|
|
165
|
+
|
|
166
|
+
def _maybe_unzip(self):
|
|
167
|
+
if self._is_zip:
|
|
168
|
+
with zipfile.ZipFile(self.target_path, "r") as zip_ref:
|
|
169
|
+
self.target_path = self.target_path.split(".")[0]
|
|
170
|
+
zip_ref.extractall(self.target_path)
|
|
171
|
+
|
|
172
|
+
def get_files(self) -> Union[str, Iterable[str]]:
|
|
173
|
+
self._maybe_unzip()
|
|
174
|
+
if os.path.isdir(self.target_path):
|
|
175
|
+
return [os.path.join(self.target_path, f) for f in os.listdir(self.target_path)]
|
|
176
|
+
return self.target_path
|
|
152
177
|
|
|
153
178
|
def dataset(self):
|
|
154
179
|
self.debug("Location %s", self.target_path)
|
|
@@ -157,10 +182,7 @@ class _Result:
|
|
|
157
182
|
"No file found. Downloading could have not finished yet or it"
|
|
158
183
|
" failed."
|
|
159
184
|
)
|
|
160
|
-
|
|
161
|
-
with zipfile.ZipFile(self.target_path, "r") as zip_ref:
|
|
162
|
-
self.target_path = self.target_path.split(".")[0]
|
|
163
|
-
zip_ref.extractall(self.target_path)
|
|
185
|
+
self._maybe_unzip()
|
|
164
186
|
if os.path.isdir(self.target_path):
|
|
165
187
|
ds_list = []
|
|
166
188
|
for f in os.listdir(self.target_path):
|
|
@@ -171,6 +193,70 @@ class _Result:
|
|
|
171
193
|
return ds_list
|
|
172
194
|
|
|
173
195
|
return xr.open_dataset(self.target_path)
|
|
196
|
+
|
|
197
|
+
class EnvVarNames:
|
|
198
|
+
RC_FILE: str = "DDSAPI_RC"
|
|
199
|
+
URL: str = "DDSAPI_URL"
|
|
200
|
+
KEY: str = "DDSAPI_KEY"
|
|
201
|
+
CACHEDIR: str = "DDSAPI_CLIENT_CACHE_DIR"
|
|
202
|
+
DISABLE_CACHE: str = "DDS_CACHE_DISABLE"
|
|
203
|
+
|
|
204
|
+
class Config:
|
|
205
|
+
"""Configuration class.
|
|
206
|
+
|
|
207
|
+
The configuration defined in the `.ddsapirc` file overwrites those
|
|
208
|
+
defined using environmental variables."""
|
|
209
|
+
|
|
210
|
+
_RC_FILENAME: str = ".ddsapirc"
|
|
211
|
+
_CACHE_FILENAME: str = ".cache"
|
|
212
|
+
url: None | str = None
|
|
213
|
+
key: None | str = None
|
|
214
|
+
cachedir: None | str = None
|
|
215
|
+
verify: None | int = None
|
|
216
|
+
|
|
217
|
+
def __init__(self, url: str | None = None, key: str | None = None) -> None:
|
|
218
|
+
dotrc = os.environ.get(
|
|
219
|
+
EnvVarNames.RC_FILE,
|
|
220
|
+
os.path.expanduser(os.path.join("~", Config._RC_FILENAME)),
|
|
221
|
+
)
|
|
222
|
+
self._init_conf_with_env_vars()
|
|
223
|
+
self._maybe_overwrite_from_rc_file(dotrc)
|
|
224
|
+
self._maybe_apply_defaults()
|
|
225
|
+
self._apply_user_defined(url=url, key=key)
|
|
226
|
+
|
|
227
|
+
def _apply_user_defined(self, url, key) -> None:
|
|
228
|
+
if url:
|
|
229
|
+
self.url = url
|
|
230
|
+
if key:
|
|
231
|
+
self.key = key
|
|
232
|
+
|
|
233
|
+
def _maybe_apply_defaults(self) -> None:
|
|
234
|
+
if self.verify is None:
|
|
235
|
+
self.verify = 1
|
|
236
|
+
if not self.cachedir:
|
|
237
|
+
self.cachedir = os.path.expanduser(
|
|
238
|
+
os.path.join("~", Config._CACHE_FILENAME)
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
def _init_conf_with_env_vars(self) -> None:
|
|
242
|
+
self.url = os.environ.get(EnvVarNames.URL)
|
|
243
|
+
self.key = os.environ.get(EnvVarNames.KEY)
|
|
244
|
+
self.cachedir = os.environ.get(EnvVarNames.CACHEDIR)
|
|
245
|
+
|
|
246
|
+
def _maybe_overwrite_from_rc_file(self, rcfile: str) -> None:
|
|
247
|
+
if os.path.exists(rcfile):
|
|
248
|
+
config = read_config(rcfile)
|
|
249
|
+
else:
|
|
250
|
+
config = {}
|
|
251
|
+
if not self.key:
|
|
252
|
+
self.key = config.get("key")
|
|
253
|
+
if not self.url:
|
|
254
|
+
self.url = config.get("url")
|
|
255
|
+
if not self.verify:
|
|
256
|
+
verify_ = config.get("verify")
|
|
257
|
+
self.verify = int(verify_) if verify_ else None
|
|
258
|
+
if not self.cachedir:
|
|
259
|
+
self.cachedir = config.get("cachedir")
|
|
174
260
|
|
|
175
261
|
|
|
176
262
|
class Client:
|
|
@@ -241,8 +327,8 @@ class Client:
|
|
|
241
327
|
|
|
242
328
|
def __init__(
|
|
243
329
|
self,
|
|
244
|
-
url=
|
|
245
|
-
key=
|
|
330
|
+
url=None,
|
|
331
|
+
key=None,
|
|
246
332
|
direct_path=False,
|
|
247
333
|
quiet=False,
|
|
248
334
|
debug=False,
|
|
@@ -267,27 +353,18 @@ class Client:
|
|
|
267
353
|
logging.basicConfig(
|
|
268
354
|
level=level, format="%(asctime)s %(levelname)s %(message)s"
|
|
269
355
|
)
|
|
356
|
+
config = Config()
|
|
357
|
+
self.url = config.url
|
|
358
|
+
self.key = config.key
|
|
359
|
+
self.verify = config.verify
|
|
360
|
+
self.cache: CacheManager = CacheManager(
|
|
361
|
+
cache_dir=config.cachedir,
|
|
362
|
+
disabled=str2bool(os.environ.get(EnvVarNames.DISABLE_CACHE), default=True))
|
|
363
|
+
self.cachedir = config.cachedir
|
|
364
|
+
|
|
365
|
+
if self.url is None or self.key is None:
|
|
366
|
+
raise Exception("Missing/incomplete configuration file")
|
|
270
367
|
|
|
271
|
-
dotrc = os.environ.get("DDSAPI_RC", os.path.expanduser("~/.ddsapirc"))
|
|
272
|
-
|
|
273
|
-
if url is None or key is None:
|
|
274
|
-
if os.path.exists(dotrc):
|
|
275
|
-
config = read_config(dotrc)
|
|
276
|
-
|
|
277
|
-
if key is None:
|
|
278
|
-
key = config.get("key")
|
|
279
|
-
|
|
280
|
-
if url is None:
|
|
281
|
-
url = config.get("url")
|
|
282
|
-
|
|
283
|
-
if verify is None:
|
|
284
|
-
verify = int(config.get("verify", 1))
|
|
285
|
-
|
|
286
|
-
if url is None or key is None or key is None:
|
|
287
|
-
raise Exception(f"Missing/incomplete configuration file: {dotrc}")
|
|
288
|
-
|
|
289
|
-
self.url = url
|
|
290
|
-
self.key = key
|
|
291
368
|
self.direct_path = direct_path
|
|
292
369
|
|
|
293
370
|
self.quiet = quiet
|
|
@@ -562,6 +639,10 @@ class Client:
|
|
|
562
639
|
session = self.session
|
|
563
640
|
if "format" not in request:
|
|
564
641
|
request["temp_file"] = target
|
|
642
|
+
cached_target = self.cache.maybe_get_from_cache(dataset_id=dataset_id, product_id=product_id, request=request)
|
|
643
|
+
if cached_target:
|
|
644
|
+
return cached_target
|
|
645
|
+
|
|
565
646
|
jreply = self._submit(
|
|
566
647
|
f"{self.url}/datasets/{dataset_id}/{product_id}/execute",
|
|
567
648
|
request,
|
|
@@ -616,14 +697,29 @@ class Client:
|
|
|
616
697
|
result = _Result(
|
|
617
698
|
self, request_id=request_id, auth_token=self.auth_token
|
|
618
699
|
)
|
|
700
|
+
import tempfile
|
|
701
|
+
if target is None:
|
|
702
|
+
_target = tempfile.NamedTemporaryFile(delete=False).name
|
|
703
|
+
else:
|
|
704
|
+
_target = target
|
|
705
|
+
try:
|
|
706
|
+
result.download(_target)
|
|
707
|
+
self.cache.add_to_cache(
|
|
708
|
+
dataset_id=dataset_id,
|
|
709
|
+
product_id=product_id,
|
|
710
|
+
request=request,
|
|
711
|
+
target=result.get_files(), overwrite=False)
|
|
712
|
+
except RuntimeError as err:
|
|
713
|
+
self.logger.error(str(err))
|
|
714
|
+
return
|
|
715
|
+
|
|
619
716
|
if target is not None:
|
|
620
|
-
try:
|
|
621
|
-
result.download(target)
|
|
622
|
-
except RuntimeError as err:
|
|
623
|
-
self.logger.error(str(err))
|
|
624
|
-
return
|
|
625
717
|
return result
|
|
626
|
-
|
|
718
|
+
else:
|
|
719
|
+
if self.cache.disabled:
|
|
720
|
+
return result.dataset()
|
|
721
|
+
else:
|
|
722
|
+
return self.cache.maybe_get_from_cache(dataset_id=dataset_id, product_id=product_id, request=request)
|
|
627
723
|
|
|
628
724
|
if msg["status"] == "RUNNING" or msg["status"] == "PENDING":
|
|
629
725
|
if self.timeout and (time.time() - start > self.timeout):
|
|
@@ -732,10 +828,14 @@ class Client:
|
|
|
732
828
|
if res is not None:
|
|
733
829
|
if not retriable(res.status_code, res.reason):
|
|
734
830
|
return res
|
|
831
|
+
try:
|
|
832
|
+
text = res.json()['detail']
|
|
833
|
+
except requests.exceptions.JSONDecodeError:
|
|
834
|
+
text = res.text
|
|
735
835
|
self.warning(
|
|
736
836
|
"Recovering from HTTP error [%s %s], attemps %s of %s",
|
|
737
837
|
res.status_code,
|
|
738
|
-
|
|
838
|
+
text,
|
|
739
839
|
tries,
|
|
740
840
|
self.retry_max,
|
|
741
841
|
)
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""This module contains simple query-hash-based cache mechanism."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import json
|
|
5
|
+
from typing import Mapping, Optional, Iterable, Union
|
|
6
|
+
from uuid import uuid4
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
import pickle
|
|
9
|
+
import shutil
|
|
10
|
+
|
|
11
|
+
import xarray as xr
|
|
12
|
+
import hashlib
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class CacheManager:
|
|
17
|
+
cache_dir: str = field(kw_only=True)
|
|
18
|
+
disabled: bool = field(default=False, init=True, kw_only=True)
|
|
19
|
+
cache_config: str = field(default=".config", init=False)
|
|
20
|
+
_cache: Mapping[str, str] = field(init=False)
|
|
21
|
+
|
|
22
|
+
def __post_init__(self):
|
|
23
|
+
self._init()
|
|
24
|
+
self._cache = self._read_cache() if not self.disabled else {}
|
|
25
|
+
|
|
26
|
+
def _init(self) -> None:
|
|
27
|
+
self._cache = {}
|
|
28
|
+
if not os.path.exists(self.cache_dir):
|
|
29
|
+
os.makedirs(self.cache_dir)
|
|
30
|
+
if os.path.exists(os.path.join(self.cache_dir, self.cache_config)):
|
|
31
|
+
return
|
|
32
|
+
self._update_cache_config()
|
|
33
|
+
|
|
34
|
+
def _update_cache_config(self) -> None:
|
|
35
|
+
with open(os.path.join(self.cache_dir, self.cache_config), "wb") as file:
|
|
36
|
+
pickle.dump(self._cache, file=file)
|
|
37
|
+
|
|
38
|
+
def _read_cache(self) -> dict:
|
|
39
|
+
with open(os.path.join(self.cache_dir, self.cache_config), "rb") as file:
|
|
40
|
+
return pickle.load(file)
|
|
41
|
+
|
|
42
|
+
def _compute_hash(
|
|
43
|
+
self, dataset_id: str, product_id: str, request: dict
|
|
44
|
+
) -> int:
|
|
45
|
+
return hashlib.sha256(
|
|
46
|
+
json.dumps(
|
|
47
|
+
dict(**{"dataset_id": dataset_id, "product_id": product_id}, **request)
|
|
48
|
+
).encode()
|
|
49
|
+
).hexdigest()
|
|
50
|
+
|
|
51
|
+
def _maybe_get_file_from_cache(
|
|
52
|
+
self, dataset_id: str, product_id: str, request: dict
|
|
53
|
+
) -> Optional[str]:
|
|
54
|
+
query_hash: int = self._compute_hash(dataset_id, product_id, request)
|
|
55
|
+
return self._cache.get(query_hash)
|
|
56
|
+
|
|
57
|
+
def add_to_cache(
|
|
58
|
+
self,
|
|
59
|
+
dataset_id: str,
|
|
60
|
+
product_id: str,
|
|
61
|
+
request: dict,
|
|
62
|
+
target: Union[Iterable[str], str],
|
|
63
|
+
*,
|
|
64
|
+
overwrite: bool = False,
|
|
65
|
+
) -> None:
|
|
66
|
+
if self.disabled:
|
|
67
|
+
return
|
|
68
|
+
query_hash: int = self._compute_hash(dataset_id, product_id, request)
|
|
69
|
+
if query_hash in self._cache and not overwrite:
|
|
70
|
+
return
|
|
71
|
+
if isinstance(target, list):
|
|
72
|
+
cache_files = []
|
|
73
|
+
for f in target:
|
|
74
|
+
_, ext = os.path.splitext(f)
|
|
75
|
+
res_file = f"{uuid4()}{ext}"
|
|
76
|
+
cache_files.append(res_file)
|
|
77
|
+
shutil.move(f, os.path.join(self.cache_dir, res_file))
|
|
78
|
+
self._cache[query_hash] = cache_files
|
|
79
|
+
elif isinstance(target, str):
|
|
80
|
+
_, ext = os.path.splitext(target)
|
|
81
|
+
res_file = f"{uuid4()}{ext}"
|
|
82
|
+
shutil.move(target, os.path.join(self.cache_dir, res_file))
|
|
83
|
+
self._cache[query_hash] = res_file
|
|
84
|
+
self._update_cache_config()
|
|
85
|
+
|
|
86
|
+
def maybe_get_from_cache(
|
|
87
|
+
self, dataset_id: str, product_id: str, request: dict
|
|
88
|
+
) -> Union[xr.Dataset, Iterable[xr.Dataset], None]:
|
|
89
|
+
target: Union[str, Iterable[str]] = self._maybe_get_file_from_cache(
|
|
90
|
+
dataset_id=dataset_id, product_id=product_id, request=request
|
|
91
|
+
)
|
|
92
|
+
if self.disabled:
|
|
93
|
+
return
|
|
94
|
+
if not target:
|
|
95
|
+
return
|
|
96
|
+
if isinstance(target, list):
|
|
97
|
+
ds_list = []
|
|
98
|
+
for f in target:
|
|
99
|
+
ds = xr.open_dataset(os.path.join(self.cache_dir, f))
|
|
100
|
+
ds_list.append(ds)
|
|
101
|
+
if len(ds_list) == 1:
|
|
102
|
+
return ds_list[0]
|
|
103
|
+
return ds_list
|
|
104
|
+
elif isinstance(target, str):
|
|
105
|
+
return xr.open_dataset(os.path.join(self.cache_dir, target))
|
|
106
|
+
else:
|
|
107
|
+
raise TypeError
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ddsapi
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6b3
|
|
4
4
|
Summary: Python Client to access and download data from CMCC Data Delivery System (DDS)
|
|
5
5
|
Home-page: https://github.com/CMCC-Foundation/ddsapi-client/
|
|
6
6
|
Author: CMCC Data Delivery System Team
|
|
@@ -18,6 +18,10 @@ Classifier: Topic :: Scientific/Engineering :: Hydrology
|
|
|
18
18
|
Requires-Python: >=3.7
|
|
19
19
|
Description-Content-Type: text/markdown
|
|
20
20
|
License-File: LICENSE
|
|
21
|
+
Requires-Dist: netCDF4>=1.5.3
|
|
22
|
+
Requires-Dist: scipy>=1.5.2
|
|
23
|
+
Requires-Dist: requests>=2.23.0
|
|
24
|
+
Requires-Dist: xarray>=0.16.0
|
|
21
25
|
|
|
22
26
|
# DDSAPI-Client
|
|
23
27
|
Python Client to access and download data from [CMCC Data Delivery System (DDS)](https://dds.cmcc.it)
|
|
@@ -40,6 +44,6 @@ $ pip install ddsapi
|
|
|
40
44
|
To use the tool a file `$HOME/.ddsapirc` must be created as following
|
|
41
45
|
|
|
42
46
|
```bash
|
|
43
|
-
url: https://
|
|
47
|
+
url: https://ddshub.cmcc.it/api/v2
|
|
44
48
|
key: <api-key>
|
|
45
49
|
```
|
|
@@ -3,8 +3,11 @@ README.md
|
|
|
3
3
|
setup.py
|
|
4
4
|
ddsapi/__init__.py
|
|
5
5
|
ddsapi/api.py
|
|
6
|
+
ddsapi/cache.py
|
|
6
7
|
ddsapi.egg-info/PKG-INFO
|
|
7
8
|
ddsapi.egg-info/SOURCES.txt
|
|
8
9
|
ddsapi.egg-info/dependency_links.txt
|
|
9
10
|
ddsapi.egg-info/requires.txt
|
|
10
|
-
ddsapi.egg-info/top_level.txt
|
|
11
|
+
ddsapi.egg-info/top_level.txt
|
|
12
|
+
tests/__init__.py
|
|
13
|
+
tests/test_config.py
|
|
@@ -17,7 +17,7 @@ with open("README.md", "r") as f:
|
|
|
17
17
|
|
|
18
18
|
setuptools.setup(
|
|
19
19
|
name="ddsapi",
|
|
20
|
-
version="0.
|
|
20
|
+
version="0.6b3",
|
|
21
21
|
author="CMCC Data Delivery System Team",
|
|
22
22
|
author_email="dds-support@cmcc.it",
|
|
23
23
|
description=(
|
|
@@ -32,7 +32,7 @@ setuptools.setup(
|
|
|
32
32
|
"netCDF4>=1.5.3",
|
|
33
33
|
"scipy>=1.5.2",
|
|
34
34
|
"requests>=2.23.0",
|
|
35
|
-
"xarray
|
|
35
|
+
"xarray>=0.16.0",
|
|
36
36
|
],
|
|
37
37
|
classifiers=[
|
|
38
38
|
"Development Status :: 4 - Beta",
|
|
File without changes
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from unittest import mock
|
|
5
|
+
|
|
6
|
+
from ddsapi.api import Config, EnvVarNames
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _read_config_mock(*ar) -> dict:
|
|
10
|
+
return {
|
|
11
|
+
"url": "url_from_file",
|
|
12
|
+
"key": "key_from_file",
|
|
13
|
+
"verify": "0",
|
|
14
|
+
"cachedir": "cachedir_from_file",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _read_config_mock2(*ar) -> dict:
|
|
19
|
+
return {
|
|
20
|
+
"url": "url_from_file",
|
|
21
|
+
"key": "key_from_file",
|
|
22
|
+
"verify": "0",
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@mock.patch.dict(os.environ, {EnvVarNames.URL: "dds-url"})
|
|
27
|
+
@mock.patch("ddsapi.api.read_config", return_value={})
|
|
28
|
+
def test_get_url_from_env_var(read_config):
|
|
29
|
+
conf = Config()
|
|
30
|
+
assert conf.url == "dds-url"
|
|
31
|
+
assert conf.key is None
|
|
32
|
+
assert conf.cachedir == os.path.expanduser(
|
|
33
|
+
os.path.join("~", Config._CACHE_FILENAME)
|
|
34
|
+
)
|
|
35
|
+
assert conf.verify == 1
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@mock.patch.dict(os.environ, {EnvVarNames.KEY: "dds-key"})
|
|
39
|
+
@mock.patch("ddsapi.api.read_config", return_value={})
|
|
40
|
+
def test_get_key_from_env_var(read_config):
|
|
41
|
+
conf = Config()
|
|
42
|
+
assert conf.key == "dds-key"
|
|
43
|
+
assert conf.url is None
|
|
44
|
+
assert conf.cachedir == os.path.expanduser(
|
|
45
|
+
os.path.join("~", Config._CACHE_FILENAME)
|
|
46
|
+
)
|
|
47
|
+
assert conf.verify == 1
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@mock.patch.dict(os.environ, {EnvVarNames.CACHEDIR: "dds-cache"})
|
|
51
|
+
@mock.patch("ddsapi.api.read_config", return_value={})
|
|
52
|
+
def test_get_cache_from_env_var(read_config):
|
|
53
|
+
conf = Config()
|
|
54
|
+
assert conf.cachedir == "dds-cache"
|
|
55
|
+
assert conf.key is None
|
|
56
|
+
assert conf.url is None
|
|
57
|
+
assert conf.verify == 1
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@mock.patch("ddsapi.api.read_config", _read_config_mock)
|
|
61
|
+
def test_read_conf_from_rc_file():
|
|
62
|
+
conf = Config()
|
|
63
|
+
assert conf.key == "key_from_file"
|
|
64
|
+
assert conf.url == "url_from_file"
|
|
65
|
+
assert conf.cachedir == "cachedir_from_file"
|
|
66
|
+
assert conf.verify == 0
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@mock.patch.dict(os.environ, {EnvVarNames.CACHEDIR: "dds-cache"})
|
|
70
|
+
@mock.patch("ddsapi.api.read_config", _read_config_mock2)
|
|
71
|
+
def test_conf_from_file_overwrites():
|
|
72
|
+
conf = Config()
|
|
73
|
+
assert conf.key == "key_from_file"
|
|
74
|
+
assert conf.url == "url_from_file"
|
|
75
|
+
assert conf.cachedir == "dds-cache"
|
|
76
|
+
assert conf.verify == 0
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@mock.patch.dict(os.environ, {EnvVarNames.KEY: "key0"})
|
|
80
|
+
@mock.patch("ddsapi.api.read_config", return_value={"key": "key1"})
|
|
81
|
+
def test_user_defined_overwrites_all(read_config):
|
|
82
|
+
conf = Config(key="key2")
|
|
83
|
+
assert conf.key == "key2"
|
|
84
|
+
assert conf.url is None
|
|
85
|
+
assert conf.cachedir == os.path.expanduser(
|
|
86
|
+
os.path.join("~", Config._CACHE_FILENAME)
|
|
87
|
+
)
|
|
88
|
+
assert conf.verify == 1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|