never-primp 1.0.0__cp38-abi3-manylinux_2_28_x86_64.whl → 1.0.2__cp38-abi3-manylinux_2_28_x86_64.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.
Potentially problematic release.
This version of never-primp might be problematic. Click here for more details.
- never_primp/__init__.py +151 -2
- never_primp/never_primp.abi3.so +0 -0
- never_primp/never_primp.pyi +50 -2
- never_primp-1.0.2.dist-info/METADATA +803 -0
- never_primp-1.0.2.dist-info/RECORD +8 -0
- never_primp-1.0.0.dist-info/METADATA +0 -358
- never_primp-1.0.0.dist-info/RECORD +0 -8
- {never_primp-1.0.0.dist-info → never_primp-1.0.2.dist-info}/WHEEL +0 -0
- {never_primp-1.0.0.dist-info → never_primp-1.0.2.dist-info}/licenses/LICENSE +0 -0
never_primp/__init__.py
CHANGED
|
@@ -3,7 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import sys
|
|
5
5
|
from functools import partial
|
|
6
|
-
from typing import TYPE_CHECKING, TypedDict
|
|
6
|
+
from typing import TYPE_CHECKING, TypedDict, Iterator
|
|
7
|
+
from collections.abc import MutableMapping
|
|
7
8
|
|
|
8
9
|
if sys.version_info <= (3, 11):
|
|
9
10
|
from typing_extensions import Unpack
|
|
@@ -26,6 +27,112 @@ else:
|
|
|
26
27
|
RequestParams = ClientRequestParams = TypedDict
|
|
27
28
|
|
|
28
29
|
|
|
30
|
+
class CookieJar(MutableMapping):
|
|
31
|
+
"""
|
|
32
|
+
A dict-like container for managing HTTP cookies, compatible with requests.Session.cookies API.
|
|
33
|
+
|
|
34
|
+
Examples:
|
|
35
|
+
client = Client()
|
|
36
|
+
|
|
37
|
+
# Set cookies
|
|
38
|
+
client.cookies['session_id'] = 'abc123'
|
|
39
|
+
client.cookies['user_token'] = 'xyz789'
|
|
40
|
+
|
|
41
|
+
# Get cookies
|
|
42
|
+
value = client.cookies['session_id']
|
|
43
|
+
value = client.cookies.get('user_token', 'default')
|
|
44
|
+
|
|
45
|
+
# Update multiple cookies
|
|
46
|
+
client.cookies.update({'key1': 'value1', 'key2': 'value2'})
|
|
47
|
+
|
|
48
|
+
# Delete cookies
|
|
49
|
+
del client.cookies['session_id']
|
|
50
|
+
|
|
51
|
+
# Clear all cookies
|
|
52
|
+
client.cookies.clear()
|
|
53
|
+
|
|
54
|
+
# Check existence
|
|
55
|
+
if 'session_id' in client.cookies:
|
|
56
|
+
print("Session exists")
|
|
57
|
+
|
|
58
|
+
# Convert to dict
|
|
59
|
+
all_cookies = dict(client.cookies)
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __init__(self, client: RClient):
|
|
63
|
+
"""Initialize CookieJar with a reference to the client."""
|
|
64
|
+
self._client = client
|
|
65
|
+
|
|
66
|
+
def __getitem__(self, name: str) -> str:
|
|
67
|
+
"""Get a cookie value by name."""
|
|
68
|
+
value = self._client.get_cookie(name)
|
|
69
|
+
if value is None:
|
|
70
|
+
raise KeyError(name)
|
|
71
|
+
return value
|
|
72
|
+
|
|
73
|
+
def __setitem__(self, name: str, value: str) -> None:
|
|
74
|
+
"""Set a cookie by name."""
|
|
75
|
+
self._client.set_cookie(name, value)
|
|
76
|
+
|
|
77
|
+
def __delitem__(self, name: str) -> None:
|
|
78
|
+
"""Delete a cookie by name."""
|
|
79
|
+
# Check if cookie exists first
|
|
80
|
+
if self._client.get_cookie(name) is None:
|
|
81
|
+
raise KeyError(name)
|
|
82
|
+
self._client.delete_cookie(name)
|
|
83
|
+
|
|
84
|
+
def __iter__(self) -> Iterator[str]:
|
|
85
|
+
"""Iterate over cookie names."""
|
|
86
|
+
return iter(self._client.get_all_cookies().keys())
|
|
87
|
+
|
|
88
|
+
def __len__(self) -> int:
|
|
89
|
+
"""Return the number of cookies."""
|
|
90
|
+
return len(self._client.get_all_cookies())
|
|
91
|
+
|
|
92
|
+
def __contains__(self, name: object) -> bool:
|
|
93
|
+
"""Check if a cookie exists."""
|
|
94
|
+
if not isinstance(name, str):
|
|
95
|
+
return False
|
|
96
|
+
return self._client.get_cookie(name) is not None
|
|
97
|
+
|
|
98
|
+
def __repr__(self) -> str:
|
|
99
|
+
"""Return string representation of cookies."""
|
|
100
|
+
cookies = self._client.get_all_cookies()
|
|
101
|
+
return f"CookieJar({cookies})"
|
|
102
|
+
|
|
103
|
+
def get(self, name: str, default: str | None = None) -> str | None:
|
|
104
|
+
"""Get a cookie value with a default fallback."""
|
|
105
|
+
value = self._client.get_cookie(name)
|
|
106
|
+
return value if value is not None else default
|
|
107
|
+
|
|
108
|
+
def update(self, cookies: dict[str, str], domain: str | None = None, path: str | None = None) -> None:
|
|
109
|
+
"""
|
|
110
|
+
Update multiple cookies at once.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
cookies: Dictionary of cookie names to values
|
|
114
|
+
domain: Optional domain for the cookies (e.g., ".example.com")
|
|
115
|
+
path: Optional path for the cookies (e.g., "/")
|
|
116
|
+
"""
|
|
117
|
+
self._client.update_cookies(cookies, domain=domain, path=path)
|
|
118
|
+
|
|
119
|
+
def clear(self) -> None:
|
|
120
|
+
"""Remove all cookies."""
|
|
121
|
+
self._client.clear_cookies()
|
|
122
|
+
|
|
123
|
+
def set(self, name: str, value: str, domain: str | None = None, path: str | None = None) -> None:
|
|
124
|
+
"""
|
|
125
|
+
Set a single cookie with optional domain and path.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
name: Cookie name
|
|
129
|
+
value: Cookie value
|
|
130
|
+
domain: Optional domain (e.g., ".example.com")
|
|
131
|
+
path: Optional path (e.g., "/")
|
|
132
|
+
"""
|
|
133
|
+
self._client.set_cookie(name, value, domain=domain, path=path)
|
|
134
|
+
|
|
135
|
+
|
|
29
136
|
class Client(RClient):
|
|
30
137
|
"""Initializes an HTTP client that can impersonate web browsers."""
|
|
31
138
|
|
|
@@ -35,7 +142,9 @@ class Client(RClient):
|
|
|
35
142
|
auth_bearer: str | None = None,
|
|
36
143
|
params: dict[str, str] | None = None,
|
|
37
144
|
headers: dict[str, str] | None = None,
|
|
145
|
+
ordered_headers: dict[str, str] | None = None,
|
|
38
146
|
cookie_store: bool | None = True,
|
|
147
|
+
split_cookies: bool | None = False,
|
|
39
148
|
referer: bool | None = True,
|
|
40
149
|
proxy: str | None = None,
|
|
41
150
|
timeout: float | None = 30,
|
|
@@ -62,8 +171,16 @@ class Client(RClient):
|
|
|
62
171
|
auth_bearer: a string representing the bearer token for bearer token authentication. Default is None.
|
|
63
172
|
params: a map of query parameters to append to the URL. Default is None.
|
|
64
173
|
headers: an optional map of HTTP headers to send with requests. Ignored if `impersonate` is set.
|
|
174
|
+
ordered_headers: an optional ordered map of HTTP headers with strict order preservation.
|
|
175
|
+
Takes priority over `headers`. Use this for bypassing anti-bot detection that checks header order.
|
|
176
|
+
Example: {"User-Agent": "...", "Accept": "...", "Accept-Language": "..."}
|
|
177
|
+
Note: Python 3.7+ dict maintains insertion order by default.
|
|
65
178
|
cookie_store: enable a persistent cookie store. Received cookies will be preserved and included
|
|
66
179
|
in additional requests. Default is True.
|
|
180
|
+
split_cookies: split cookies into multiple `cookie` headers (HTTP/2 style) instead of a single
|
|
181
|
+
`Cookie` header. Useful for mimicking browser behavior in HTTP/2. Default is False.
|
|
182
|
+
When True: cookie: a=1 \n cookie: b=2 \n cookie: c=3
|
|
183
|
+
When False: Cookie: a=1; b=2; c=3
|
|
67
184
|
referer: automatic setting of the `Referer` header. Default is True.
|
|
68
185
|
proxy: proxy URL for HTTP requests, example: "socks5://127.0.0.1:9150". Default is None.
|
|
69
186
|
timeout: timeout for HTTP requests in seconds. Default is 30.
|
|
@@ -93,6 +210,35 @@ class Client(RClient):
|
|
|
93
210
|
http2_only: if true - use only HTTP/2, if false - use only HTTP/1. Default is False.
|
|
94
211
|
"""
|
|
95
212
|
super().__init__()
|
|
213
|
+
self._cookies_jar: CookieJar | None = None
|
|
214
|
+
|
|
215
|
+
@property
|
|
216
|
+
def cookies(self) -> CookieJar:
|
|
217
|
+
"""
|
|
218
|
+
Access the cookie jar for dict-like cookie management.
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
CookieJar: A dict-like container for managing cookies.
|
|
222
|
+
|
|
223
|
+
Examples:
|
|
224
|
+
# Set cookies
|
|
225
|
+
client.cookies['session_id'] = 'abc123'
|
|
226
|
+
|
|
227
|
+
# Get cookies
|
|
228
|
+
value = client.cookies['session_id']
|
|
229
|
+
|
|
230
|
+
# Update cookies
|
|
231
|
+
client.cookies.update({'key': 'value'})
|
|
232
|
+
|
|
233
|
+
# Delete cookies
|
|
234
|
+
del client.cookies['session_id']
|
|
235
|
+
|
|
236
|
+
# Clear all
|
|
237
|
+
client.cookies.clear()
|
|
238
|
+
"""
|
|
239
|
+
if self._cookies_jar is None:
|
|
240
|
+
self._cookies_jar = CookieJar(self)
|
|
241
|
+
return self._cookies_jar
|
|
96
242
|
|
|
97
243
|
def __enter__(self) -> Client:
|
|
98
244
|
return self
|
|
@@ -131,7 +277,9 @@ class AsyncClient(Client):
|
|
|
131
277
|
auth_bearer: str | None = None,
|
|
132
278
|
params: dict[str, str] | None = None,
|
|
133
279
|
headers: dict[str, str] | None = None,
|
|
280
|
+
ordered_headers: dict[str, str] | None = None,
|
|
134
281
|
cookie_store: bool | None = True,
|
|
282
|
+
split_cookies: bool | None = False,
|
|
135
283
|
referer: bool | None = True,
|
|
136
284
|
proxy: str | None = None,
|
|
137
285
|
timeout: float | None = 30,
|
|
@@ -150,7 +298,8 @@ class AsyncClient(Client):
|
|
|
150
298
|
tcp_keepalive: float | None = None,
|
|
151
299
|
# Retry mechanism
|
|
152
300
|
retry_count: int | None = None,
|
|
153
|
-
retry_backoff: float | None = None
|
|
301
|
+
retry_backoff: float | None = None,
|
|
302
|
+
):
|
|
154
303
|
super().__init__()
|
|
155
304
|
|
|
156
305
|
async def __aenter__(self) -> AsyncClient:
|
never_primp/never_primp.abi3.so
CHANGED
|
Binary file
|
never_primp/never_primp.pyi
CHANGED
|
@@ -38,6 +38,7 @@ class RequestParams(TypedDict, total=False):
|
|
|
38
38
|
auth_bearer: str | None
|
|
39
39
|
params: dict[str, str] | None
|
|
40
40
|
headers: dict[str, str] | None
|
|
41
|
+
ordered_headers: dict[str, str] | None
|
|
41
42
|
cookies: dict[str, str] | None
|
|
42
43
|
timeout: float | None
|
|
43
44
|
content: bytes | None
|
|
@@ -82,8 +83,10 @@ class RClient:
|
|
|
82
83
|
auth_bearer: str | None = None,
|
|
83
84
|
params: dict[str, str] | None = None,
|
|
84
85
|
headers: dict[str, str] | None = None,
|
|
86
|
+
ordered_headers: dict[str, str] | None = None,
|
|
85
87
|
timeout: float | None = None,
|
|
86
88
|
cookie_store: bool | None = True,
|
|
89
|
+
split_cookies: bool | None = False,
|
|
87
90
|
referer: bool | None = True,
|
|
88
91
|
proxy: str | None = None,
|
|
89
92
|
impersonate: IMPERSONATE | None = None,
|
|
@@ -94,14 +97,59 @@ class RClient:
|
|
|
94
97
|
ca_cert_file: str | None = None,
|
|
95
98
|
https_only: bool | None = False,
|
|
96
99
|
http2_only: bool | None = False,
|
|
100
|
+
pool_idle_timeout: float | None = None,
|
|
101
|
+
pool_max_idle_per_host: int | None = None,
|
|
102
|
+
tcp_nodelay: bool | None = None,
|
|
103
|
+
tcp_keepalive: float | None = None,
|
|
104
|
+
retry_count: int | None = None,
|
|
105
|
+
retry_backoff: float | None = None,
|
|
97
106
|
): ...
|
|
98
107
|
@property
|
|
99
108
|
def headers(self) -> dict[str, str]: ...
|
|
100
109
|
@headers.setter
|
|
101
110
|
def headers(self, headers: dict[str, str]) -> None: ...
|
|
102
111
|
def headers_update(self, headers: dict[str, str]) -> None: ...
|
|
103
|
-
|
|
104
|
-
def
|
|
112
|
+
@property
|
|
113
|
+
def ordered_headers(self) -> dict[str, str]: ...
|
|
114
|
+
@ordered_headers.setter
|
|
115
|
+
def ordered_headers(self, ordered_headers: dict[str, str]) -> None: ...
|
|
116
|
+
def ordered_headers_update(self, ordered_headers: dict[str, str]) -> None: ...
|
|
117
|
+
# Cookie management methods (no URL required)
|
|
118
|
+
def get_all_cookies(self) -> dict[str, str]: ...
|
|
119
|
+
def set_cookie(self, name: str, value: str, domain: str | None = None, path: str | None = None) -> None: ...
|
|
120
|
+
def get_cookie(self, name: str) -> str | None: ...
|
|
121
|
+
def update_cookies(self, cookies: dict[str, str], domain: str | None = None, path: str | None = None) -> None: ...
|
|
122
|
+
def delete_cookie(self, name: str) -> None: ...
|
|
123
|
+
def clear_cookies(self) -> None: ...
|
|
124
|
+
# Client properties
|
|
125
|
+
@property
|
|
126
|
+
def auth(self) -> tuple[str, str | None] | None: ...
|
|
127
|
+
@auth.setter
|
|
128
|
+
def auth(self, auth: tuple[str, str | None] | None) -> None: ...
|
|
129
|
+
@property
|
|
130
|
+
def auth_bearer(self) -> str | None: ...
|
|
131
|
+
@auth_bearer.setter
|
|
132
|
+
def auth_bearer(self, auth_bearer: str | None) -> None: ...
|
|
133
|
+
@property
|
|
134
|
+
def params(self) -> dict[str, str] | None: ...
|
|
135
|
+
@params.setter
|
|
136
|
+
def params(self, params: dict[str, str] | None) -> None: ...
|
|
137
|
+
@property
|
|
138
|
+
def timeout(self) -> float | None: ...
|
|
139
|
+
@timeout.setter
|
|
140
|
+
def timeout(self, timeout: float | None) -> None: ...
|
|
141
|
+
@property
|
|
142
|
+
def split_cookies(self) -> bool | None: ...
|
|
143
|
+
@split_cookies.setter
|
|
144
|
+
def split_cookies(self, split_cookies: bool | None) -> None: ...
|
|
145
|
+
@property
|
|
146
|
+
def retry_count(self) -> int | None: ...
|
|
147
|
+
@retry_count.setter
|
|
148
|
+
def retry_count(self, retry_count: int | None) -> None: ...
|
|
149
|
+
@property
|
|
150
|
+
def retry_backoff(self) -> float | None: ...
|
|
151
|
+
@retry_backoff.setter
|
|
152
|
+
def retry_backoff(self, retry_backoff: float | None) -> None: ...
|
|
105
153
|
@property
|
|
106
154
|
def proxy(self) -> str | None: ...
|
|
107
155
|
@proxy.setter
|