blitz-api-py 0.4.0__tar.gz → 0.5.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.
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/CHANGELOG.md +7 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/PKG-INFO +8 -5
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/README.md +7 -4
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/_client_async.py +23 -2
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/_client_sync.py +23 -2
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/_rate_limit_async.py +6 -4
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/_rate_limit_sync.py +6 -4
- blitz_api_py-0.5.0/src/blitz_api/_version.py +1 -0
- blitz_api_py-0.4.0/src/blitz_api/_version.py +0 -1
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/.gitignore +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/LICENSE +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/pyproject.toml +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/__init__.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/_base_client.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/_client.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/_compat.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/_constants.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/_exceptions.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/_pagination_async.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/_pagination_base.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/_pagination_sync.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/_rate_limit.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/py.typed +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/resources/__init__.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/resources/_async/__init__.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/resources/_async/account.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/resources/_async/enrichment.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/resources/_async/search.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/resources/_async/utils.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/resources/_sync/__init__.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/resources/_sync/account.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/resources/_sync/enrichment.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/resources/_sync/search.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/resources/_sync/utils.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/types/__init__.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/types/_models.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/types/account.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/types/enrichment.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/types/enums.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/types/filters.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/types/search.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/types/shared.py +0 -0
- {blitz_api_py-0.4.0 → blitz_api_py-0.5.0}/src/blitz_api/types/utils.py +0 -0
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.0](https://github.com/api-blitz/blitz-api-py/compare/v0.4.0...v0.5.0) (2026-06-18)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* scope client-side rate limiting per endpoint ([#13](https://github.com/api-blitz/blitz-api-py/issues/13)) ([de5308b](https://github.com/api-blitz/blitz-api-py/commit/de5308b6995edc68dd1e43a8554296b7de095df2))
|
|
9
|
+
|
|
3
10
|
## [0.4.0](https://github.com/api-blitz/blitz-api-py/compare/v0.3.0...v0.4.0) (2026-06-17)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: blitz-api-py
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Typed Python SDK for the Blitz API — B2B data, search, and enrichment.
|
|
5
5
|
Project-URL: Homepage, https://blitz-api.ai
|
|
6
6
|
Project-URL: Documentation, https://docs.blitz-api.ai
|
|
@@ -258,10 +258,13 @@ client = BlitzAPI(
|
|
|
258
258
|
```
|
|
259
259
|
|
|
260
260
|
The client-side rate limiter is a sliding window — at most `rate_limit_rps` requests
|
|
261
|
-
in any rolling second —
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
261
|
+
in any rolling second — applied **per endpoint**: each endpoint (e.g. `.email` vs
|
|
262
|
+
`.phone`) is throttled independently, mirroring the API's own limit, which is also per
|
|
263
|
+
endpoint (5 req/s by default; check yours via
|
|
264
|
+
`client.account.key_info().max_requests_per_seconds`). A single client instance therefore
|
|
265
|
+
stays under the limit on every endpoint, so a burst on one never blocks another. Across
|
|
266
|
+
multiple processes — which share an endpoint's budget — you may still hit `429`; the retry
|
|
267
|
+
path handles that.
|
|
265
268
|
|
|
266
269
|
Every method also accepts a per-call `timeout` (seconds or an `httpx.Timeout`) when one
|
|
267
270
|
endpoint needs longer than the client default:
|
|
@@ -227,10 +227,13 @@ client = BlitzAPI(
|
|
|
227
227
|
```
|
|
228
228
|
|
|
229
229
|
The client-side rate limiter is a sliding window — at most `rate_limit_rps` requests
|
|
230
|
-
in any rolling second —
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
230
|
+
in any rolling second — applied **per endpoint**: each endpoint (e.g. `.email` vs
|
|
231
|
+
`.phone`) is throttled independently, mirroring the API's own limit, which is also per
|
|
232
|
+
endpoint (5 req/s by default; check yours via
|
|
233
|
+
`client.account.key_info().max_requests_per_seconds`). A single client instance therefore
|
|
234
|
+
stays under the limit on every endpoint, so a burst on one never blocks another. Across
|
|
235
|
+
multiple processes — which share an endpoint's budget — you may still hit `429`; the retry
|
|
236
|
+
path handles that.
|
|
234
237
|
|
|
235
238
|
Every method also accepts a per-call `timeout` (seconds or an `httpx.Timeout`) when one
|
|
236
239
|
endpoint needs longer than the client default:
|
|
@@ -50,13 +50,34 @@ class AsyncBlitzAPI(BaseClient):
|
|
|
50
50
|
)
|
|
51
51
|
self._http_client = http_client or httpx.AsyncClient(timeout=timeout)
|
|
52
52
|
self._owns_http_client = http_client is None
|
|
53
|
-
self.
|
|
53
|
+
self._rate_limit_rps = rate_limit_rps
|
|
54
|
+
# One limiter per endpoint path so each endpoint's rate limit is tracked
|
|
55
|
+
# independently (e.g. ``.email`` and ``.phone`` do not share a budget). Built
|
|
56
|
+
# lazily in ``_limiter_for`` on first use of each path.
|
|
57
|
+
self._rate_limiters: dict[str, AsyncRateLimiter] = {}
|
|
54
58
|
if sleep is None:
|
|
55
59
|
import asyncio
|
|
56
60
|
|
|
57
61
|
sleep = asyncio.sleep
|
|
58
62
|
self._sleep = sleep
|
|
59
63
|
|
|
64
|
+
def _limiter_for(self, path: str) -> AsyncRateLimiter:
|
|
65
|
+
"""Return the per-endpoint limiter for ``path``, creating it on first use.
|
|
66
|
+
|
|
67
|
+
Each endpoint path gets its own sliding window so its rate limit is tracked
|
|
68
|
+
independently of every other endpoint.
|
|
69
|
+
"""
|
|
70
|
+
limiter = self._rate_limiters.get(path)
|
|
71
|
+
if limiter is None:
|
|
72
|
+
# ``setdefault`` keeps concurrent first-callers on the same instance; any
|
|
73
|
+
# extra limiter built in a race is harmlessly discarded. Thread the client's
|
|
74
|
+
# ``sleep`` through so a custom/fake sleep injected for tests also drives the
|
|
75
|
+
# limiter's throttle wait, not just the retry backoff.
|
|
76
|
+
limiter = self._rate_limiters.setdefault(
|
|
77
|
+
path, AsyncRateLimiter(self._rate_limit_rps, sleep=self._sleep)
|
|
78
|
+
)
|
|
79
|
+
return limiter
|
|
80
|
+
|
|
60
81
|
async def _request(
|
|
61
82
|
self,
|
|
62
83
|
method: str,
|
|
@@ -72,7 +93,7 @@ class AsyncBlitzAPI(BaseClient):
|
|
|
72
93
|
|
|
73
94
|
attempt = 0
|
|
74
95
|
while True:
|
|
75
|
-
await self.
|
|
96
|
+
await self._limiter_for(path).acquire()
|
|
76
97
|
try:
|
|
77
98
|
if timeout is None:
|
|
78
99
|
response = await self._http_client.request(
|
|
@@ -52,13 +52,34 @@ class BlitzAPI(BaseClient):
|
|
|
52
52
|
)
|
|
53
53
|
self._http_client = http_client or httpx.Client(timeout=timeout)
|
|
54
54
|
self._owns_http_client = http_client is None
|
|
55
|
-
self.
|
|
55
|
+
self._rate_limit_rps = rate_limit_rps
|
|
56
|
+
# One limiter per endpoint path so each endpoint's rate limit is tracked
|
|
57
|
+
# independently (e.g. ``.email`` and ``.phone`` do not share a budget). Built
|
|
58
|
+
# lazily in ``_limiter_for`` on first use of each path.
|
|
59
|
+
self._rate_limiters: dict[str, RateLimiter] = {}
|
|
56
60
|
if sleep is None:
|
|
57
61
|
import time
|
|
58
62
|
|
|
59
63
|
sleep = time.sleep
|
|
60
64
|
self._sleep = sleep
|
|
61
65
|
|
|
66
|
+
def _limiter_for(self, path: str) -> RateLimiter:
|
|
67
|
+
"""Return the per-endpoint limiter for ``path``, creating it on first use.
|
|
68
|
+
|
|
69
|
+
Each endpoint path gets its own sliding window so its rate limit is tracked
|
|
70
|
+
independently of every other endpoint.
|
|
71
|
+
"""
|
|
72
|
+
limiter = self._rate_limiters.get(path)
|
|
73
|
+
if limiter is None:
|
|
74
|
+
# ``setdefault`` keeps concurrent first-callers on the same instance; any
|
|
75
|
+
# extra limiter built in a race is harmlessly discarded. Thread the client's
|
|
76
|
+
# ``sleep`` through so a custom/fake sleep injected for tests also drives the
|
|
77
|
+
# limiter's throttle wait, not just the retry backoff.
|
|
78
|
+
limiter = self._rate_limiters.setdefault(
|
|
79
|
+
path, RateLimiter(self._rate_limit_rps, sleep=self._sleep)
|
|
80
|
+
)
|
|
81
|
+
return limiter
|
|
82
|
+
|
|
62
83
|
def _request(
|
|
63
84
|
self,
|
|
64
85
|
method: str,
|
|
@@ -74,7 +95,7 @@ class BlitzAPI(BaseClient):
|
|
|
74
95
|
|
|
75
96
|
attempt = 0
|
|
76
97
|
while True:
|
|
77
|
-
self.
|
|
98
|
+
self._limiter_for(path).acquire()
|
|
78
99
|
try:
|
|
79
100
|
if timeout is None:
|
|
80
101
|
response = self._http_client.request(
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"""Client-side sliding-window rate limiter (async source; sync twin generated).
|
|
2
2
|
|
|
3
|
-
The API enforces a per-
|
|
4
|
-
outgoing requests *before* they are sent
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
The API enforces a per-endpoint request rate (5 req/s by default). This limiter throttles
|
|
4
|
+
outgoing requests *before* they are sent. The client holds one limiter **per endpoint
|
|
5
|
+
path** (see ``_client_async.py``), so each endpoint is throttled to ``rps`` independently,
|
|
6
|
+
mirroring the server's per-endpoint budget; a single client instance therefore stays under
|
|
7
|
+
the limit on every endpoint on its own. The server-side 429 retry path is the backstop for
|
|
8
|
+
bursts across processes, which share the same per-endpoint budget.
|
|
7
9
|
|
|
8
10
|
The algorithm is a sliding window: at most ``rps`` requests may begin in any rolling
|
|
9
11
|
one-second window. This matches the Blitz docs ("max 5 requests per 1000 ms") and the
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
# Do not edit by hand — edit the async source and run `python scripts/gen_sync.py`.
|
|
3
3
|
"""Client-side sliding-window rate limiter (async source; sync twin generated).
|
|
4
4
|
|
|
5
|
-
The API enforces a per-
|
|
6
|
-
outgoing requests *before* they are sent
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
The API enforces a per-endpoint request rate (5 req/s by default). This limiter throttles
|
|
6
|
+
outgoing requests *before* they are sent. The client holds one limiter **per endpoint
|
|
7
|
+
path** (see ``_client_async.py``), so each endpoint is throttled to ``rps`` independently,
|
|
8
|
+
mirroring the server's per-endpoint budget; a single client instance therefore stays under
|
|
9
|
+
the limit on every endpoint on its own. The server-side 429 retry path is the backstop for
|
|
10
|
+
bursts across processes, which share the same per-endpoint budget.
|
|
9
11
|
|
|
10
12
|
The algorithm is a sliding window: at most ``rps`` requests may begin in any rolling
|
|
11
13
|
one-second window. This matches the Blitz docs ("max 5 requests per 1000 ms") and the
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.5.0" # x-release-please-version
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.4.0" # x-release-please-version
|
|
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
|
|
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
|