core-https 2.0.2__tar.gz → 2.0.3__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.
- {core_https-2.0.2 → core_https-2.0.3}/PKG-INFO +7 -4
- core_https-2.0.3/core_https/requesters/aiohttp_rate_limit.py +60 -0
- core_https-2.0.3/core_https/requesters/aiohttp_throttle.py +54 -0
- {core_https-2.0.2 → core_https-2.0.3}/core_https.egg-info/PKG-INFO +7 -4
- {core_https-2.0.2 → core_https-2.0.3}/core_https.egg-info/SOURCES.txt +2 -0
- {core_https-2.0.2 → core_https-2.0.3}/core_https.egg-info/requires.txt +5 -3
- {core_https-2.0.2 → core_https-2.0.3}/pyproject.toml +9 -4
- {core_https-2.0.2 → core_https-2.0.3}/LICENSE +0 -0
- {core_https-2.0.2 → core_https-2.0.3}/README.rst +0 -0
- {core_https-2.0.2 → core_https-2.0.3}/core_https/__init__.py +0 -0
- {core_https-2.0.2 → core_https-2.0.3}/core_https/exceptions.py +0 -0
- {core_https-2.0.2 → core_https-2.0.3}/core_https/py.typed +0 -0
- {core_https-2.0.2 → core_https-2.0.3}/core_https/requesters/__init__.py +0 -0
- {core_https-2.0.2 → core_https-2.0.3}/core_https/requesters/aiohttp_.py +0 -0
- {core_https-2.0.2 → core_https-2.0.3}/core_https/requesters/base.py +0 -0
- {core_https-2.0.2 → core_https-2.0.3}/core_https/requesters/requests_.py +0 -0
- {core_https-2.0.2 → core_https-2.0.3}/core_https/requesters/urllib3_.py +0 -0
- {core_https-2.0.2 → core_https-2.0.3}/core_https/tests/__init__.py +0 -0
- {core_https-2.0.2 → core_https-2.0.3}/core_https/tests/aiohttp_.py +0 -0
- {core_https-2.0.2 → core_https-2.0.3}/core_https/tests/base.py +0 -0
- {core_https-2.0.2 → core_https-2.0.3}/core_https/tests/decorators.py +0 -0
- {core_https-2.0.2 → core_https-2.0.3}/core_https/tests/requests_.py +0 -0
- {core_https-2.0.2 → core_https-2.0.3}/core_https/tests/urllib3_.py +0 -0
- {core_https-2.0.2 → core_https-2.0.3}/core_https/utils.py +0 -0
- {core_https-2.0.2 → core_https-2.0.3}/core_https.egg-info/dependency_links.txt +0 -0
- {core_https-2.0.2 → core_https-2.0.3}/core_https.egg-info/top_level.txt +0 -0
- {core_https-2.0.2 → core_https-2.0.3}/setup.cfg +0 -0
- {core_https-2.0.2 → core_https-2.0.3}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: core-https
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.3
|
|
4
4
|
Summary: This project/library contains common elements related to HTTP & API services...
|
|
5
5
|
Author-email: Alejandro Cora González <alek.cora.glez@gmail.com>
|
|
6
6
|
Maintainer: Alejandro Cora González
|
|
@@ -24,14 +24,17 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
24
24
|
Requires-Python: >=3.9
|
|
25
25
|
Description-Content-Type: text/x-rst
|
|
26
26
|
License-File: LICENSE
|
|
27
|
-
Requires-Dist: aiohttp<4.0.0,>=3.12.0
|
|
27
|
+
Requires-Dist: aiohttp<4.0.0,>=3.12.0
|
|
28
28
|
Requires-Dist: core-mixins>=2.2.2
|
|
29
|
-
Requires-Dist: requests<3.0.0,>=2.32.3
|
|
30
|
-
Requires-Dist: urllib3<3.0.0,>=2.2.3
|
|
29
|
+
Requires-Dist: requests<3.0.0,>=2.32.3
|
|
30
|
+
Requires-Dist: urllib3<3.0.0,>=2.2.3
|
|
31
31
|
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: aiolimiter<2.0.0,>=1.2.1; extra == "dev"
|
|
32
33
|
Requires-Dist: core-dev-tools>=1.0.1; extra == "dev"
|
|
33
34
|
Requires-Dist: core-tests>=2.0.2; extra == "dev"
|
|
34
35
|
Requires-Dist: types-requests>=2.32.0.20250602; extra == "dev"
|
|
36
|
+
Provides-Extra: extras
|
|
37
|
+
Requires-Dist: aiolimiter<2.0.0,>=1.2.1; extra == "extras"
|
|
35
38
|
Dynamic: license-file
|
|
36
39
|
|
|
37
40
|
core-https
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from aiohttp import ClientResponse
|
|
4
|
+
from aiolimiter import AsyncLimiter
|
|
5
|
+
|
|
6
|
+
from core_https.requesters.aiohttp_throttle import AioHttpThrottleRequester
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AioHttpRateLimitRequester(AioHttpThrottleRequester):
|
|
10
|
+
"""
|
|
11
|
+
An HTTP requester that enforces a simple *rate limit* using
|
|
12
|
+
:class:`aiolimiter.AsyncLimiter`. This class restricts how many
|
|
13
|
+
requests may be *started* within a given time window. It does **not**
|
|
14
|
+
limit concurrency; multiple requests may still run in parallel
|
|
15
|
+
if they acquire permission within the same window.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
max_concurrency: int,
|
|
21
|
+
max_rate: int,
|
|
22
|
+
time_period: float,
|
|
23
|
+
**kwargs
|
|
24
|
+
) -> None:
|
|
25
|
+
"""
|
|
26
|
+
Initialize the rate-limited requester.
|
|
27
|
+
|
|
28
|
+
:param max_rate: Maximum number of requests allowed within the time window.
|
|
29
|
+
:param time_period: Duration (in seconds) of the rate-limiting window.
|
|
30
|
+
:param kwargs: Additional keyword arguments passed to :class:`AioHttpRequester`.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
if max_rate <= 0:
|
|
34
|
+
raise ValueError("`max_rate` must be positive!")
|
|
35
|
+
|
|
36
|
+
if time_period <= 0:
|
|
37
|
+
raise ValueError("`time_period` must be positive!")
|
|
38
|
+
|
|
39
|
+
super().__init__(max_concurrency=max_concurrency, **kwargs)
|
|
40
|
+
|
|
41
|
+
self.max_rate = max_rate
|
|
42
|
+
self.time_period = time_period
|
|
43
|
+
|
|
44
|
+
self._limiter = AsyncLimiter(
|
|
45
|
+
max_rate=self.max_rate,
|
|
46
|
+
time_period=self.time_period,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
async def request(self, *args, **kwargs) -> ClientResponse:
|
|
50
|
+
"""
|
|
51
|
+
Execute an HTTP request subject to the configured rate limit. The
|
|
52
|
+
coroutine will wait (non-blocking) until a rate slot becomes available,
|
|
53
|
+
and then delegate the call to the base :class:`AioHttpRequester`.
|
|
54
|
+
|
|
55
|
+
:return: The HTTP response object.
|
|
56
|
+
:raises Exception: Any exception raised by the underlying HTTP client.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
async with self._limiter:
|
|
60
|
+
return await super().request(*args, **kwargs)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
|
|
5
|
+
from aiohttp import ClientResponse
|
|
6
|
+
|
|
7
|
+
from core_https.requesters.aiohttp_ import AioHttpRequester
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AioHttpThrottleRequester(AioHttpRequester):
|
|
11
|
+
"""
|
|
12
|
+
An `AioHttpRequester` implementation that limits the number of
|
|
13
|
+
concurrent in-flight HTTP requests using an `asyncio.Semaphore`. This
|
|
14
|
+
throttler enforces *max_concurrency* at the coroutine level within a
|
|
15
|
+
single event loop. Each call to :meth:`request` must acquire a semaphore
|
|
16
|
+
permit before dispatching the actual HTTP request.
|
|
17
|
+
|
|
18
|
+
**Notes:**
|
|
19
|
+
|
|
20
|
+
- The throttling mechanism limits only concurrent *coroutine execution*. It
|
|
21
|
+
does not enforce rate limiting (requests per second).
|
|
22
|
+
- If you override :meth:`request` in a subclass, be aware that
|
|
23
|
+
`await super().request(...)` calls the parent implementation (so the parent
|
|
24
|
+
semaphore *will* be used for the actual HTTP call). However, any code you
|
|
25
|
+
run **before** or **after** that `super()` call executes outside the parent's
|
|
26
|
+
semaphore (and therefore is not throttled).
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(self, max_concurrency: int, **kwargs) -> None:
|
|
30
|
+
"""
|
|
31
|
+
:param max_concurrency: Maximum number of concurrent requests allowed.
|
|
32
|
+
:param kwargs: Passed through to :class:`AioHttpRequester`.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
super().__init__(**kwargs)
|
|
36
|
+
self.max_concurrency = max_concurrency
|
|
37
|
+
self._semaphore = asyncio.Semaphore(self.max_concurrency)
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
def registration_key(cls) -> str:
|
|
41
|
+
return cls.__name__
|
|
42
|
+
|
|
43
|
+
async def request(self, *args, **kwargs) -> ClientResponse:
|
|
44
|
+
"""
|
|
45
|
+
Execute an HTTP request with concurrency throttling. It acquires
|
|
46
|
+
a semaphore permit before delegating the actual request to the
|
|
47
|
+
underlying :class:`AioHttpRequester` implementation.
|
|
48
|
+
|
|
49
|
+
:returns: The aiohttp response object.
|
|
50
|
+
:raises: Any exception raised by the underlying session.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
async with self._semaphore:
|
|
54
|
+
return await super().request(*args, **kwargs)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: core-https
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.3
|
|
4
4
|
Summary: This project/library contains common elements related to HTTP & API services...
|
|
5
5
|
Author-email: Alejandro Cora González <alek.cora.glez@gmail.com>
|
|
6
6
|
Maintainer: Alejandro Cora González
|
|
@@ -24,14 +24,17 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
24
24
|
Requires-Python: >=3.9
|
|
25
25
|
Description-Content-Type: text/x-rst
|
|
26
26
|
License-File: LICENSE
|
|
27
|
-
Requires-Dist: aiohttp<4.0.0,>=3.12.0
|
|
27
|
+
Requires-Dist: aiohttp<4.0.0,>=3.12.0
|
|
28
28
|
Requires-Dist: core-mixins>=2.2.2
|
|
29
|
-
Requires-Dist: requests<3.0.0,>=2.32.3
|
|
30
|
-
Requires-Dist: urllib3<3.0.0,>=2.2.3
|
|
29
|
+
Requires-Dist: requests<3.0.0,>=2.32.3
|
|
30
|
+
Requires-Dist: urllib3<3.0.0,>=2.2.3
|
|
31
31
|
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: aiolimiter<2.0.0,>=1.2.1; extra == "dev"
|
|
32
33
|
Requires-Dist: core-dev-tools>=1.0.1; extra == "dev"
|
|
33
34
|
Requires-Dist: core-tests>=2.0.2; extra == "dev"
|
|
34
35
|
Requires-Dist: types-requests>=2.32.0.20250602; extra == "dev"
|
|
36
|
+
Provides-Extra: extras
|
|
37
|
+
Requires-Dist: aiolimiter<2.0.0,>=1.2.1; extra == "extras"
|
|
35
38
|
Dynamic: license-file
|
|
36
39
|
|
|
37
40
|
core-https
|
|
@@ -13,6 +13,8 @@ core_https.egg-info/requires.txt
|
|
|
13
13
|
core_https.egg-info/top_level.txt
|
|
14
14
|
core_https/requesters/__init__.py
|
|
15
15
|
core_https/requesters/aiohttp_.py
|
|
16
|
+
core_https/requesters/aiohttp_rate_limit.py
|
|
17
|
+
core_https/requesters/aiohttp_throttle.py
|
|
16
18
|
core_https/requesters/base.py
|
|
17
19
|
core_https/requesters/requests_.py
|
|
18
20
|
core_https/requesters/urllib3_.py
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
core-mixins>=2.2.2
|
|
2
|
-
|
|
3
|
-
[:python_version >= "3.9"]
|
|
4
1
|
aiohttp<4.0.0,>=3.12.0
|
|
2
|
+
core-mixins>=2.2.2
|
|
5
3
|
requests<3.0.0,>=2.32.3
|
|
6
4
|
urllib3<3.0.0,>=2.2.3
|
|
7
5
|
|
|
8
6
|
[dev]
|
|
7
|
+
aiolimiter<2.0.0,>=1.2.1
|
|
9
8
|
core-dev-tools>=1.0.1
|
|
10
9
|
core-tests>=2.0.2
|
|
11
10
|
types-requests>=2.32.0.20250602
|
|
11
|
+
|
|
12
|
+
[extras]
|
|
13
|
+
aiolimiter<2.0.0,>=1.2.1
|
|
@@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta"
|
|
|
9
9
|
[project]
|
|
10
10
|
name = "core-https"
|
|
11
11
|
description = "This project/library contains common elements related to HTTP & API services..."
|
|
12
|
-
version = "2.0.
|
|
12
|
+
version = "2.0.3"
|
|
13
13
|
|
|
14
14
|
authors = [
|
|
15
15
|
{name = "Alejandro Cora González", email = "alek.cora.glez@gmail.com"}
|
|
@@ -39,19 +39,24 @@ classifiers = [
|
|
|
39
39
|
]
|
|
40
40
|
|
|
41
41
|
dependencies = [
|
|
42
|
-
"aiohttp>=3.12.0,<4.0.0
|
|
42
|
+
"aiohttp>=3.12.0,<4.0.0",
|
|
43
43
|
"core-mixins>=2.2.2",
|
|
44
|
-
"requests>=2.32.3,<3.0.0
|
|
45
|
-
"urllib3>=2.2.3,<3.0.0
|
|
44
|
+
"requests>=2.32.3,<3.0.0",
|
|
45
|
+
"urllib3>=2.2.3,<3.0.0",
|
|
46
46
|
]
|
|
47
47
|
|
|
48
48
|
[project.optional-dependencies]
|
|
49
49
|
dev = [
|
|
50
|
+
"aiolimiter>=1.2.1,<2.0.0",
|
|
50
51
|
"core-dev-tools>=1.0.1",
|
|
51
52
|
"core-tests>=2.0.2",
|
|
52
53
|
"types-requests>=2.32.0.20250602",
|
|
53
54
|
]
|
|
54
55
|
|
|
56
|
+
extras = [
|
|
57
|
+
"aiolimiter>=1.2.1,<2.0.0",
|
|
58
|
+
]
|
|
59
|
+
|
|
55
60
|
[project.urls]
|
|
56
61
|
Homepage = "https://gitlab.com/bytecode-solutions/core/core-https"
|
|
57
62
|
Repository = "https://gitlab.com/bytecode-solutions/core/core-https"
|
|
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
|