[Git][debian-gis-team/ecmwf-api-client][upstream] New upstream version 1.7.0

Antonio Valentino (@antonio.valentino) gitlab at salsa.debian.org
Mon Jun 22 22:59:57 BST 2026



Antonio Valentino pushed to branch upstream at Debian GIS Project / ecmwf-api-client


Commits:
a64fe3d7 by Antonio Valentino at 2026-06-22T21:47:13+00:00
New upstream version 1.7.0
- - - - -


7 changed files:

- .github/workflows/check-and-publish.yml
- MANIFEST.in
- README.md
- ecmwfapi/api.py
- − example.py
- + pyproject.toml
- − setup.py


Changes:

=====================================
.github/workflows/check-and-publish.yml
=====================================
@@ -24,9 +24,9 @@ jobs:
     timeout-minutes: 20
 
     steps:
-      - uses: actions/checkout at v4
+      - uses: actions/checkout at v5
 
-      - uses: actions/setup-python at v5
+      - uses: actions/setup-python at v6
         with:
           python-version: ${{ matrix.python-version }}
 
@@ -59,9 +59,9 @@ jobs:
     runs-on: ubuntu-latest
 
     steps:
-    - uses: actions/checkout at v4
+    - uses: actions/checkout at v5
     - name: Set up Python
-      uses: actions/setup-python at v5
+      uses: actions/setup-python at v6
       with:
         python-version: '3.8'
     - name: Install dependencies


=====================================
MANIFEST.in
=====================================
@@ -1,3 +1,2 @@
-include *.py
 include LICENSE
 include MANIFEST.in
\ No newline at end of file


=====================================
README.md
=====================================
@@ -1,75 +1,88 @@
 # ecmwf-api-client
 
-# Installation
+[![PyPI version](https://img.shields.io/pypi/v/ecmwf-api-client.svg)](https://pypi.org/project/ecmwf-api-client/)
+[![Python versions](https://img.shields.io/pypi/pyversions/ecmwf-api-client.svg)](https://pypi.org/project/ecmwf-api-client/)
+[![Build](https://github.com/ecmwf/ecmwf-api-client/actions/workflows/check-and-publish.yml/badge.svg?branch=master)](https://github.com/ecmwf/ecmwf-api-client/actions/workflows/check-and-publish.yml)
+[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
 
-Install via pip with:
+Python client for the [ECMWF Web API](https://confluence.ecmwf.int/display/WEBAPI). Two entry points:
 
-> $ pip install ecmwf-api-client
+- **`ECMWFDataServer`** — retrieve IFS research experiments.
+- **`ECMWFService`** — access [MARS](https://confluence.ecmwf.int/display/WEBAPI/Access+MARS), ECMWF's Meteorological Archival and Retrieval System, for authorized users.
 
-# Configure
+## What this client is for
 
-## Anonymous access (default, not recommended)
+- **IFS research experiments** — available anonymously, or with registered access for a better quality of service.
+- **MARS archive access** — for authorized users; see [Access MARS](https://confluence.ecmwf.int/display/WEBAPI/Access+MARS) for who can access it and how.
 
-Anonymous access is the default type of access, with no configuration needed.
+## Looking for public datasets?
 
-However, anonymous access is only available for a limited set of datasets, and comes with a much lower quality of service. For access to all the available datasets, and an improved quality of service, please use registered access (see below).
+The **ECMWF Public Datasets Service** (TIGGE, S2S, ERA-Interim, and others) has been decommissioned. See the [decommissioning notice](https://confluence.ecmwf.int/display/DAC/Decommissioning+of+ECMWF+Public+Datasets+Service) for where each dataset moved — in short: TIGGE and S2S to the [ECMWF Data Store (ECDS)](https://ecds.ecmwf.int/), reanalyses to the [Climate Data Store (CDS)](https://cds.climate.copernicus.eu/), and real-time open forecast data is available via [ecmwf-opendata](https://github.com/ecmwf/ecmwf-opendata).
 
-## Registered access (recommended)
+## Installation
 
-* Register with ECMWF at https://www.ecmwf.int.
-* Retrieve you API access key at https://api.ecmwf.int/v1/key/.
+```
+$ pip install ecmwf-api-client
+```
 
-   Note that the API access key expires in 1 year. You will receive an email to the registered email address 1 month before the expiration date with the renewal instructions. To check the expiry date of your current key, log into www.ecmwf.int, and go to https://api.ecmwf.int/v1/key/.
+or with conda:
 
-* Copy and paste the API access key into the file $HOME/.ecmwfapirc (Unix/Linux) or %USERPROFILE%\\.ecmwfapirc (Windows: usually in C:\\Users\\\<USERNAME\>\\.ecmwfapirc).
+```
+$ conda install -c conda-forge ecmwf-api-client
+```
 
-   Your $HOME/.ecmwfapirc (Unix/Linux) or %USERPROFILE%\\.ecmwfapirc (Windows) should look something like this:
-   ```
-   {
-       "url"   : "https://api.ecmwf.int/v1",
-       "key"   : "XXXXXXXXXXXXXXXXXXXXXX",
-       "email" : "john.smith at example.com"
-   }
-   ```
-* Alternatively, one can use a file of their own liking, and point to it using environment variable `ECMWF_API_RC_FILE`. `ECMWF_API_RC_FILE` should be set to the full path of the given file. This method takes priority of the previous method of using a .ecmwfapirc file.
-* As yet another option, one can set the API access key values directly in the environment using variables `ECMWF_API_KEY` (key), `ECMWF_API_URL` (url), `ECMWF_API_EMAIL` (email). This method takes priority over the previous method of using environment variable `ECMWF_API_RC_FILE`.
-   
-# Example
+## Configure
 
-You can test this small python script to retrieve TIGGE (https://apps.ecmwf.int/datasets/data/tigge) data. Note that access to TIGGE data requires registered access, and is subject to accepting a licence at https://apps.ecmwf.int/datasets/data/tigge/licence/.
-```
-#!/usr/bin/env python
-from ecmwfapi import ECMWFDataServer
+### Anonymous access (default)
+
+No configuration needed. Anonymous access works only for the IFS research experiments, with a lower quality of service. For everything else, and for a better quality of service, use registered access.
+
+### Registered access (recommended)
+
+- Register with ECMWF at https://www.ecmwf.int.
+- Retrieve your API key at https://api.ecmwf.int/v1/key/ (see [Install ECMWF API Key](https://confluence.ecmwf.int/display/WEBAPI/Install+ECMWF+API+Key) for details, including key expiry and renewal).
+- Save the key to `$HOME/.ecmwfapirc` (Unix/Linux/macOS) or `C:\Users\<USERNAME>\.ecmwfapirc` (Windows):
+
+  ```
+  {
+      "url"   : "https://api.ecmwf.int/v1",
+      "key"   : "XXXXXXXXXXXXXXXXXXXXXX",
+      "email" : "john.smith at example.com"
+  }
+  ```
 
-# To run this example, you need an API key
-# available from https://api.ecmwf.int/v1/key/
+- Alternatively, point the environment variable `ECMWF_API_RC_FILE` to a file of your choice (takes priority over `.ecmwfapirc`).
+- Or set `ECMWF_API_KEY`, `ECMWF_API_URL`, `ECMWF_API_EMAIL` directly in the environment (takes priority over `ECMWF_API_RC_FILE`).
+- Or pass the values directly in code: `ECMWFDataServer(url=..., key=..., email=...)` or `ECMWFService("mars", url=..., key=..., email=...)`.
+
+## Retrieving IFS research experiments
+
+Use `ECMWFDataServer`:
+
+```python
+from ecmwfapi import ECMWFDataServer
 
 server = ECMWFDataServer()
 server.retrieve({
-    'origin'    : "ecmf",
-    'levtype'   : "sfc",
-    'number'    : "1",
-    'expver'    : "prod",
-    'dataset'   : "tigge",
-    'step'      : "0/6/12/18",
-    'area'      : "70/-130/30/-60",
-    'grid'      : "2/2",
-    'param'     : "167",
-    'time'      : "00/12",
-    'date'      : "2014-11-01",
-    'type'      : "pf",
-    'class'     : "ti",
-    'target'    : "tigge_2014-11-01_0012.grib"
+    # ... request parameters ...
 })
 ```
 
-# Logging
+Don't write the request by hand. Open the experiment's page (for example https://apps.ecmwf.int/ifs-experiments/rd/gkzp/), select what you need, and the site generates the exact request to paste into `retrieve({...})`.
 
-Logging messages by default are emitted to `stdout` using Python's `print` statement.
+## Accessing MARS
 
-To change that behaviour, one can define their own logging function and use it like so:
+For MARS access, follow [Access MARS](https://confluence.ecmwf.int/display/WEBAPI/Access+MARS). The recommended way is the `mars` command wrapper script provided there, which runs MARS requests from a file. The wrapper is built on this package's `ECMWFService` class.
 
-```
+## Retrieving efficiently
+
+Before submitting requests, it is recommended to read [Retrieval efficiency](https://confluence.ecmwf.int/display/WEBAPI/Retrieval+efficiency) — it explains how to check the cost of requests, how to structure requests around tapes, and the request limits. The [Web API FAQ](https://confluence.ecmwf.int/display/WEBAPI/Web+API+FAQ) covers monitoring requests and common errors.
+
+## Logging
+
+By default, log messages are printed to `stdout`. To use your own logging:
+
+```python
 import logging
 from ecmwfapi import ECMWFDataServer
 
@@ -81,7 +94,7 @@ def my_logging_function(msg):
 server = ECMWFDataServer(log=my_logging_function)
 ```
 
-# License
+## License
 
 Copyright 2019 European Centre for Medium-Range Weather Forecasts (ECMWF)
 Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at


=====================================
ecmwfapi/api.py
=====================================
@@ -7,9 +7,6 @@
 # granted to it by virtue of its status as an intergovernmental organisation nor
 # does it submit to any jurisdiction.
 
-# make the python3-like print behave in python 2
-from __future__ import print_function
-
 import json
 import os
 import sys
@@ -17,34 +14,19 @@ import time
 import traceback
 import textwrap
 from contextlib import closing
-
-# python 2 and 3 compatible urllib and httplib imports
-try:
-    from urllib.parse import urlparse
-    from urllib.parse import urljoin
-    from urllib.error import HTTPError, URLError
-    from urllib.request import (
-        HTTPRedirectHandler,
-        Request,
-        build_opener,
-        urlopen,
-        addinfourl,
-    )
-    from http.client import BadStatusLine
-except ImportError:
-    from urlparse import urlparse
-    from urlparse import urljoin
-    from urllib2 import HTTPError, URLError
-    from urllib2 import HTTPRedirectHandler, Request, build_opener, urlopen, addinfourl
-    from httplib import BadStatusLine
-
-try:
-    import ssl
-except ImportError:
-    sys.exit("Python socket module was not compiled with SSL support. Aborting...")
+from http.client import BadStatusLine
+from urllib.error import HTTPError, URLError
+from urllib.parse import urljoin, urlparse
+from urllib.request import (
+    HTTPRedirectHandler,
+    Request,
+    addinfourl,
+    build_opener,
+    urlopen,
+)
 
 
-VERSION = "1.6.5"
+VERSION = "1.7.0"
 
 
 DEFAULT_RCFILE_PATH = "~/.ecmwfapirc"
@@ -234,25 +216,11 @@ class Ignore303(HTTPRedirectHandler):
     def redirect_request(self, req, fp, code, msg, headers, newurl):
         if code in [301, 302]:
             # We want the posts to work even if we are redirected
-            try:
-                # Python < 3.4
-                data = req.get_data()
-            except AttributeError:
-                # Python >= 3.4
-                data = req.data
-
-            try:
-                # Python < 3.4
-                origin_req_host = req.get_origin_req_host()
-            except AttributeError:
-                # Python >= 3.4
-                origin_req_host = req.origin_req_host
-
             return Request(
                 newurl,
-                data=data,
+                data=req.data,
                 headers=req.headers,
-                origin_req_host=origin_req_host,
+                origin_req_host=req.origin_req_host,
                 unverifiable=True,
             )
         return None
@@ -270,7 +238,7 @@ def print_with_timestamp(msg):
     print("%s %s" % (t, msg))
 
 
-class Connection(object):
+class Connection:
     def __init__(
         self, url, email=None, key=None, verbose=False, quiet=False, log=no_log
     ):
@@ -419,7 +387,7 @@ class Connection(object):
             pass
 
 
-class APIRequest(object):
+class APIRequest:
     def __init__(
         self,
         url,
@@ -580,7 +548,7 @@ class APIRequest(object):
             self.log("")
 
 
-class ECMWFDataServer(object):
+class ECMWFDataServer:
     def __init__(
         self, url=None, key=None, email=None, verbose=False, log=print_with_timestamp
     ):
@@ -607,7 +575,7 @@ class ECMWFDataServer(object):
         c.execute(req, target)
 
 
-class ECMWFService(object):
+class ECMWFService:
     def __init__(
         self,
         service,


=====================================
example.py deleted
=====================================
@@ -1,33 +0,0 @@
-#!/usr/bin/env python
-#
-# (C) Copyright 2012-2013 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-#
-
-from ecmwfapi import ECMWFDataServer
-
-# To run this example, you need an API key
-# available from https://api.ecmwf.int/v1/key/
-
-server = ECMWFDataServer()
-server.retrieve(
-    {
-        "dataset": "tigge",
-        "step": "24",
-        "number": "all",
-        "levtype": "sl",
-        "date": "20071001",
-        "time": "00",
-        "origin": "all",
-        "type": "pf",
-        "param": "tp",
-        "area": "70/-130/30/-60",
-        "grid": "2/2",
-        "target": "data.grib",
-    }
-)


=====================================
pyproject.toml
=====================================
@@ -0,0 +1,38 @@
+[build-system]
+requires = ["setuptools>=64"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "ecmwf-api-client"
+description = "Python client for ECMWF web services API."
+readme = "README.md"
+license = { text = "Apache License Version 2.0" }
+authors = [
+    { name = "European Centre for Medium-Range Weather Forecasts (ECMWF)", email = "software.support at ecmwf.int" },
+]
+requires-python = ">=3.8"
+dynamic = ["version"]
+classifiers = [
+    "Development Status :: 5 - Production/Stable",
+    "Intended Audience :: Developers",
+    "License :: OSI Approved :: Apache Software License",
+    "Programming Language :: Python :: 3",
+    "Programming Language :: Python :: 3.8",
+    "Programming Language :: Python :: 3.9",
+    "Programming Language :: Python :: 3.10",
+    "Programming Language :: Python :: 3.11",
+    "Programming Language :: Python :: 3.12",
+    "Programming Language :: Python :: 3.13",
+    "Programming Language :: Python :: Implementation :: CPython",
+    "Programming Language :: Python :: Implementation :: PyPy",
+    "Operating System :: OS Independent",
+]
+
+[project.urls]
+Homepage = "https://github.com/ecmwf/ecmwf-api-client"
+
+[tool.setuptools.dynamic]
+version = { attr = "ecmwfapi.api.VERSION" }
+
+[tool.setuptools.packages.find]
+include = ["ecmwfapi*"]


=====================================
setup.py deleted
=====================================
@@ -1,47 +0,0 @@
-#!/usr/bin/env python
-#
-# (C) Copyright 2012-2019 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-#
-
-import io
-import os.path
-
-from setuptools import setup, find_packages
-
-import ecmwfapi
-
-
-def read(fname):
-    file_path = os.path.join(os.path.dirname(__file__), fname)
-    return io.open(file_path, encoding="utf-8").read()
-
-
-setup(
-    name="ecmwf-api-client",
-    version=ecmwfapi.__version__,
-    description=ecmwfapi.__doc__,
-    long_description=read("README.md"),
-    author="European Centre for Medium-Range Weather Forecasts (ECMWF)",
-    author_email="software.support at ecmwf.int",
-    license="Apache License Version 2.0",
-    url="https://github.com/ecmwf/ecmwf-api-client",
-    long_description_content_type="text/markdown",
-    packages=find_packages(),
-    zip_safe=True,
-    classifiers=[
-        "Development Status :: 5 - Production/Stable",
-        "Intended Audience :: Developers",
-        "License :: OSI Approved :: Apache Software License",
-        "Programming Language :: Python :: 2",
-        "Programming Language :: Python :: 3",
-        "Programming Language :: Python :: Implementation :: CPython",
-        "Programming Language :: Python :: Implementation :: PyPy",
-        "Operating System :: OS Independent",
-    ],
-)



View it on GitLab: https://salsa.debian.org/debian-gis-team/ecmwf-api-client/-/commit/a64fe3d74a3820086e5d3ef2d6e94576012a0f59

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/ecmwf-api-client/-/commit/a64fe3d74a3820086e5d3ef2d6e94576012a0f59
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20260622/dece7093/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list