ecmwf-datastores-client 0.1.0__tar.gz → 0.3.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.

Potentially problematic release.


This version of ecmwf-datastores-client might be problematic. Click here for more details.

Files changed (54) hide show
  1. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/.cruft.json +2 -2
  2. ecmwf_datastores_client-0.3.0/.github/workflows/on-pr-closed.yml +18 -0
  3. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/.github/workflows/on-push.yml +15 -4
  4. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/.pre-commit-config.yaml +7 -2
  5. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/Makefile +1 -0
  6. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/PKG-INFO +15 -29
  7. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/README.md +13 -27
  8. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/ci/environment-ci.yml +3 -2
  9. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/docs/conf.py +1 -0
  10. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/docs/index.md +1 -0
  11. ecmwf_datastores_client-0.3.0/docs/notebooks/index.md +7 -0
  12. ecmwf_datastores_client-0.3.0/docs/notebooks/quick_start.ipynb +45 -0
  13. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/ecmwf/datastores/catalogue.py +0 -11
  14. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/ecmwf/datastores/client.py +21 -4
  15. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/ecmwf/datastores/processing.py +8 -69
  16. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/ecmwf/datastores/version.py +1 -1
  17. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/ecmwf_datastores_client.egg-info/PKG-INFO +15 -29
  18. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/ecmwf_datastores_client.egg-info/SOURCES.txt +5 -2
  19. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/ecmwf_datastores_client.egg-info/requires.txt +1 -1
  20. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/pyproject.toml +1 -1
  21. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/tests/conftest.py +1 -4
  22. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/tests/integration_test_20_processing.py +7 -6
  23. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/tests/integration_test_30_remote.py +0 -6
  24. ecmwf_datastores_client-0.1.0/tests/integration_test_60_api_client.py → ecmwf_datastores_client-0.3.0/tests/integration_test_60_client.py +9 -9
  25. ecmwf_datastores_client-0.1.0/tests/integration_test_70_legacy_api_client.py → ecmwf_datastores_client-0.3.0/tests/integration_test_70_legacy_client.py +13 -13
  26. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/tests/test_20_processing.py +6 -28
  27. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/.gitignore +0 -0
  28. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/.pre-commit-config-cruft.yaml +0 -0
  29. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/Dockerfile +0 -0
  30. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/LICENSE +0 -0
  31. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/ci/environment-integration.yml +0 -0
  32. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/docs/Makefile +0 -0
  33. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/docs/_static/.gitkeep +0 -0
  34. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/docs/_templates/.gitkeep +0 -0
  35. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/docs/make.bat +0 -0
  36. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/ecmwf/datastores/__init__.py +0 -0
  37. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/ecmwf/datastores/config.py +0 -0
  38. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/ecmwf/datastores/legacy_client.py +0 -0
  39. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/ecmwf/datastores/profile.py +0 -0
  40. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/ecmwf/datastores/py.typed +0 -0
  41. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/ecmwf/datastores/utils.py +0 -0
  42. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/ecmwf_datastores_client.egg-info/dependency_links.txt +0 -0
  43. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/ecmwf_datastores_client.egg-info/top_level.txt +0 -0
  44. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/environment.yml +0 -0
  45. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/setup.cfg +0 -0
  46. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/tests/integration_test_10_catalogue.py +0 -0
  47. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/tests/integration_test_40_results.py +0 -0
  48. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/tests/integration_test_50_profile.py +0 -0
  49. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/tests/integration_test_80_adaptors.py +0 -0
  50. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/tests/integration_test_90_features.py +0 -0
  51. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/tests/test_00_version.py +0 -0
  52. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/tests/test_01_config.py +0 -0
  53. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/tests/test_10_catalogue.py +0 -0
  54. {ecmwf_datastores_client-0.1.0 → ecmwf_datastores_client-0.3.0}/tests/test_40_results.py +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "template": "https://github.com/ecmwf-projects/cookiecutter-conda-package",
3
- "commit": "18065cb3d40660d1b7d74ac1cbe285f08552e658",
3
+ "commit": "0b4d61da26c3aacfc1778716cb36749d16846c51",
4
4
  "checkout": null,
5
5
  "context": {
6
6
  "cookiecutter": {
@@ -13,7 +13,7 @@
13
13
  "integration_tests": "True",
14
14
  "pypi": true,
15
15
  "_template": "https://github.com/ecmwf-projects/cookiecutter-conda-package",
16
- "_commit": "18065cb3d40660d1b7d74ac1cbe285f08552e658"
16
+ "_commit": "0b4d61da26c3aacfc1778716cb36749d16846c51"
17
17
  }
18
18
  },
19
19
  "directory": null
@@ -0,0 +1,18 @@
1
+ name: on-pr-closed
2
+ on:
3
+ pull_request:
4
+ types:
5
+ - closed
6
+
7
+ jobs:
8
+ remove-preview:
9
+ runs-on: ubuntu-latest
10
+ permissions:
11
+ contents: write
12
+ pull-requests: write
13
+
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: rossjrw/pr-preview-action@v1
17
+ with:
18
+ action: "remove"
@@ -117,6 +117,7 @@ jobs:
117
117
  runs-on: macos-latest
118
118
  permissions:
119
119
  contents: write
120
+ pull-requests: write
120
121
 
121
122
  steps:
122
123
  - uses: actions/checkout@v4
@@ -140,16 +141,26 @@ jobs:
140
141
  run: |
141
142
  python -m pip install --no-deps -e .
142
143
  - name: Build documentation
144
+ timeout-minutes: 10
145
+ env:
146
+ ECMWF_DATASTORES_URL: ${{ secrets.ECMWF_DATASTORES_URL }}
147
+ ECMWF_DATASTORES_KEY: ${{ secrets.ECMWF_DATASTORES_KEY }}
148
+ ANONYMOUS_PAT: ${{ secrets.ECMWF_DATASTORES_ANON_KEY }}
143
149
  run: |
144
150
  make docs-build
151
+ - uses: rossjrw/pr-preview-action@v1
152
+ with:
153
+ source-dir: "docs/_build/html"
145
154
  - name: Deploy documentation
146
- uses: peaceiris/actions-gh-pages@v4
155
+ uses: JamesIves/github-pages-deploy-action@v4
147
156
  if: |
148
157
  github.event_name == 'push' &&
149
158
  startsWith(github.ref, 'refs/tags')
150
159
  with:
151
- github_token: ${{ secrets.GITHUB_TOKEN }}
152
- publish_dir: ./docs/_build/html/
160
+ folder: ./docs/_build/html/
161
+ # See: https://github.com/marketplace/actions/deploy-pr-preview#ensure-your-main-deployment-is-compatible
162
+ clean-exclude: pr-preview/
163
+ force: false
153
164
 
154
165
  integration-tests:
155
166
  needs: [combine-environments, unit-tests]
@@ -188,7 +199,7 @@ jobs:
188
199
  env:
189
200
  ECMWF_DATASTORES_URL: ${{ secrets.ECMWF_DATASTORES_URL }}
190
201
  ECMWF_DATASTORES_KEY: ${{ secrets.ECMWF_DATASTORES_KEY }}
191
- ECMWF_DATASTORES_ANON_KEY: ${{ secrets.ECMWF_DATASTORES_ANON_KEY }}
202
+ ANONYMOUS_PAT: ${{ secrets.ECMWF_DATASTORES_ANON_KEY }}
192
203
  run: |
193
204
  make ci-integration-tests COV_REPORT=xml
194
205
 
@@ -17,7 +17,7 @@ repos:
17
17
  - id: blackdoc
18
18
  additional_dependencies: [black==23.11.0]
19
19
  - repo: https://github.com/astral-sh/ruff-pre-commit
20
- rev: v0.11.8
20
+ rev: v0.11.12
21
21
  hooks:
22
22
  - id: ruff
23
23
  args: [--fix, --show-fixes]
@@ -34,6 +34,11 @@ repos:
34
34
  - id: pretty-format-toml
35
35
  args: [--autofix]
36
36
  - repo: https://github.com/gitleaks/gitleaks
37
- rev: v8.25.1
37
+ rev: v8.27.0
38
38
  hooks:
39
39
  - id: gitleaks
40
+ - repo: https://github.com/kynan/nbstripout
41
+ rev: 0.8.1
42
+ hooks:
43
+ - id: nbstripout
44
+ args: [--drop-empty-cells]
@@ -26,6 +26,7 @@ docker-run:
26
26
  docker run --rm -ti -v $(PWD):/srv $(PROJECT)
27
27
 
28
28
  template-update:
29
+ pre-commit autoupdate --repo https://github.com/kynan/nbstripout
29
30
  pre-commit run --all-files cruft -c .pre-commit-config-cruft.yaml
30
31
 
31
32
  docs-build:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ecmwf-datastores-client
3
- Version: 0.1.0
3
+ Version: 0.3.0
4
4
  Summary: ECMWF Data Stores Service (DSS) API Python client
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -228,25 +228,20 @@ Requires-Dist: multiurl>=0.3.2
228
228
  Requires-Dist: requests
229
229
  Requires-Dist: typing-extensions
230
230
  Provides-Extra: legacy
231
- Requires-Dist: cdsapi>=0.7.5; extra == "legacy"
231
+ Requires-Dist: cdsapi>=0.7.6; extra == "legacy"
232
232
  Dynamic: license-file
233
233
 
234
234
  <p align="center">
235
235
  <a href="https://github.com/ecmwf/codex/raw/refs/heads/main/ESEE">
236
- <img src="https://github.com/ecmwf/codex/raw/refs/heads/main/ESEE/data_provision_badge.svg" alt="ECMWF Software EnginE">
237
- </a>
236
+ <img src="https://github.com/ecmwf/codex/raw/refs/heads/main/ESEE/data_provision_badge.svg" alt="ECMWF Software EnginE"></a>
238
237
  <a href="https://github.com/ecmwf/codex/raw/refs/heads/main/Project Maturity">
239
- <img src="https://github.com/ecmwf/codex/raw/refs/heads/main/Project Maturity/incubating_badge.svg" alt="Maturity Level">
240
- </a>
241
- <!-- <a href="https://codecov.io/gh/ecmwf/earthkit">
242
- <img src="https://codecov.io/gh/ecmwf/ecmwf-datastores-client/branch/main/graph/badge.svg" alt="Code Coverage">
243
- </a> -->
238
+ <img src="https://github.com/ecmwf/codex/raw/refs/heads/main/Project Maturity/incubating_badge.svg" alt="Maturity Level"></a>
239
+ <!-- <a href="https://codecov.io/gh/ecmwf/ecmwf-datastores-client">
240
+ <img src="https://codecov.io/gh/ecmwf/ecmwf-datastores-client/branch/main/graph/badge.svg" alt="Code Coverage"></a> -->
244
241
  <a href="https://opensource.org/licenses/apache-2-0">
245
- <img src="https://img.shields.io/badge/Licence-Apache 2.0-blue.svg" alt="Licence">
246
- </a>
247
- <a href="https://github.com/ecmwf/earthkit/releases">
248
- <img src="https://img.shields.io/github/v/release/ecmwf/ecmwf-datastores-client?color=purple&label=Release" alt="Latest Release">
249
- </a>
242
+ <img src="https://img.shields.io/badge/Licence-Apache 2.0-blue.svg" alt="Licence"></a>
243
+ <a href="https://github.com/ecmwf/ecmwf-datastores-client/releases">
244
+ <img src="https://img.shields.io/github/v/release/ecmwf/ecmwf-datastores-client?color=purple&label=Release" alt="Latest Release"></a>
250
245
  </p>
251
246
 
252
247
  <p align="center">
@@ -282,8 +277,11 @@ $ pip install ecmwf-datastores-client
282
277
 
283
278
  ## Configuration
284
279
 
285
- The `Client` requires the `url` to the API root and a valid API `key`. You can also set the `ECMWF_DATASTORES_URL` and `ECMWF_DATASTORES_KEY` environment variables, or use a configuration file.
286
- The configuration file must be located at `~/.ecmwfdatastoresrc`, or at the path specified by the `ECMWF_DATASTORES_RC_FILE` environment variable.
280
+ The `Client` requires the `url` to the API root and a valid API `key`. These can be provided in three ways, in order of precedence:
281
+
282
+ 1. As keyword arguments when instantiating the `Client`.
283
+ 1. Via the `ECMWF_DATASTORES_URL` and `ECMWF_DATASTORES_KEY` environment variables.
284
+ 1. From a configuration file, which must be located at `~/.ecmwfdatastoresrc` or at the path specified by the `ECMWF_DATASTORES_RC_FILE` environment variable.
287
285
 
288
286
  ```
289
287
  $ cat $HOME/.ecmwfdatastoresrc
@@ -291,14 +289,6 @@ url: https://cds.climate.copernicus.eu/api
291
289
  key: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
292
290
  ```
293
291
 
294
- It is possible (though not recommended) to use the API key of one of the test users:
295
-
296
- ```
297
- 00112233-4455-6677-c899-aabbccddeeff
298
- ```
299
-
300
- This key is used for anonymous tests and is designed to be the least performant option for accessing the system.
301
-
302
292
  ## Quick Start
303
293
 
304
294
  Configure the logging level to display INFO messages:
@@ -312,12 +302,8 @@ Configure the logging level to display INFO messages:
312
302
  Instantiate the API client and optionally verify authentication:
313
303
 
314
304
  ```python
315
- >>> import os
316
305
  >>> from ecmwf.datastores import Client
317
- >>> client = Client(
318
- ... url=os.getenv("ECMWF_DATASTORES_URL"),
319
- ... key=os.getenv("ECMWF_DATASTORES_KEY"),
320
- ... )
306
+ >>> client = Client()
321
307
  >>> client.check_authentication() # optional check
322
308
  {...}
323
309
 
@@ -1,19 +1,14 @@
1
1
  <p align="center">
2
2
  <a href="https://github.com/ecmwf/codex/raw/refs/heads/main/ESEE">
3
- <img src="https://github.com/ecmwf/codex/raw/refs/heads/main/ESEE/data_provision_badge.svg" alt="ECMWF Software EnginE">
4
- </a>
3
+ <img src="https://github.com/ecmwf/codex/raw/refs/heads/main/ESEE/data_provision_badge.svg" alt="ECMWF Software EnginE"></a>
5
4
  <a href="https://github.com/ecmwf/codex/raw/refs/heads/main/Project Maturity">
6
- <img src="https://github.com/ecmwf/codex/raw/refs/heads/main/Project Maturity/incubating_badge.svg" alt="Maturity Level">
7
- </a>
8
- <!-- <a href="https://codecov.io/gh/ecmwf/earthkit">
9
- <img src="https://codecov.io/gh/ecmwf/ecmwf-datastores-client/branch/main/graph/badge.svg" alt="Code Coverage">
10
- </a> -->
5
+ <img src="https://github.com/ecmwf/codex/raw/refs/heads/main/Project Maturity/incubating_badge.svg" alt="Maturity Level"></a>
6
+ <!-- <a href="https://codecov.io/gh/ecmwf/ecmwf-datastores-client">
7
+ <img src="https://codecov.io/gh/ecmwf/ecmwf-datastores-client/branch/main/graph/badge.svg" alt="Code Coverage"></a> -->
11
8
  <a href="https://opensource.org/licenses/apache-2-0">
12
- <img src="https://img.shields.io/badge/Licence-Apache 2.0-blue.svg" alt="Licence">
13
- </a>
14
- <a href="https://github.com/ecmwf/earthkit/releases">
15
- <img src="https://img.shields.io/github/v/release/ecmwf/ecmwf-datastores-client?color=purple&label=Release" alt="Latest Release">
16
- </a>
9
+ <img src="https://img.shields.io/badge/Licence-Apache 2.0-blue.svg" alt="Licence"></a>
10
+ <a href="https://github.com/ecmwf/ecmwf-datastores-client/releases">
11
+ <img src="https://img.shields.io/github/v/release/ecmwf/ecmwf-datastores-client?color=purple&label=Release" alt="Latest Release"></a>
17
12
  </p>
18
13
 
19
14
  <p align="center">
@@ -49,8 +44,11 @@ $ pip install ecmwf-datastores-client
49
44
 
50
45
  ## Configuration
51
46
 
52
- The `Client` requires the `url` to the API root and a valid API `key`. You can also set the `ECMWF_DATASTORES_URL` and `ECMWF_DATASTORES_KEY` environment variables, or use a configuration file.
53
- The configuration file must be located at `~/.ecmwfdatastoresrc`, or at the path specified by the `ECMWF_DATASTORES_RC_FILE` environment variable.
47
+ The `Client` requires the `url` to the API root and a valid API `key`. These can be provided in three ways, in order of precedence:
48
+
49
+ 1. As keyword arguments when instantiating the `Client`.
50
+ 1. Via the `ECMWF_DATASTORES_URL` and `ECMWF_DATASTORES_KEY` environment variables.
51
+ 1. From a configuration file, which must be located at `~/.ecmwfdatastoresrc` or at the path specified by the `ECMWF_DATASTORES_RC_FILE` environment variable.
54
52
 
55
53
  ```
56
54
  $ cat $HOME/.ecmwfdatastoresrc
@@ -58,14 +56,6 @@ url: https://cds.climate.copernicus.eu/api
58
56
  key: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
59
57
  ```
60
58
 
61
- It is possible (though not recommended) to use the API key of one of the test users:
62
-
63
- ```
64
- 00112233-4455-6677-c899-aabbccddeeff
65
- ```
66
-
67
- This key is used for anonymous tests and is designed to be the least performant option for accessing the system.
68
-
69
59
  ## Quick Start
70
60
 
71
61
  Configure the logging level to display INFO messages:
@@ -79,12 +69,8 @@ Configure the logging level to display INFO messages:
79
69
  Instantiate the API client and optionally verify authentication:
80
70
 
81
71
  ```python
82
- >>> import os
83
72
  >>> from ecmwf.datastores import Client
84
- >>> client = Client(
85
- ... url=os.getenv("ECMWF_DATASTORES_URL"),
86
- ... key=os.getenv("ECMWF_DATASTORES_KEY"),
87
- ... )
73
+ >>> client = Client()
88
74
  >>> client.check_authentication() # optional check
89
75
  {...}
90
76
 
@@ -14,8 +14,9 @@ dependencies:
14
14
  - sphinx
15
15
  - sphinx-autoapi
16
16
  # DO NOT EDIT ABOVE THIS LINE, ADD DEPENDENCIES BELOW
17
+ - ipykernel
18
+ - nbsphinx
17
19
  - types-requests
18
20
  - pip:
19
- # TODO: install from pypi or conda when available
20
- - git+https://github.com/bopen/cdsapi.git@COPDS-2640
21
+ - cdsapi >= 0.7.6
21
22
  - responses
@@ -29,6 +29,7 @@ release = ecmwf.datastores.__version__
29
29
  extensions = [
30
30
  "autoapi.extension",
31
31
  "myst_parser",
32
+ "nbsphinx",
32
33
  "sphinx.ext.autodoc",
33
34
  "sphinx.ext.napoleon",
34
35
  ]
@@ -11,6 +11,7 @@ Knowledge Base.
11
11
  :maxdepth: 2
12
12
 
13
13
  README.md
14
+ notebooks/index
14
15
  API Reference <_api/datastores/index>
15
16
  ```
16
17
 
@@ -0,0 +1,7 @@
1
+ # Notebooks
2
+
3
+ ```{toctree}
4
+ :maxdepth: 1
5
+
6
+ quick_start
7
+ ```
@@ -0,0 +1,45 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "0",
6
+ "metadata": {},
7
+ "source": [
8
+ "# Quick start"
9
+ ]
10
+ },
11
+ {
12
+ "cell_type": "code",
13
+ "execution_count": null,
14
+ "id": "1",
15
+ "metadata": {},
16
+ "outputs": [],
17
+ "source": [
18
+ "from ecmwf.datastores import Client\n",
19
+ "\n",
20
+ "client = Client()"
21
+ ]
22
+ }
23
+ ],
24
+ "metadata": {
25
+ "kernelspec": {
26
+ "display_name": "Python 3 (ipykernel)",
27
+ "language": "python",
28
+ "name": "python3"
29
+ },
30
+ "language_info": {
31
+ "codemirror_mode": {
32
+ "name": "ipython",
33
+ "version": 3
34
+ },
35
+ "file_extension": ".py",
36
+ "mimetype": "text/x-python",
37
+ "name": "python",
38
+ "nbconvert_exporter": "python",
39
+ "pygments_lexer": "ipython3",
40
+ "version": "3.11.11"
41
+ }
42
+ },
43
+ "nbformat": 4,
44
+ "nbformat_minor": 5
45
+ }
@@ -15,7 +15,6 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  import datetime
18
- import warnings
19
18
  from typing import Any, Callable
20
19
 
21
20
  import attrs
@@ -93,16 +92,6 @@ class Collection(ApiResponse):
93
92
  url = self._get_link_href(rel="retrieve")
94
93
  return datastores.Process.from_request("get", url, **self._request_kwargs)
95
94
 
96
- @property
97
- def process(self) -> datastores.Process:
98
- warnings.warn(
99
- "`process` has been deprecated, and in the future will raise an error."
100
- "Please use `submit` and `apply_constraints` from now on.",
101
- DeprecationWarning,
102
- stacklevel=2,
103
- )
104
- return self._process
105
-
106
95
  @property
107
96
  def form(self) -> list[dict[str, Any]]:
108
97
  url = f"{self.url}/form.json"
@@ -28,6 +28,8 @@ from ecmwf.datastores.catalogue import Catalogue
28
28
  from ecmwf.datastores.processing import Processing, RequestKwargs
29
29
  from ecmwf.datastores.profile import Profile
30
30
 
31
+ T_STATUS = Literal["accepted", "running", "successful", "failed", "rejected"]
32
+
31
33
 
32
34
  @attrs.define(slots=False)
33
35
  class Client:
@@ -179,6 +181,21 @@ class Client:
179
181
  """
180
182
  return self._profile_api.check_authentication()
181
183
 
184
+ def delete(self, *request_ids: str) -> dict[str, Any]:
185
+ """Delete requests.
186
+
187
+ Parameters
188
+ ----------
189
+ *request_ids: str
190
+ Request IDs.
191
+
192
+ Returns
193
+ -------
194
+ dict[str,Any]
195
+ Content of the response.
196
+ """
197
+ return self._retrieve_api.delete(*request_ids)
198
+
182
199
  def download_results(self, request_id: str, target: str | None = None) -> str:
183
200
  """Download the results of a request.
184
201
 
@@ -234,7 +251,7 @@ class Client:
234
251
  Parameters
235
252
  ----------
236
253
  limit: int | None
237
- Number of processes per page.
254
+ Number of collections per page.
238
255
  sortby: {None, 'id', 'relevance', 'title', 'update'}
239
256
  Field to sort results by.
240
257
  query: str or None
@@ -259,17 +276,17 @@ class Client:
259
276
  self,
260
277
  limit: int | None = None,
261
278
  sortby: Literal[None, "created", "-created"] = None,
262
- status: Literal[None, "accepted", "running", "successful", "failed"] = None,
279
+ status: None | T_STATUS | list[T_STATUS] = None,
263
280
  ) -> datastores.Jobs:
264
281
  """Retrieve submitted jobs.
265
282
 
266
283
  Parameters
267
284
  ----------
268
285
  limit: int or None
269
- Number of processes per page.
286
+ Number of jobs per page.
270
287
  sortby: {None, 'created', '-created'}
271
288
  Field to sort results by.
272
- status: {None, 'accepted', 'running', 'successful', 'failed'}
289
+ status: None or {'accepted', 'running', 'successful', 'failed', 'rejected'} or list
273
290
  Status of the results.
274
291
 
275
292
  Returns
@@ -400,16 +400,6 @@ class Remote:
400
400
  """Request ID."""
401
401
  return self.url.rpartition("/")[2]
402
402
 
403
- @property
404
- def request_uid(self) -> str:
405
- warnings.warn(
406
- "`request_uid` has been deprecated, and in the future will raise an error."
407
- "Please use `request_id` from now on.",
408
- DeprecationWarning,
409
- stacklevel=2,
410
- )
411
- return self.request_id
412
-
413
403
  @property
414
404
  def json(self) -> dict[str, Any]:
415
405
  """Content of the response."""
@@ -450,48 +440,18 @@ class Remote:
450
440
  """When the job was created."""
451
441
  return utils.string_to_datetime(self.json["created"])
452
442
 
453
- @property
454
- def creation_datetime(self) -> datetime.datetime:
455
- warnings.warn(
456
- "`creation_datetime` has been deprecated, and in the future will raise an error."
457
- "Please use `created_at` from now on.",
458
- DeprecationWarning,
459
- stacklevel=2,
460
- )
461
- return self.created_at
462
-
463
443
  @property
464
444
  def started_at(self) -> datetime.datetime | None:
465
445
  """When the job started. If None, the job has not started."""
466
446
  value = self.json.get("started")
467
447
  return value if value is None else utils.string_to_datetime(value)
468
448
 
469
- @property
470
- def start_datetime(self) -> datetime.datetime | None:
471
- warnings.warn(
472
- "`start_datetime` has been deprecated, and in the future will raise an error."
473
- "Please use `started_at` from now on.",
474
- DeprecationWarning,
475
- stacklevel=2,
476
- )
477
- return self.started_at
478
-
479
449
  @property
480
450
  def finished_at(self) -> datetime.datetime | None:
481
451
  """When the job finished. If None, the job has not finished."""
482
452
  value = self.json.get("finished")
483
453
  return value if value is None else utils.string_to_datetime(value)
484
454
 
485
- @property
486
- def end_datetime(self) -> datetime.datetime | None:
487
- warnings.warn(
488
- "`end_datetime` has been deprecated, and in the future will raise an error."
489
- "Please use `finished_at` from now on.",
490
- DeprecationWarning,
491
- stacklevel=2,
492
- )
493
- return self.finished_at
494
-
495
455
  def _wait_on_results(self) -> None:
496
456
  sleep = 1.0
497
457
  while not self.results_ready:
@@ -507,7 +467,7 @@ class Remote:
507
467
  return True
508
468
  if status in ("accepted", "running"):
509
469
  return False
510
- if status == "failed":
470
+ if status in ("failed", "rejected"):
511
471
  results = self._make_results(wait=False)
512
472
  raise ProcessingFailedError(error_json_to_message(results._json_dict))
513
473
  if status in ("dismissed", "deleted"):
@@ -525,15 +485,6 @@ class Remote:
525
485
  results = Results.from_request("get", results_url, **self._request_kwargs)
526
486
  return results
527
487
 
528
- def make_results(self, wait: bool = True) -> Results:
529
- warnings.warn(
530
- "`make_results` has been deprecated, and in the future will raise an error."
531
- "Please use `get_results` from now on.",
532
- DeprecationWarning,
533
- stacklevel=2,
534
- )
535
- return self._make_results(wait)
536
-
537
488
  def get_results(self) -> Results:
538
489
  """Retrieve results.
539
490
 
@@ -641,15 +592,6 @@ class Job(ApiResponse):
641
592
  url = self._get_link_href(rel="self")
642
593
  return Remote(url, **self._request_kwargs)
643
594
 
644
- def make_remote(self) -> Remote:
645
- warnings.warn(
646
- "`make_remote` has been deprecated, and in the future will raise an error."
647
- "Please use `get_remote` from now on.",
648
- DeprecationWarning,
649
- stacklevel=2,
650
- )
651
- return self.get_remote()
652
-
653
595
 
654
596
  @attrs.define
655
597
  class Jobs(ApiResponsePaginated):
@@ -660,16 +602,6 @@ class Jobs(ApiResponsePaginated):
660
602
  """List of request IDs."""
661
603
  return [job["jobID"] for job in self._json_dict["jobs"]]
662
604
 
663
- @property
664
- def request_uids(self) -> list[str]:
665
- warnings.warn(
666
- "`request_uids` has been deprecated, and in the future will raise an error."
667
- "Please use `request_ids` from now on.",
668
- DeprecationWarning,
669
- stacklevel=2,
670
- )
671
- return self.request_ids
672
-
673
605
 
674
606
  @attrs.define
675
607
  class Results(ApiResponse):
@@ -773,6 +705,13 @@ class Processing:
773
705
  log_callback=self.log_callback,
774
706
  )
775
707
 
708
+ def delete(self, *job_ids: str) -> dict[str, Any]:
709
+ url = f"{self.url}/jobs/delete"
710
+ response = ApiResponse.from_request(
711
+ "post", url, json={"job_ids": job_ids}, **self._request_kwargs
712
+ )
713
+ return response._json_dict
714
+
776
715
  def get_processes(self, **params: Any) -> Processes:
777
716
  url = f"{self.url}/processes"
778
717
  return Processes.from_request("get", url, params=params, **self._request_kwargs)
@@ -1,2 +1,2 @@
1
1
  # Do not change! Do not track in version control!
2
- __version__ = "0.1.0"
2
+ __version__ = "0.3.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ecmwf-datastores-client
3
- Version: 0.1.0
3
+ Version: 0.3.0
4
4
  Summary: ECMWF Data Stores Service (DSS) API Python client
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -228,25 +228,20 @@ Requires-Dist: multiurl>=0.3.2
228
228
  Requires-Dist: requests
229
229
  Requires-Dist: typing-extensions
230
230
  Provides-Extra: legacy
231
- Requires-Dist: cdsapi>=0.7.5; extra == "legacy"
231
+ Requires-Dist: cdsapi>=0.7.6; extra == "legacy"
232
232
  Dynamic: license-file
233
233
 
234
234
  <p align="center">
235
235
  <a href="https://github.com/ecmwf/codex/raw/refs/heads/main/ESEE">
236
- <img src="https://github.com/ecmwf/codex/raw/refs/heads/main/ESEE/data_provision_badge.svg" alt="ECMWF Software EnginE">
237
- </a>
236
+ <img src="https://github.com/ecmwf/codex/raw/refs/heads/main/ESEE/data_provision_badge.svg" alt="ECMWF Software EnginE"></a>
238
237
  <a href="https://github.com/ecmwf/codex/raw/refs/heads/main/Project Maturity">
239
- <img src="https://github.com/ecmwf/codex/raw/refs/heads/main/Project Maturity/incubating_badge.svg" alt="Maturity Level">
240
- </a>
241
- <!-- <a href="https://codecov.io/gh/ecmwf/earthkit">
242
- <img src="https://codecov.io/gh/ecmwf/ecmwf-datastores-client/branch/main/graph/badge.svg" alt="Code Coverage">
243
- </a> -->
238
+ <img src="https://github.com/ecmwf/codex/raw/refs/heads/main/Project Maturity/incubating_badge.svg" alt="Maturity Level"></a>
239
+ <!-- <a href="https://codecov.io/gh/ecmwf/ecmwf-datastores-client">
240
+ <img src="https://codecov.io/gh/ecmwf/ecmwf-datastores-client/branch/main/graph/badge.svg" alt="Code Coverage"></a> -->
244
241
  <a href="https://opensource.org/licenses/apache-2-0">
245
- <img src="https://img.shields.io/badge/Licence-Apache 2.0-blue.svg" alt="Licence">
246
- </a>
247
- <a href="https://github.com/ecmwf/earthkit/releases">
248
- <img src="https://img.shields.io/github/v/release/ecmwf/ecmwf-datastores-client?color=purple&label=Release" alt="Latest Release">
249
- </a>
242
+ <img src="https://img.shields.io/badge/Licence-Apache 2.0-blue.svg" alt="Licence"></a>
243
+ <a href="https://github.com/ecmwf/ecmwf-datastores-client/releases">
244
+ <img src="https://img.shields.io/github/v/release/ecmwf/ecmwf-datastores-client?color=purple&label=Release" alt="Latest Release"></a>
250
245
  </p>
251
246
 
252
247
  <p align="center">
@@ -282,8 +277,11 @@ $ pip install ecmwf-datastores-client
282
277
 
283
278
  ## Configuration
284
279
 
285
- The `Client` requires the `url` to the API root and a valid API `key`. You can also set the `ECMWF_DATASTORES_URL` and `ECMWF_DATASTORES_KEY` environment variables, or use a configuration file.
286
- The configuration file must be located at `~/.ecmwfdatastoresrc`, or at the path specified by the `ECMWF_DATASTORES_RC_FILE` environment variable.
280
+ The `Client` requires the `url` to the API root and a valid API `key`. These can be provided in three ways, in order of precedence:
281
+
282
+ 1. As keyword arguments when instantiating the `Client`.
283
+ 1. Via the `ECMWF_DATASTORES_URL` and `ECMWF_DATASTORES_KEY` environment variables.
284
+ 1. From a configuration file, which must be located at `~/.ecmwfdatastoresrc` or at the path specified by the `ECMWF_DATASTORES_RC_FILE` environment variable.
287
285
 
288
286
  ```
289
287
  $ cat $HOME/.ecmwfdatastoresrc
@@ -291,14 +289,6 @@ url: https://cds.climate.copernicus.eu/api
291
289
  key: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
292
290
  ```
293
291
 
294
- It is possible (though not recommended) to use the API key of one of the test users:
295
-
296
- ```
297
- 00112233-4455-6677-c899-aabbccddeeff
298
- ```
299
-
300
- This key is used for anonymous tests and is designed to be the least performant option for accessing the system.
301
-
302
292
  ## Quick Start
303
293
 
304
294
  Configure the logging level to display INFO messages:
@@ -312,12 +302,8 @@ Configure the logging level to display INFO messages:
312
302
  Instantiate the API client and optionally verify authentication:
313
303
 
314
304
  ```python
315
- >>> import os
316
305
  >>> from ecmwf.datastores import Client
317
- >>> client = Client(
318
- ... url=os.getenv("ECMWF_DATASTORES_URL"),
319
- ... key=os.getenv("ECMWF_DATASTORES_KEY"),
320
- ... )
306
+ >>> client = Client()
321
307
  >>> client.check_authentication() # optional check
322
308
  {...}
323
309
 
@@ -8,6 +8,7 @@ Makefile
8
8
  README.md
9
9
  environment.yml
10
10
  pyproject.toml
11
+ .github/workflows/on-pr-closed.yml
11
12
  .github/workflows/on-push.yml
12
13
  ci/environment-ci.yml
13
14
  ci/environment-integration.yml
@@ -17,6 +18,8 @@ docs/index.md
17
18
  docs/make.bat
18
19
  docs/_static/.gitkeep
19
20
  docs/_templates/.gitkeep
21
+ docs/notebooks/index.md
22
+ docs/notebooks/quick_start.ipynb
20
23
  ecmwf/datastores/__init__.py
21
24
  ecmwf/datastores/catalogue.py
22
25
  ecmwf/datastores/client.py
@@ -38,8 +41,8 @@ tests/integration_test_20_processing.py
38
41
  tests/integration_test_30_remote.py
39
42
  tests/integration_test_40_results.py
40
43
  tests/integration_test_50_profile.py
41
- tests/integration_test_60_api_client.py
42
- tests/integration_test_70_legacy_api_client.py
44
+ tests/integration_test_60_client.py
45
+ tests/integration_test_70_legacy_client.py
43
46
  tests/integration_test_80_adaptors.py
44
47
  tests/integration_test_90_features.py
45
48
  tests/test_00_version.py
@@ -4,4 +4,4 @@ requests
4
4
  typing-extensions
5
5
 
6
6
  [legacy]
7
- cdsapi>=0.7.5
7
+ cdsapi>=0.7.6
@@ -32,7 +32,7 @@ readme = "README.md"
32
32
  requires-python = ">=3.8"
33
33
 
34
34
  [project.optional-dependencies]
35
- legacy = ["cdsapi >= 0.7.5"]
35
+ legacy = ["cdsapi >= 0.7.6"]
36
36
 
37
37
  [project.urls]
38
38
  documentation = "https://ecmwf.github.io/ecmwf-datastores-client/"
@@ -21,10 +21,7 @@ def api_root_url() -> str:
21
21
 
22
22
  @pytest.fixture
23
23
  def api_anon_key() -> str:
24
- return os.getenv(
25
- "ECMWF_DATASTORES_ANON_KEY",
26
- "00112233-4455-6677-c899-aabbccddeeff", # gitleaks:allow
27
- )
24
+ return os.getenv("ANONYMOUS_PAT", "00112233-4455-6677-c899-aabbccddeeff")
28
25
 
29
26
 
30
27
  @pytest.fixture
@@ -75,9 +75,10 @@ def test_processing_get_jobs_sortby(api_anon_client: Client) -> None:
75
75
  assert [id2] != api_anon_client.get_jobs(sortby="created", limit=1).request_ids
76
76
 
77
77
 
78
- def test_deprecation_warnings(api_anon_client: Client) -> None:
79
- with pytest.warns(DeprecationWarning):
80
- api_anon_client.submit("test-adaptor-dummy", {}).request_uid
81
-
82
- with pytest.warns(DeprecationWarning):
83
- api_anon_client.get_jobs().request_uids
78
+ def test_processing_delete(api_anon_client: Client) -> None:
79
+ id1 = api_anon_client.submit("test-adaptor-dummy", {}).request_id
80
+ id2 = api_anon_client.submit("test-adaptor-dummy", {}).request_id
81
+ job1, job2 = api_anon_client.delete(id1, id2)["jobs"]
82
+ assert job1["status"] == job2["status"] == "dismissed"
83
+ assert job1["jobID"] == id1
84
+ assert job2["jobID"] == id2
@@ -106,9 +106,3 @@ def test_remote_datetimes(api_anon_client: Client) -> None:
106
106
  assert remote.finished_at is not None
107
107
  assert remote.created_at < remote.started_at < remote.finished_at
108
108
  assert remote.finished_at == remote.updated_at
109
-
110
-
111
- def test_make_results_deprecation(api_anon_client: Client) -> None:
112
- remote = api_anon_client.submit("test-adaptor-dummy", {})
113
- with pytest.warns(DeprecationWarning, match="`make_results` has been deprecated"):
114
- remote.make_results()
@@ -9,7 +9,7 @@ from urllib3.exceptions import InsecureRequestWarning
9
9
  from ecmwf.datastores import Client, Remote, Results, processing
10
10
 
11
11
 
12
- def test_api_client_download_results(
12
+ def test_client_download_results(
13
13
  api_anon_client: Client, tmp_path: pathlib.Path
14
14
  ) -> None:
15
15
  remote = api_anon_client.submit("test-adaptor-dummy", {})
@@ -20,27 +20,27 @@ def test_api_client_download_results(
20
20
  assert os.path.exists(result)
21
21
 
22
22
 
23
- def test_api_client_get_process(api_anon_client: Client) -> None:
23
+ def test_client_get_process(api_anon_client: Client) -> None:
24
24
  process = api_anon_client.get_process("test-adaptor-dummy")
25
25
  assert isinstance(process, processing.Process)
26
26
  assert process.id == "test-adaptor-dummy"
27
27
  assert set(process.headers) == {"User-Agent", "PRIVATE-TOKEN"}
28
28
 
29
29
 
30
- def test_api_client_get_remote(api_anon_client: Client) -> None:
30
+ def test_client_get_remote(api_anon_client: Client) -> None:
31
31
  request_id = api_anon_client.submit("test-adaptor-dummy", {}).request_id
32
32
  remote = api_anon_client.get_remote(request_id)
33
33
  assert remote.request_id == request_id
34
34
  assert set(remote.headers) == {"User-Agent", "PRIVATE-TOKEN"}
35
35
 
36
36
 
37
- def test_api_client_get_results(api_anon_client: Client) -> None:
37
+ def test_client_get_results(api_anon_client: Client) -> None:
38
38
  request_id = api_anon_client.submit("test-adaptor-dummy", {}).request_id
39
39
  results = api_anon_client.get_results(request_id)
40
40
  assert isinstance(results, Results)
41
41
 
42
42
 
43
- def test_api_client_retrieve(
43
+ def test_client_retrieve(
44
44
  api_anon_client: Client,
45
45
  tmp_path: pathlib.Path,
46
46
  ) -> None:
@@ -54,24 +54,24 @@ def test_api_client_retrieve(
54
54
  assert os.path.getsize(actual_target) == 1
55
55
 
56
56
 
57
- def test_api_client_submit(api_anon_client: Client) -> None:
57
+ def test_client_submit(api_anon_client: Client) -> None:
58
58
  remote = api_anon_client.submit("test-adaptor-dummy", {})
59
59
  assert isinstance(remote, Remote)
60
60
 
61
61
 
62
- def test_api_client_submit_and_wait_on_results(api_anon_client: Client) -> None:
62
+ def test_client_submit_and_wait_on_results(api_anon_client: Client) -> None:
63
63
  results = api_anon_client.submit_and_wait_on_results("test-adaptor-dummy", {})
64
64
  assert isinstance(results, Results)
65
65
 
66
66
 
67
- def test_api_client_verify(api_root_url: str, api_anon_key: str) -> None:
67
+ def test_client_verify(api_root_url: str, api_anon_key: str) -> None:
68
68
  if not api_root_url.startswith("https"):
69
69
  pytest.skip(f"{api_root_url=} does not use https protocol")
70
70
  with pytest.warns(InsecureRequestWarning):
71
71
  Client(url=api_root_url, key=api_anon_key, verify=False, maximum_tries=0)
72
72
 
73
73
 
74
- def test_api_client_timeout(
74
+ def test_client_timeout(
75
75
  api_root_url: str,
76
76
  api_anon_key: str,
77
77
  tmp_path: pathlib.Path,
@@ -54,7 +54,7 @@ def legacy_update(remote: processing.Remote) -> None:
54
54
  )
55
55
 
56
56
 
57
- def test_legacy_api_client_retrieve(
57
+ def test_legacy_client_retrieve(
58
58
  tmp_path: pathlib.Path, legacy_client: LegacyClient
59
59
  ) -> None:
60
60
  collection_id = "test-adaptor-dummy"
@@ -65,7 +65,7 @@ def test_legacy_api_client_retrieve(
65
65
  assert os.path.getsize(target) == 1
66
66
 
67
67
 
68
- def test_legacy_api_client_result(
68
+ def test_legacy_client_result(
69
69
  monkeypatch: pytest.MonkeyPatch,
70
70
  tmp_path: pathlib.Path,
71
71
  legacy_client: LegacyClient,
@@ -92,7 +92,7 @@ def test_legacy_api_client_result(
92
92
 
93
93
 
94
94
  @pytest.mark.parametrize("quiet", [True, False])
95
- def test_legacy_api_client_quiet(
95
+ def test_legacy_client_quiet(
96
96
  caplog: pytest.LogCaptureFixture,
97
97
  api_root_url: str,
98
98
  api_anon_key: str,
@@ -105,7 +105,7 @@ def test_legacy_api_client_quiet(
105
105
 
106
106
 
107
107
  @pytest.mark.parametrize("debug", [True, False])
108
- def test_legacy_api_client_debug(
108
+ def test_legacy_client_debug(
109
109
  caplog: pytest.LogCaptureFixture,
110
110
  api_root_url: str,
111
111
  api_anon_key: str,
@@ -120,7 +120,7 @@ def test_legacy_api_client_debug(
120
120
  "wait_until_complete,expected_type",
121
121
  [(True, processing.Results), (False, processing.Remote)],
122
122
  )
123
- def test_legacy_api_client_wait_until_complete(
123
+ def test_legacy_client_wait_until_complete(
124
124
  tmp_path: pathlib.Path,
125
125
  api_root_url: str,
126
126
  api_anon_key: str,
@@ -156,7 +156,7 @@ def test_legacy_api_client_wait_until_complete(
156
156
  ),
157
157
  ],
158
158
  )
159
- def test_legacy_api_client_update(
159
+ def test_legacy_client_update(
160
160
  api_root_url: str,
161
161
  api_anon_key: str,
162
162
  collection_id: str,
@@ -173,7 +173,7 @@ def test_legacy_api_client_update(
173
173
 
174
174
 
175
175
  @pytest.mark.filterwarnings("ignore:Unverified HTTPS")
176
- def test_legacy_api_client_kwargs(api_root_url: str, api_anon_key: str) -> None:
176
+ def test_legacy_client_kwargs(api_root_url: str, api_anon_key: str) -> None:
177
177
  session = requests.Session()
178
178
  client = LegacyClient(
179
179
  url=api_root_url,
@@ -198,7 +198,7 @@ def test_legacy_api_client_kwargs(api_root_url: str, api_anon_key: str) -> None:
198
198
  assert client.client.session is session
199
199
 
200
200
 
201
- def test_legacy_api_client_logging(
201
+ def test_legacy_client_logging(
202
202
  caplog: pytest.LogCaptureFixture,
203
203
  api_root_url: str,
204
204
  api_anon_key: str,
@@ -226,7 +226,7 @@ def test_legacy_api_client_logging(
226
226
  ]
227
227
 
228
228
 
229
- def test_legacy_api_client_download(
229
+ def test_legacy_client_download(
230
230
  tmp_path: pathlib.Path,
231
231
  monkeypatch: pytest.MonkeyPatch,
232
232
  api_root_url: str,
@@ -258,7 +258,7 @@ def test_legacy_api_client_download(
258
258
  assert all(os.path.getsize(target) == 1 for target in targets)
259
259
 
260
260
 
261
- def test_legacy_api_client_status(legacy_client: LegacyClient) -> None:
261
+ def test_legacy_client_status(legacy_client: LegacyClient) -> None:
262
262
  status = legacy_client.status()
263
263
  assert set(status) <= {
264
264
  "critical",
@@ -277,7 +277,7 @@ def test_legacy_api_client_status(legacy_client: LegacyClient) -> None:
277
277
  )
278
278
 
279
279
 
280
- def test_legacy_api_client_remote(
280
+ def test_legacy_client_remote(
281
281
  legacy_client: LegacyClient, tmp_path: pathlib.Path
282
282
  ) -> None:
283
283
  results = legacy_client.retrieve("test-adaptor-dummy", {"size": 1})
@@ -288,7 +288,7 @@ def test_legacy_api_client_remote(
288
288
  assert os.path.getsize(target) == 1
289
289
 
290
290
 
291
- def test_legacy_api_client_warning(
291
+ def test_legacy_client_warning(
292
292
  api_root_url: str,
293
293
  api_anon_key: str,
294
294
  ) -> None:
@@ -305,7 +305,7 @@ def test_legacy_api_client_warning(
305
305
  )
306
306
 
307
307
 
308
- def test_legacy_api_client_toolbox(legacy_client: LegacyClient) -> None:
308
+ def test_legacy_client_toolbox(legacy_client: LegacyClient) -> None:
309
309
  with pytest.raises(NotImplementedError):
310
310
  legacy_client.service("service")
311
311
  with pytest.raises(NotImplementedError):
@@ -389,33 +389,6 @@ def test_submit(cat: catalogue.Catalogue) -> None:
389
389
  assert remote.finished_at.isoformat() == "2022-09-02T17:32:54.308120+00:00"
390
390
 
391
391
 
392
- @responses.activate
393
- def test_depracations(cat: catalogue.Catalogue) -> None:
394
- responses_add()
395
-
396
- collection = cat.get_collection(COLLECTION_ID)
397
- with pytest.warns(DeprecationWarning, match="`process` has been deprecated"):
398
- assert isinstance(collection.process, processing.Process)
399
-
400
- request = {"variable": "temperature", "year": "2022"}
401
- remote = collection.submit(request)
402
-
403
- with pytest.warns(
404
- DeprecationWarning, match="`creation_datetime` has been deprecated"
405
- ):
406
- assert (
407
- remote.creation_datetime.isoformat() == "2022-09-02T17:30:48.201213+00:00"
408
- )
409
-
410
- with pytest.warns(DeprecationWarning, match="`start_datetime` has been deprecated"):
411
- assert remote.start_datetime is not None
412
- assert remote.start_datetime.isoformat() == "2022-09-02T17:32:43.890617+00:00"
413
-
414
- with pytest.warns(DeprecationWarning, match="`end_datetime` has been deprecated"):
415
- assert remote.end_datetime is not None
416
- assert remote.end_datetime.isoformat() == "2022-09-02T17:32:54.308120+00:00"
417
-
418
-
419
392
  @responses.activate
420
393
  @pytest.mark.parametrize("method", ("submit", "apply_constraints", "estimate_costs"))
421
394
  def test_process_docstrings(cat: catalogue.Catalogue, method: str) -> None:
@@ -438,8 +411,12 @@ def test_wait_on_result(cat: catalogue.Catalogue) -> None:
438
411
  remote._wait_on_results()
439
412
 
440
413
 
414
+ @pytest.mark.parametrize("status", ["failed", "rejected"])
441
415
  @responses.activate
442
- def test_wait_on_result_failed(cat: catalogue.Catalogue) -> None:
416
+ def test_wait_on_result_failed(
417
+ cat: catalogue.Catalogue, status: str, monkeypatch: pytest.MonkeyPatch
418
+ ) -> None:
419
+ monkeypatch.setitem(JOB_FAILED_JSON, "status", status)
443
420
  responses_add()
444
421
 
445
422
  collection = cat.get_collection(COLLECTION_ID)
@@ -451,6 +428,7 @@ def test_wait_on_result_failed(cat: catalogue.Catalogue) -> None:
451
428
  ):
452
429
  remote._wait_on_results()
453
430
 
431
+ assert remote.status == status
454
432
  assert remote.created_at.isoformat() == "2022-09-02T17:30:48.201213+00:00"
455
433
  assert remote.started_at is not None
456
434
  assert remote.started_at.isoformat() == "2022-09-02T17:32:43.890617+00:00"