ebird-api 4.0.0__tar.gz → 4.1.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.
- {ebird_api-4.0.0 → ebird_api-4.1.0}/CHANGELOG.md +3 -0
- {ebird_api-4.0.0/src/ebird_api.egg-info → ebird_api-4.1.0}/PKG-INFO +1 -1
- {ebird_api-4.0.0 → ebird_api-4.1.0}/pyproject.toml +2 -2
- {ebird_api-4.0.0 → ebird_api-4.1.0}/src/ebird/api/requests/__init__.py +1 -1
- {ebird_api-4.0.0 → ebird_api-4.1.0}/src/ebird/api/requests/utils.py +34 -6
- {ebird_api-4.0.0 → ebird_api-4.1.0/src/ebird_api.egg-info}/PKG-INFO +1 -1
- {ebird_api-4.0.0 → ebird_api-4.1.0}/LICENSE.txt +0 -0
- {ebird_api-4.0.0 → ebird_api-4.1.0}/README.md +0 -0
- {ebird_api-4.0.0 → ebird_api-4.1.0}/setup.cfg +0 -0
- {ebird_api-4.0.0 → ebird_api-4.1.0}/setup.py +0 -0
- {ebird_api-4.0.0 → ebird_api-4.1.0}/src/ebird/api/requests/checklists.py +0 -0
- {ebird_api-4.0.0 → ebird_api-4.1.0}/src/ebird/api/requests/client.py +0 -0
- {ebird_api-4.0.0 → ebird_api-4.1.0}/src/ebird/api/requests/constants.py +0 -0
- {ebird_api-4.0.0 → ebird_api-4.1.0}/src/ebird/api/requests/hotspots.py +0 -0
- {ebird_api-4.0.0 → ebird_api-4.1.0}/src/ebird/api/requests/observations.py +0 -0
- {ebird_api-4.0.0 → ebird_api-4.1.0}/src/ebird/api/requests/regions.py +0 -0
- {ebird_api-4.0.0 → ebird_api-4.1.0}/src/ebird/api/requests/species.py +0 -0
- {ebird_api-4.0.0 → ebird_api-4.1.0}/src/ebird/api/requests/statistics.py +0 -0
- {ebird_api-4.0.0 → ebird_api-4.1.0}/src/ebird/api/requests/taxonomy.py +0 -0
- {ebird_api-4.0.0 → ebird_api-4.1.0}/src/ebird/api/requests/validation.py +0 -0
- {ebird_api-4.0.0 → ebird_api-4.1.0}/src/ebird_api.egg-info/SOURCES.txt +0 -0
- {ebird_api-4.0.0 → ebird_api-4.1.0}/src/ebird_api.egg-info/dependency_links.txt +0 -0
- {ebird_api-4.0.0 → ebird_api-4.1.0}/src/ebird_api.egg-info/top_level.txt +0 -0
|
@@ -8,6 +8,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|
|
8
8
|
This project adheres to [PEP440](https://www.python.org/dev/peps/pep-0440/)
|
|
9
9
|
and by implication, [Semantic Versioning](http://semver.org/).
|
|
10
10
|
|
|
11
|
+
## [4.1.0] - 2026-06-14
|
|
12
|
+
- Retry requests, with exponentinal back-off, if an error occurs.
|
|
13
|
+
|
|
11
14
|
## [4.0.0] - 2025-07-09
|
|
12
15
|
- Moved the package to ebird.api.requests to make space for other projects.
|
|
13
16
|
- Changed the minimum supported python version to 3.10
|
|
@@ -29,7 +29,7 @@ license = {text = "MIT License"}
|
|
|
29
29
|
name = "ebird-api"
|
|
30
30
|
readme = "README.md"
|
|
31
31
|
requires-python = ">= 3.10"
|
|
32
|
-
version = "4.
|
|
32
|
+
version = "4.1.0"
|
|
33
33
|
|
|
34
34
|
[project.urls]
|
|
35
35
|
Repository = "https://github.com/ProjectBabbler/ebird-api.git"
|
|
@@ -37,7 +37,7 @@ Issues = "https://github.com/ProjectBabbler/ebird-api/issues"
|
|
|
37
37
|
Changelog = "https://github.com/ProjectBabbler/ebird-api/blob/master/CHANGELOG.md"
|
|
38
38
|
|
|
39
39
|
[tool.bumpversion]
|
|
40
|
-
current_version = "4.
|
|
40
|
+
current_version = "4.1.0"
|
|
41
41
|
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
|
|
42
42
|
serialize = ["{major}.{minor}.{patch}"]
|
|
43
43
|
ignore_missing_version = false
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"""Various functions used in the API."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
+
import time
|
|
5
|
+
from urllib.error import HTTPError
|
|
4
6
|
from urllib.parse import urlencode
|
|
5
7
|
from urllib.request import Request, urlopen
|
|
6
8
|
|
|
@@ -74,7 +76,7 @@ def filter_parameters(params):
|
|
|
74
76
|
return filtered
|
|
75
77
|
|
|
76
78
|
|
|
77
|
-
def get_response(url, params=None, headers=None):
|
|
79
|
+
def get_response(url, params=None, headers=None, max_retries=3, backoff_factor=1.0):
|
|
78
80
|
"""Get the content from the eBird API.
|
|
79
81
|
|
|
80
82
|
:param url: the URL for the API call.
|
|
@@ -84,7 +86,14 @@ def get_response(url, params=None, headers=None):
|
|
|
84
86
|
:type params: dict
|
|
85
87
|
|
|
86
88
|
:param headers: the headers to add to the request.
|
|
87
|
-
:type
|
|
89
|
+
:type headers: dict
|
|
90
|
+
|
|
91
|
+
:param max_retries: number of times to retry after a 429 response.
|
|
92
|
+
:type max_retries: int
|
|
93
|
+
|
|
94
|
+
:param backoff_factor: seconds to wait before the first retry; doubles
|
|
95
|
+
on each subsequent attempt.
|
|
96
|
+
:type backoff_factor: float
|
|
88
97
|
|
|
89
98
|
:return: the content returned by the API
|
|
90
99
|
:rtype: str
|
|
@@ -104,7 +113,15 @@ def get_response(url, params=None, headers=None):
|
|
|
104
113
|
for name, value in headers.items():
|
|
105
114
|
request.add_header(name, value)
|
|
106
115
|
|
|
107
|
-
|
|
116
|
+
for attempt in range(max_retries + 1):
|
|
117
|
+
try:
|
|
118
|
+
return urlopen(request).read()
|
|
119
|
+
except HTTPError as exc:
|
|
120
|
+
if attempt == max_retries:
|
|
121
|
+
raise
|
|
122
|
+
retry_after = exc.headers.get("Retry-After") if exc.code == 429 else None
|
|
123
|
+
delay = float(retry_after) if retry_after else backoff_factor * (2**attempt)
|
|
124
|
+
time.sleep(delay)
|
|
108
125
|
|
|
109
126
|
|
|
110
127
|
def get_json(content):
|
|
@@ -138,7 +155,7 @@ def save_json(filename, data, indent=None):
|
|
|
138
155
|
json.dump(data, outfile, indent=indent)
|
|
139
156
|
|
|
140
157
|
|
|
141
|
-
def call(url, params, headers):
|
|
158
|
+
def call(url, params, headers, max_retries=3, backoff_factor=1.0):
|
|
142
159
|
"""Call the eBird API.
|
|
143
160
|
|
|
144
161
|
:param url: the URL for the API call.
|
|
@@ -148,7 +165,14 @@ def call(url, params, headers):
|
|
|
148
165
|
:type params: dict
|
|
149
166
|
|
|
150
167
|
:param headers: the headers to add to the request.
|
|
151
|
-
:type
|
|
168
|
+
:type headers: dict
|
|
169
|
+
|
|
170
|
+
:param max_retries: number of times to retry after a 429 response.
|
|
171
|
+
:type max_retries: int
|
|
172
|
+
|
|
173
|
+
:param backoff_factor: seconds to wait before the first retry; doubles
|
|
174
|
+
on each subsequent attempt.
|
|
175
|
+
:type backoff_factor: float
|
|
152
176
|
|
|
153
177
|
:return: the content returned by the API
|
|
154
178
|
:rtype: dict | list
|
|
@@ -161,4 +185,8 @@ def call(url, params, headers):
|
|
|
161
185
|
"""
|
|
162
186
|
filtered = filter_parameters(params)
|
|
163
187
|
mapped = map_parameters(filtered)
|
|
164
|
-
return get_json(
|
|
188
|
+
return get_json(
|
|
189
|
+
get_response(
|
|
190
|
+
url, mapped, headers, max_retries=max_retries, backoff_factor=backoff_factor
|
|
191
|
+
)
|
|
192
|
+
)
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|