core-https 3.1.0__py3-none-any.whl → 3.1.1__py3-none-any.whl
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/__init__.py +3 -6
- core_https/exceptions.py +0 -2
- core_https/requesters/aiohttp_.py +22 -24
- core_https/requesters/aiohttp_rate_limit.py +1 -8
- core_https/requesters/aiohttp_throttle.py +3 -4
- core_https/requesters/base.py +12 -20
- core_https/requesters/requests_.py +11 -12
- core_https/requesters/urllib3_.py +11 -15
- core_https/tests/aiohttp_.py +9 -9
- core_https/tests/base.py +1 -4
- core_https/tests/decorators.py +20 -20
- core_https/tests/requests_.py +8 -8
- core_https/tests/urllib3_.py +9 -10
- core_https/utils.py +18 -13
- {core_https-3.1.0.dist-info → core_https-3.1.1.dist-info}/METADATA +8 -4
- core_https-3.1.1.dist-info/RECORD +22 -0
- {core_https-3.1.0.dist-info → core_https-3.1.1.dist-info}/WHEEL +1 -1
- core_https-3.1.0.dist-info/RECORD +0 -22
- {core_https-3.1.0.dist-info → core_https-3.1.1.dist-info}/licenses/LICENSE +0 -0
- {core_https-3.1.0.dist-info → core_https-3.1.1.dist-info}/top_level.txt +0 -0
core_https/__init__.py
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
1
|
"""
|
|
4
2
|
Public API for the core_https package: HTTP status codes
|
|
5
3
|
and status info enum.
|
|
6
4
|
"""
|
|
7
5
|
|
|
8
|
-
from importlib.metadata import PackageNotFoundError
|
|
9
|
-
from importlib.metadata import version
|
|
6
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
10
7
|
|
|
11
8
|
from core_mixins.compatibility import StrEnum
|
|
12
9
|
|
|
@@ -45,7 +42,7 @@ class StatusInfo(StrEnum):
|
|
|
45
42
|
|
|
46
43
|
|
|
47
44
|
__all__ = [
|
|
48
|
-
"__version__",
|
|
49
45
|
"HTTPStatus",
|
|
50
|
-
"StatusInfo"
|
|
46
|
+
"StatusInfo",
|
|
47
|
+
"__version__",
|
|
51
48
|
]
|
core_https/exceptions.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
1
|
"""Asynchronous HTTP requester implementation backed by aiohttp."""
|
|
4
2
|
|
|
5
3
|
from __future__ import annotations
|
|
@@ -7,8 +5,6 @@ from __future__ import annotations
|
|
|
7
5
|
import asyncio
|
|
8
6
|
from contextlib import suppress
|
|
9
7
|
from typing import Any
|
|
10
|
-
from typing import Dict
|
|
11
|
-
from typing import Optional
|
|
12
8
|
|
|
13
9
|
from aiohttp import (
|
|
14
10
|
ClientResponse,
|
|
@@ -20,8 +16,8 @@ from aiohttp import (
|
|
|
20
16
|
from core_mixins.compatibility import Self
|
|
21
17
|
|
|
22
18
|
from core_https.exceptions import RetryableException
|
|
23
|
-
|
|
24
|
-
from .base import IRequester
|
|
19
|
+
|
|
20
|
+
from .base import HTTPMethod, IRequester
|
|
25
21
|
|
|
26
22
|
|
|
27
23
|
class AioHttpRequester(IRequester):
|
|
@@ -80,8 +76,8 @@ class AioHttpRequester(IRequester):
|
|
|
80
76
|
|
|
81
77
|
def __init__(
|
|
82
78
|
self,
|
|
83
|
-
session:
|
|
84
|
-
retries:
|
|
79
|
+
session: ClientSession | None = None,
|
|
80
|
+
retries: int | None = 3,
|
|
85
81
|
**kwargs,
|
|
86
82
|
) -> None:
|
|
87
83
|
"""
|
|
@@ -110,7 +106,7 @@ class AioHttpRequester(IRequester):
|
|
|
110
106
|
super().__init__(**kwargs)
|
|
111
107
|
|
|
112
108
|
self._session = session
|
|
113
|
-
self._session_lock:
|
|
109
|
+
self._session_lock: asyncio.Lock | None = None
|
|
114
110
|
self._owns_session = session is None
|
|
115
111
|
self._timeout = ClientTimeout(total=self.timeout)
|
|
116
112
|
self.retries = retries
|
|
@@ -152,16 +148,18 @@ class AioHttpRequester(IRequester):
|
|
|
152
148
|
self._session_lock = asyncio.Lock()
|
|
153
149
|
|
|
154
150
|
async with self._session_lock:
|
|
155
|
-
if self._session is None: # Double-check after acquiring lock...
|
|
156
|
-
self._session
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
151
|
+
if self._session is not None: # Double-check after acquiring lock...
|
|
152
|
+
return self._session
|
|
153
|
+
|
|
154
|
+
self._session = ClientSession(
|
|
155
|
+
timeout=self._timeout,
|
|
156
|
+
connector=TCPConnector(
|
|
157
|
+
limit=self.connector_limit,
|
|
158
|
+
limit_per_host=self.connector_limit_per_host,
|
|
159
|
+
),
|
|
160
|
+
)
|
|
163
161
|
|
|
164
|
-
|
|
162
|
+
self._owns_session = True
|
|
165
163
|
|
|
166
164
|
return self._session
|
|
167
165
|
|
|
@@ -169,12 +167,12 @@ class AioHttpRequester(IRequester):
|
|
|
169
167
|
self,
|
|
170
168
|
url: str,
|
|
171
169
|
method: HTTPMethod = HTTPMethod.GET,
|
|
172
|
-
headers:
|
|
173
|
-
retries:
|
|
174
|
-
backoff_factor:
|
|
175
|
-
session:
|
|
176
|
-
params:
|
|
177
|
-
timeout:
|
|
170
|
+
headers: dict[str, Any] | None = None,
|
|
171
|
+
retries: int | None = None,
|
|
172
|
+
backoff_factor: float | None = None,
|
|
173
|
+
session: ClientSession | None = None,
|
|
174
|
+
params: dict[str, Any] | None = None,
|
|
175
|
+
timeout: float | None = None,
|
|
178
176
|
**kwargs,
|
|
179
177
|
) -> ClientResponse:
|
|
180
178
|
"""
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
1
|
"""Rate-limited aiohttp requester using aiolimiter.AsyncLimiter."""
|
|
4
2
|
|
|
5
3
|
from aiohttp import ClientResponse
|
|
@@ -17,12 +15,7 @@ class AioHttpRateLimitRequester(AioHttpRequester):
|
|
|
17
15
|
if they acquire permission within the same window.
|
|
18
16
|
"""
|
|
19
17
|
|
|
20
|
-
def __init__(
|
|
21
|
-
self,
|
|
22
|
-
max_rate: int,
|
|
23
|
-
time_period: float,
|
|
24
|
-
**kwargs
|
|
25
|
-
) -> None:
|
|
18
|
+
def __init__(self, max_rate: int, time_period: float, **kwargs) -> None:
|
|
26
19
|
"""
|
|
27
20
|
Initialize the rate-limited requester.
|
|
28
21
|
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
1
|
"""Concurrency-throttled aiohttp requester using asyncio.Semaphore."""
|
|
4
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
5
|
import asyncio
|
|
6
|
-
from typing import Optional
|
|
7
6
|
|
|
8
7
|
from aiohttp import ClientResponse
|
|
9
8
|
|
|
@@ -37,7 +36,7 @@ class AioHttpThrottleRequester(AioHttpRequester):
|
|
|
37
36
|
|
|
38
37
|
super().__init__(**kwargs)
|
|
39
38
|
self.max_concurrency = max_concurrency
|
|
40
|
-
self._semaphore:
|
|
39
|
+
self._semaphore: asyncio.Semaphore | None = None
|
|
41
40
|
|
|
42
41
|
@classmethod
|
|
43
42
|
def engine(cls) -> str:
|
core_https/requesters/base.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
1
|
"""Abstract base class and shared utilities for all HTTP requester implementations."""
|
|
4
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
5
|
import re
|
|
6
|
-
from abc import ABC
|
|
7
|
-
from abc import
|
|
8
|
-
from typing import Any
|
|
6
|
+
from abc import ABC, abstractmethod
|
|
7
|
+
from collections.abc import Mapping
|
|
8
|
+
from typing import Any
|
|
9
9
|
|
|
10
10
|
from core_mixins.interfaces.factory import IFactory
|
|
11
11
|
|
|
@@ -85,8 +85,8 @@ class IRequester(IFactory, ABC):
|
|
|
85
85
|
self,
|
|
86
86
|
encoding: str = "utf-8",
|
|
87
87
|
raise_for_status: bool = False,
|
|
88
|
-
retries:
|
|
89
|
-
backoff_factor:
|
|
88
|
+
retries: Any | None = None,
|
|
89
|
+
backoff_factor: float | None = None,
|
|
90
90
|
connector_limit: int = 100,
|
|
91
91
|
connector_limit_per_host: int = 30,
|
|
92
92
|
timeout: int = 10,
|
|
@@ -195,9 +195,9 @@ class IRequester(IFactory, ABC):
|
|
|
195
195
|
self,
|
|
196
196
|
url: str,
|
|
197
197
|
method: HTTPMethod,
|
|
198
|
-
headers:
|
|
199
|
-
retries:
|
|
200
|
-
backoff_factor:
|
|
198
|
+
headers: dict[str, str] | None = None,
|
|
199
|
+
retries: Any | None = None,
|
|
200
|
+
backoff_factor: float | None = None,
|
|
201
201
|
**kwargs, # Each `engine`have its own attributes...
|
|
202
202
|
) -> Any:
|
|
203
203
|
"""
|
|
@@ -293,10 +293,7 @@ class IRequester(IFactory, ABC):
|
|
|
293
293
|
- The method gracefully handles malformed or missing headers
|
|
294
294
|
"""
|
|
295
295
|
|
|
296
|
-
headers_ = {
|
|
297
|
-
k.lower(): v
|
|
298
|
-
for k, v in headers.items()
|
|
299
|
-
}
|
|
296
|
+
headers_ = {k.lower(): v for k, v in headers.items()}
|
|
300
297
|
|
|
301
298
|
# First trying "charset" header directly (rare)...
|
|
302
299
|
charset = headers_.get("charset")
|
|
@@ -307,12 +304,7 @@ class IRequester(IFactory, ABC):
|
|
|
307
304
|
content_type = headers_.get("content-type", "")
|
|
308
305
|
match = re.search(r"charset=([^\s;]+)", content_type, re.IGNORECASE)
|
|
309
306
|
if match:
|
|
310
|
-
return (
|
|
311
|
-
match.group(1)
|
|
312
|
-
.strip()
|
|
313
|
-
.replace("'", "")
|
|
314
|
-
.replace('"', "")
|
|
315
|
-
)
|
|
307
|
+
return match.group(1).strip().replace("'", "").replace('"', "")
|
|
316
308
|
|
|
317
309
|
return self.encoding or default
|
|
318
310
|
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
1
|
"""Synchronous HTTP requester implementation backed by the requests library."""
|
|
4
2
|
|
|
5
|
-
from
|
|
3
|
+
from __future__ import annotations
|
|
6
4
|
|
|
7
5
|
import requests
|
|
8
6
|
import urllib3
|
|
9
7
|
from requests.adapters import HTTPAdapter
|
|
10
8
|
|
|
11
9
|
from core_https.requesters.base import IRequester
|
|
10
|
+
|
|
12
11
|
from .base import HTTPMethod
|
|
13
12
|
|
|
14
13
|
|
|
@@ -36,9 +35,9 @@ class RequestsRequester(IRequester):
|
|
|
36
35
|
|
|
37
36
|
def __init__(
|
|
38
37
|
self,
|
|
39
|
-
session:
|
|
40
|
-
retries:
|
|
41
|
-
backoff_factor:
|
|
38
|
+
session: requests.Session | None = None,
|
|
39
|
+
retries: urllib3.Retry | None = None,
|
|
40
|
+
backoff_factor: float | None = None,
|
|
42
41
|
**kwargs,
|
|
43
42
|
) -> None:
|
|
44
43
|
"""
|
|
@@ -86,12 +85,12 @@ class RequestsRequester(IRequester):
|
|
|
86
85
|
self,
|
|
87
86
|
url: str,
|
|
88
87
|
method: HTTPMethod = HTTPMethod.GET,
|
|
89
|
-
headers:
|
|
90
|
-
retries:
|
|
91
|
-
backoff_factor:
|
|
92
|
-
session:
|
|
93
|
-
params:
|
|
94
|
-
timeout:
|
|
88
|
+
headers: dict[str, str] | None = None,
|
|
89
|
+
retries: urllib3.Retry | None = None,
|
|
90
|
+
backoff_factor: float | None = None,
|
|
91
|
+
session: requests.Session | None = None,
|
|
92
|
+
params: dict | None = None,
|
|
93
|
+
timeout: float | None = None,
|
|
95
94
|
**kwargs,
|
|
96
95
|
) -> requests.Response:
|
|
97
96
|
"""
|
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
1
|
"""Low-level synchronous HTTP requester implementation backed by urllib3."""
|
|
4
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
5
|
import json
|
|
6
6
|
from contextlib import suppress
|
|
7
|
-
from typing import Dict, Optional
|
|
8
7
|
|
|
9
|
-
from urllib3 import BaseHTTPResponse
|
|
10
|
-
from urllib3 import PoolManager
|
|
11
|
-
from urllib3 import Retry
|
|
8
|
+
from urllib3 import BaseHTTPResponse, PoolManager, Retry
|
|
12
9
|
|
|
13
|
-
from .base import HTTPMethod
|
|
14
|
-
from .base import IRequester
|
|
10
|
+
from .base import HTTPMethod, IRequester
|
|
15
11
|
|
|
16
12
|
|
|
17
13
|
class Urllib3Requester(IRequester):
|
|
@@ -31,8 +27,8 @@ class Urllib3Requester(IRequester):
|
|
|
31
27
|
|
|
32
28
|
def __init__(
|
|
33
29
|
self,
|
|
34
|
-
pool_manager:
|
|
35
|
-
retries:
|
|
30
|
+
pool_manager: PoolManager | None = None,
|
|
31
|
+
retries: Retry | None = None,
|
|
36
32
|
**kwargs,
|
|
37
33
|
) -> None:
|
|
38
34
|
"""
|
|
@@ -56,11 +52,11 @@ class Urllib3Requester(IRequester):
|
|
|
56
52
|
self,
|
|
57
53
|
url: str,
|
|
58
54
|
method: HTTPMethod = HTTPMethod.GET,
|
|
59
|
-
headers:
|
|
60
|
-
retries:
|
|
61
|
-
backoff_factor:
|
|
62
|
-
fields:
|
|
63
|
-
timeout:
|
|
55
|
+
headers: dict[str, str] | None = None,
|
|
56
|
+
retries: Retry | None = None,
|
|
57
|
+
backoff_factor: float | None = None,
|
|
58
|
+
fields: dict | None = None,
|
|
59
|
+
timeout: float | None = None,
|
|
64
60
|
**kwargs,
|
|
65
61
|
) -> BaseHTTPResponse:
|
|
66
62
|
"""
|
core_https/tests/aiohttp_.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
1
|
"""
|
|
4
2
|
Test utilities for aiohttp HTTP client library.
|
|
5
3
|
|
|
@@ -38,7 +36,9 @@ See Also:
|
|
|
38
36
|
- BaseUrllib3TestCases: Test utilities for urllib3 library
|
|
39
37
|
"""
|
|
40
38
|
|
|
41
|
-
from
|
|
39
|
+
from __future__ import annotations
|
|
40
|
+
|
|
41
|
+
from typing import Any
|
|
42
42
|
from unittest.mock import AsyncMock, Mock
|
|
43
43
|
|
|
44
44
|
from aiohttp import ClientResponseError
|
|
@@ -103,14 +103,14 @@ class BaseAiohttpTestCases(BaseHttpTestCases):
|
|
|
103
103
|
cls,
|
|
104
104
|
url: str = "https://example.com",
|
|
105
105
|
method: str = "GET",
|
|
106
|
-
json_response:
|
|
106
|
+
json_response: dict[str, Any] | None = None,
|
|
107
107
|
status: int = 200,
|
|
108
|
-
headers:
|
|
109
|
-
text_response:
|
|
110
|
-
content:
|
|
108
|
+
headers: dict[str, str] | None = None,
|
|
109
|
+
text_response: str | None = None,
|
|
110
|
+
content: bytes | None = None,
|
|
111
111
|
content_type: str = "application/json",
|
|
112
112
|
charset: str = "utf-8",
|
|
113
|
-
raise_for_status_exception:
|
|
113
|
+
raise_for_status_exception: Exception | None = None,
|
|
114
114
|
) -> Mock:
|
|
115
115
|
"""
|
|
116
116
|
Create a mock aiohttp.ClientResponse object for testing.
|
|
@@ -203,7 +203,7 @@ class BaseAiohttpTestCases(BaseHttpTestCases):
|
|
|
203
203
|
url: str = "http://example.com",
|
|
204
204
|
status: int = 404,
|
|
205
205
|
message: str = "Not Found",
|
|
206
|
-
history:
|
|
206
|
+
history: list | None = None,
|
|
207
207
|
) -> ClientResponseError:
|
|
208
208
|
"""
|
|
209
209
|
Create a ClientResponseError for testing error handling.
|
core_https/tests/base.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
1
|
"""
|
|
4
2
|
Base test case classes for HTTP request testing.
|
|
5
3
|
|
|
@@ -27,7 +25,6 @@ See Also:
|
|
|
27
25
|
- BaseUrllib3TestCases: Specialized test utilities for urllib3 library
|
|
28
26
|
"""
|
|
29
27
|
|
|
30
|
-
from typing import Dict
|
|
31
28
|
from unittest import TestCase
|
|
32
29
|
|
|
33
30
|
from core_https.utils import HTTPStatus
|
|
@@ -83,4 +80,4 @@ class BaseHttpTestCases(TestCase):
|
|
|
83
80
|
|
|
84
81
|
# Dictionary mapping HTTP status codes to their reason phrases.
|
|
85
82
|
# Generated from :class:`HTTPStatus` enum.
|
|
86
|
-
code_mapper:
|
|
83
|
+
code_mapper: dict[int, str] = HTTPStatus.as_dict()
|
core_https/tests/decorators.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
1
|
"""
|
|
4
2
|
Test decorators for HTTP library mocking.
|
|
5
3
|
|
|
@@ -26,8 +24,10 @@ See Also:
|
|
|
26
24
|
- BaseUrllib3TestCases: Base class for urllib3 test utilities.
|
|
27
25
|
"""
|
|
28
26
|
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
29
|
from functools import wraps
|
|
30
|
-
from typing import Any
|
|
30
|
+
from typing import Any
|
|
31
31
|
from unittest.mock import AsyncMock, Mock, patch
|
|
32
32
|
|
|
33
33
|
from .aiohttp_ import BaseAiohttpTestCases
|
|
@@ -38,14 +38,14 @@ from .urllib3_ import BaseUrllib3TestCases
|
|
|
38
38
|
def patch_aiohttp(
|
|
39
39
|
url: str = "https://example.com",
|
|
40
40
|
method: str = "GET",
|
|
41
|
-
json_response:
|
|
41
|
+
json_response: dict[str, Any] | None = None,
|
|
42
42
|
status: int = 200,
|
|
43
|
-
headers:
|
|
44
|
-
text_response:
|
|
45
|
-
content:
|
|
43
|
+
headers: dict[str, str] | None = None,
|
|
44
|
+
text_response: str | None = None,
|
|
45
|
+
content: bytes | None = None,
|
|
46
46
|
content_type: str = "application/json",
|
|
47
47
|
charset: str = "utf-8",
|
|
48
|
-
raise_for_status_exception:
|
|
48
|
+
raise_for_status_exception: Exception | None = None,
|
|
49
49
|
):
|
|
50
50
|
"""
|
|
51
51
|
Decorator that patches `aiohttp.ClientSession._request` with
|
|
@@ -127,12 +127,12 @@ def patch_aiohttp(
|
|
|
127
127
|
def patch_requests(
|
|
128
128
|
url: str = "https://example.com",
|
|
129
129
|
encoding: str = "utf-8",
|
|
130
|
-
headers:
|
|
131
|
-
json_response:
|
|
132
|
-
text_response:
|
|
130
|
+
headers: dict[str, str] | None = None,
|
|
131
|
+
json_response: dict[str, Any] | None = None,
|
|
132
|
+
text_response: str | None = None,
|
|
133
133
|
status_code: int = 200,
|
|
134
|
-
content:
|
|
135
|
-
raise_for_status_exception:
|
|
134
|
+
content: bytes | None = None,
|
|
135
|
+
raise_for_status_exception: Exception | None = None,
|
|
136
136
|
):
|
|
137
137
|
"""
|
|
138
138
|
Decorator that patches requests.sessions.Session.request to
|
|
@@ -217,17 +217,17 @@ def patch_urllib3(
|
|
|
217
217
|
method: str = "GET",
|
|
218
218
|
status: int = 200,
|
|
219
219
|
data: bytes = b'{"message": "success"}',
|
|
220
|
-
headers:
|
|
221
|
-
reason:
|
|
220
|
+
headers: dict[str, str] | None = None,
|
|
221
|
+
reason: str | None = None,
|
|
222
222
|
version: int = 11,
|
|
223
223
|
preload_content: bool = True,
|
|
224
224
|
decode_content: bool = True,
|
|
225
225
|
version_string: str = "HTTP/1.1",
|
|
226
|
-
original_response:
|
|
227
|
-
pool:
|
|
228
|
-
connection:
|
|
229
|
-
msg:
|
|
230
|
-
retries:
|
|
226
|
+
original_response: Mock | None = None,
|
|
227
|
+
pool: Mock | None = None,
|
|
228
|
+
connection: Mock | None = None,
|
|
229
|
+
msg: Mock | None = None,
|
|
230
|
+
retries: Mock | None = None,
|
|
231
231
|
enforce_content_length: bool = False,
|
|
232
232
|
with_json_attr: bool = True,
|
|
233
233
|
):
|
core_https/tests/requests_.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
1
|
"""
|
|
4
2
|
Test utilities for requests HTTP client library.
|
|
5
3
|
|
|
@@ -37,8 +35,10 @@ See Also:
|
|
|
37
35
|
- BaseUrllib3TestCases: Test utilities for urllib3 library
|
|
38
36
|
"""
|
|
39
37
|
|
|
38
|
+
from __future__ import annotations
|
|
39
|
+
|
|
40
40
|
import json
|
|
41
|
-
from typing import Any
|
|
41
|
+
from typing import Any
|
|
42
42
|
from unittest.mock import Mock
|
|
43
43
|
|
|
44
44
|
from core_https.tests.base import BaseHttpTestCases
|
|
@@ -105,12 +105,12 @@ class BaseRequestsTestCases(BaseHttpTestCases):
|
|
|
105
105
|
cls,
|
|
106
106
|
url: str = "https://example.com",
|
|
107
107
|
encoding: str = "utf-8",
|
|
108
|
-
headers:
|
|
109
|
-
json_response:
|
|
110
|
-
text_response:
|
|
108
|
+
headers: dict[str, str] | None = None,
|
|
109
|
+
json_response: dict[str, Any] | None = None,
|
|
110
|
+
text_response: str | None = None,
|
|
111
111
|
status_code: int = 200,
|
|
112
|
-
content:
|
|
113
|
-
raise_for_status_exception:
|
|
112
|
+
content: bytes | None = None,
|
|
113
|
+
raise_for_status_exception: Exception | None = None,
|
|
114
114
|
) -> Mock:
|
|
115
115
|
"""
|
|
116
116
|
Create a mock requests.Response object for testing.
|
core_https/tests/urllib3_.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
1
|
"""
|
|
4
2
|
Test utilities for urllib3 HTTP client library.
|
|
5
3
|
|
|
@@ -43,8 +41,9 @@ See Also:
|
|
|
43
41
|
- BaseAiohttpTestCases: Test utilities for aiohttp library
|
|
44
42
|
"""
|
|
45
43
|
|
|
44
|
+
from __future__ import annotations
|
|
45
|
+
|
|
46
46
|
import json
|
|
47
|
-
from typing import Dict, Optional
|
|
48
47
|
from unittest.mock import Mock
|
|
49
48
|
|
|
50
49
|
from urllib3._collections import HTTPHeaderDict
|
|
@@ -114,17 +113,17 @@ class BaseUrllib3TestCases(BaseHttpTestCases):
|
|
|
114
113
|
method: str = "GET",
|
|
115
114
|
status: int = 200,
|
|
116
115
|
data: bytes = b'{"message": "success"}',
|
|
117
|
-
headers:
|
|
118
|
-
reason:
|
|
116
|
+
headers: dict[str, str] | None = None,
|
|
117
|
+
reason: str | None = None,
|
|
119
118
|
version: int = 11,
|
|
120
119
|
preload_content: bool = True,
|
|
121
120
|
decode_content: bool = True,
|
|
122
121
|
version_string: str = "HTTP/1.1",
|
|
123
|
-
original_response:
|
|
124
|
-
pool:
|
|
125
|
-
connection:
|
|
126
|
-
msg:
|
|
127
|
-
retries:
|
|
122
|
+
original_response: Mock | None = None,
|
|
123
|
+
pool: Mock | None = None,
|
|
124
|
+
connection: Mock | None = None,
|
|
125
|
+
msg: Mock | None = None,
|
|
126
|
+
retries: Mock | None = None,
|
|
128
127
|
enforce_content_length: bool = False,
|
|
129
128
|
with_json_attr: bool = True,
|
|
130
129
|
) -> Mock:
|
core_https/utils.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
1
|
"""
|
|
4
2
|
HTTP utilities for the core_https library.
|
|
5
3
|
|
|
@@ -48,7 +46,6 @@ See Also:
|
|
|
48
46
|
"""
|
|
49
47
|
|
|
50
48
|
from enum import Enum
|
|
51
|
-
from typing import Dict
|
|
52
49
|
|
|
53
50
|
|
|
54
51
|
class HTTPStatus(Enum):
|
|
@@ -226,7 +223,7 @@ class HTTPStatus(Enum):
|
|
|
226
223
|
raise ValueError(f"No HTTPStatus found for code: {code}") from exc
|
|
227
224
|
|
|
228
225
|
@classmethod
|
|
229
|
-
def as_dict(cls) ->
|
|
226
|
+
def as_dict(cls) -> dict[int, str]:
|
|
230
227
|
"""
|
|
231
228
|
Get all HTTP status codes as a dictionary.
|
|
232
229
|
|
|
@@ -238,13 +235,10 @@ class HTTPStatus(Enum):
|
|
|
238
235
|
print(codes[200]) # "OK"
|
|
239
236
|
"""
|
|
240
237
|
|
|
241
|
-
return {
|
|
242
|
-
member.code: member.description
|
|
243
|
-
for member in cls
|
|
244
|
-
}
|
|
238
|
+
return {member.code: member.description for member in cls}
|
|
245
239
|
|
|
246
240
|
|
|
247
|
-
_HTTP_STATUS_BY_CODE:
|
|
241
|
+
_HTTP_STATUS_BY_CODE: dict[int, HTTPStatus] = {m.value: m for m in HTTPStatus}
|
|
248
242
|
|
|
249
243
|
|
|
250
244
|
class HTTPMethod(Enum):
|
|
@@ -312,7 +306,12 @@ class HTTPMethod(Enum):
|
|
|
312
306
|
|
|
313
307
|
Safe methods are those that do not modify server state.
|
|
314
308
|
"""
|
|
315
|
-
return self in (
|
|
309
|
+
return self in (
|
|
310
|
+
HTTPMethod.GET,
|
|
311
|
+
HTTPMethod.HEAD,
|
|
312
|
+
HTTPMethod.OPTIONS,
|
|
313
|
+
HTTPMethod.TRACE,
|
|
314
|
+
)
|
|
316
315
|
|
|
317
316
|
def is_idempotent(self) -> bool:
|
|
318
317
|
"""
|
|
@@ -320,8 +319,14 @@ class HTTPMethod(Enum):
|
|
|
320
319
|
|
|
321
320
|
Idempotent methods can be called multiple times with the same result.
|
|
322
321
|
"""
|
|
323
|
-
return self in (
|
|
324
|
-
|
|
322
|
+
return self in (
|
|
323
|
+
HTTPMethod.GET,
|
|
324
|
+
HTTPMethod.HEAD,
|
|
325
|
+
HTTPMethod.PUT,
|
|
326
|
+
HTTPMethod.DELETE,
|
|
327
|
+
HTTPMethod.OPTIONS,
|
|
328
|
+
HTTPMethod.TRACE,
|
|
329
|
+
)
|
|
325
330
|
|
|
326
331
|
def is_cacheable(self) -> bool:
|
|
327
332
|
"""
|
|
@@ -358,4 +363,4 @@ class HTTPMethod(Enum):
|
|
|
358
363
|
raise ValueError(f"No HTTPMethod found for name: {name}") from exc
|
|
359
364
|
|
|
360
365
|
|
|
361
|
-
_HTTP_METHOD_BY_NAME:
|
|
366
|
+
_HTTP_METHOD_BY_NAME: dict[str, HTTPMethod] = {m.value: m for m in HTTPMethod}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: core-https
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.1
|
|
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
|
|
@@ -27,13 +27,13 @@ Requires-Python: >=3.9
|
|
|
27
27
|
Description-Content-Type: text/x-rst
|
|
28
28
|
License-File: LICENSE
|
|
29
29
|
Requires-Dist: aiohttp<4.0.0,>=3.12.0
|
|
30
|
-
Requires-Dist: core-mixins>=3.2.
|
|
30
|
+
Requires-Dist: core-mixins>=3.2.2
|
|
31
31
|
Requires-Dist: requests<3.0.0,>=2.32.3
|
|
32
32
|
Requires-Dist: urllib3<3.0.0,>=2.2.3
|
|
33
33
|
Provides-Extra: dev
|
|
34
34
|
Requires-Dist: aiolimiter<2.0.0,>=1.2.1; extra == "dev"
|
|
35
|
-
Requires-Dist: core-dev-tools>=2.
|
|
36
|
-
Requires-Dist: core-tests>=2.
|
|
35
|
+
Requires-Dist: core-dev-tools>=2.1.0; extra == "dev"
|
|
36
|
+
Requires-Dist: core-tests>=2.3.0; extra == "dev"
|
|
37
37
|
Requires-Dist: types-requests>=2.32.0.20250602; extra == "dev"
|
|
38
38
|
Provides-Extra: extras
|
|
39
39
|
Requires-Dist: aiolimiter<2.0.0,>=1.2.1; extra == "extras"
|
|
@@ -46,6 +46,10 @@ This project/library contains common elements related to HTTP...
|
|
|
46
46
|
|
|
47
47
|
===============================================================================
|
|
48
48
|
|
|
49
|
+
.. image:: https://static.pepy.tech/personalized-badge/core-https?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads
|
|
50
|
+
:target: https://pepy.tech/projects/core-https
|
|
51
|
+
:alt: PyPI Downloads
|
|
52
|
+
|
|
49
53
|
.. image:: https://img.shields.io/pypi/pyversions/core-https.svg
|
|
50
54
|
:target: https://pypi.org/project/core-https/
|
|
51
55
|
:alt: Python Versions
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
core_https/__init__.py,sha256=YssKKc3kkQNLYHcXKyqb2u4ocGKL-nCs1SXyUHxHxBw,984
|
|
2
|
+
core_https/exceptions.py,sha256=kocOWT8_TQ3VS_IgCmo3hSJhNG5ytQn5f7eLpNhSk6E,4936
|
|
3
|
+
core_https/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
core_https/utils.py,sha256=vWpVw3UEK2lmFf4Fh3MakiAaE53KHYM9nZvC2Q-inbc,12298
|
|
5
|
+
core_https/requesters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
core_https/requesters/aiohttp_.py,sha256=wIWLhu62QqgglJijbPs3DuFLtV46Gj-UOVF0Jf-UVA4,11223
|
|
7
|
+
core_https/requesters/aiohttp_rate_limit.py,sha256=oY2dsdSrRuHRA0VV2ZoEAy3_ypVp46sa2FMX1NhZpW0,2033
|
|
8
|
+
core_https/requesters/aiohttp_throttle.py,sha256=BQVkcVv0l4xubCkVxKP7Gx5zrGw1KNOewZZjKiMncKU,2316
|
|
9
|
+
core_https/requesters/base.py,sha256=CVeqmaqCST5ZoBc46wqmpzmml0a-TGgqepPg1r4Y0o8,16441
|
|
10
|
+
core_https/requesters/requests_.py,sha256=ImGq4w--fGy7boRP0qZ0LQYgvXsyUZi5ZYCvSDGKCbk,3328
|
|
11
|
+
core_https/requesters/urllib3_.py,sha256=BFtOEBblnQaD0XoQrKuv7RW0hMdptiqP_mLoGi36WLY,3469
|
|
12
|
+
core_https/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
+
core_https/tests/aiohttp_.py,sha256=y2Mrg5iypSbswi7JFHAwRQycrOTzHow_RkjehZXQpbk,9593
|
|
14
|
+
core_https/tests/base.py,sha256=Qrr1kDhGg84V58_nY37OUWuBO13cKCzQ-SadsunZBLw,3387
|
|
15
|
+
core_https/tests/decorators.py,sha256=g1fvKnrfKv1xqYEbeWWLCLz958TlOhu5IVwoO9TAUU0,12891
|
|
16
|
+
core_https/tests/requests_.py,sha256=MO1rxE-1aWXlZ-qyhUfq_AEyNz7MNHq3jNeB6y91buA,8274
|
|
17
|
+
core_https/tests/urllib3_.py,sha256=UPCQkhbbNw2lT7ICBrFLlNEKZADNN3iYE7gkCGNGjrc,13166
|
|
18
|
+
core_https-3.1.1.dist-info/licenses/LICENSE,sha256=dj8Wz7OWOIOTyLJzaYLn8RFz_W5uYWSGR2xS5lHNAl4,1082
|
|
19
|
+
core_https-3.1.1.dist-info/METADATA,sha256=dK5JQ-DJW5DNmVg-L-ddbuzQ9KzDErGU3RTNeapPNNI,7216
|
|
20
|
+
core_https-3.1.1.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
21
|
+
core_https-3.1.1.dist-info/top_level.txt,sha256=Ufm6w6dLS6hyTPwMUXt4O6klJfLyKpkaG6csd2kmaDw,11
|
|
22
|
+
core_https-3.1.1.dist-info/RECORD,,
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
core_https/__init__.py,sha256=-7M1Xlzb68X8hc9Mw24gTBkXybc_MfekBwg6CDwCmGc,1038
|
|
2
|
-
core_https/exceptions.py,sha256=l0NKIGi5NeJ2Aw-231txK24CIv-tgceKBvP2_u2i3jw,4961
|
|
3
|
-
core_https/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
core_https/utils.py,sha256=PJbKgOFAXAMTfwcuIFMK2zKwdqFIPh8ixJDgpzdhmFA,12262
|
|
5
|
-
core_https/requesters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
core_https/requesters/aiohttp_.py,sha256=nDnjSb9rxi2HYOkAQPQ_Ypi2irG_WWoFY-Oiy6rg1HA,11329
|
|
7
|
-
core_https/requesters/aiohttp_rate_limit.py,sha256=_qEwu2QvNAu0DcxSxKaIEQF4du_4_NcHhVwdcDAO9DI,2096
|
|
8
|
-
core_https/requesters/aiohttp_throttle.py,sha256=gC_UURL6rgOOHON2qGLK8hByLOYrlxCIy4bDlWedwPc,2336
|
|
9
|
-
core_https/requesters/base.py,sha256=rzZ-MOBDBS17GWQwD4-_LWszpOv1vCReRyRY9RpylT8,16578
|
|
10
|
-
core_https/requesters/requests_.py,sha256=pFgMB-ajFJGPS9FfZzbEgN1vnMVRoExz3E_6I-496eI,3378
|
|
11
|
-
core_https/requesters/urllib3_.py,sha256=DVJ4qmjWPHH9FiVbMnEjEUR0kztB6s1gnOHPrN_TTvs,3568
|
|
12
|
-
core_https/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
-
core_https/tests/aiohttp_.py,sha256=NChlPeyaAMa7p1OtfuC5yZx2E-XQAXm_NTsFnGZjDQE,9622
|
|
14
|
-
core_https/tests/base.py,sha256=Nx_nLR7927F1UShva3YJ5gkqtKQaU6g2rpkO__Ph5qg,3436
|
|
15
|
-
core_https/tests/decorators.py,sha256=9wa_omtkJ7ImUDOyy69vYRt-Ulzkah4H2UT7gjAhtxQ,12947
|
|
16
|
-
core_https/tests/requests_.py,sha256=Wja7zI_zkOH8DNnY3RJCJQSPghkVS36-WGZSee4ZSmE,8294
|
|
17
|
-
core_https/tests/urllib3_.py,sha256=zKYroybSItnWa7BU1bGG4HSh0O7H1jNn6JKDLUPx5Nc,13210
|
|
18
|
-
core_https-3.1.0.dist-info/licenses/LICENSE,sha256=dj8Wz7OWOIOTyLJzaYLn8RFz_W5uYWSGR2xS5lHNAl4,1082
|
|
19
|
-
core_https-3.1.0.dist-info/METADATA,sha256=jZTPFoO6w5484n8LaUwRMNKI_9MxLqA3vNPzne4-SpU,6978
|
|
20
|
-
core_https-3.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
21
|
-
core_https-3.1.0.dist-info/top_level.txt,sha256=Ufm6w6dLS6hyTPwMUXt4O6klJfLyKpkaG6csd2kmaDw,11
|
|
22
|
-
core_https-3.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|