never-primp 1.2.2__cp38-abi3-macosx_11_0_arm64.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.
@@ -0,0 +1,653 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import sys
5
+ from functools import partial
6
+ from typing import TYPE_CHECKING, TypedDict, Iterator
7
+ from collections.abc import MutableMapping
8
+
9
+ if sys.version_info <= (3, 11):
10
+ from typing_extensions import Unpack
11
+ else:
12
+ from typing import Unpack
13
+
14
+
15
+ from .never_primp import RClient
16
+
17
+ if TYPE_CHECKING:
18
+ from .never_primp import IMPERSONATE, IMPERSONATE_OS, ClientRequestParams, HttpMethod, RequestParams, Response
19
+ else:
20
+
21
+ class _Unpack:
22
+ @staticmethod
23
+ def __getitem__(*args, **kwargs):
24
+ pass
25
+
26
+ Unpack = _Unpack()
27
+ RequestParams = ClientRequestParams = TypedDict
28
+
29
+
30
+ class HeadersJar(MutableMapping):
31
+ """
32
+ A dict-like container for managing HTTP headers, compatible with requests.Session.headers API.
33
+
34
+ Examples:
35
+ client = Client()
36
+
37
+ # Set headers
38
+ client.headers['User-Agent'] = 'CustomAgent/1.0'
39
+ client.headers['Accept'] = 'application/json'
40
+
41
+ # Get headers
42
+ value = client.headers['User-Agent']
43
+ value = client.headers.get('Accept', 'default')
44
+
45
+ # Update multiple headers
46
+ client.headers.update({'X-Custom': 'value1', 'X-Another': 'value2'})
47
+
48
+ # Delete headers
49
+ del client.headers['User-Agent']
50
+
51
+ # Clear all headers
52
+ client.headers.clear()
53
+
54
+ # Check existence
55
+ if 'User-Agent' in client.headers:
56
+ print("User-Agent exists")
57
+
58
+ # Convert to dict
59
+ all_headers = dict(client.headers)
60
+ """
61
+
62
+ def __init__(self, client: RClient):
63
+ """Initialize HeadersJar with a reference to the client."""
64
+ self._client = client
65
+
66
+ def __getitem__(self, name: str) -> str:
67
+ """Get a header value by name."""
68
+ value = self._client.get_header(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 header by name."""
75
+ self._client.set_header(name, value)
76
+
77
+ def __delitem__(self, name: str) -> None:
78
+ """Delete a header by name."""
79
+ # Check if header exists first
80
+ if self._client.get_header(name) is None:
81
+ raise KeyError(name)
82
+ self._client.delete_header(name)
83
+
84
+ def __iter__(self) -> Iterator[str]:
85
+ """Iterate over header names."""
86
+ return iter(self._client.get_headers().keys())
87
+
88
+ def __len__(self) -> int:
89
+ """Return the number of headers."""
90
+ return len(self._client.get_headers())
91
+
92
+ def __contains__(self, name: object) -> bool:
93
+ """Check if a header exists."""
94
+ if not isinstance(name, str):
95
+ return False
96
+ return self._client.get_header(name) is not None
97
+
98
+ def __repr__(self) -> str:
99
+ """Return string representation of headers."""
100
+ headers = self._client.get_headers()
101
+ return f"HeadersJar({headers})"
102
+
103
+ def get(self, name: str, default: str | None = None) -> str | None:
104
+ """Get a header value with a default fallback."""
105
+ value = self._client.get_header(name)
106
+ return value if value is not None else default
107
+
108
+ def update(self, headers: dict[str, str]) -> None:
109
+ """
110
+ Update multiple headers at once.
111
+
112
+ Args:
113
+ headers: Dictionary of header names to values
114
+ """
115
+ self._client.headers_update(headers)
116
+
117
+ def clear(self) -> None:
118
+ """Remove all headers."""
119
+ self._client.clear_headers()
120
+
121
+ def set(self, name: str, value: str) -> None:
122
+ """
123
+ Set a single header.
124
+
125
+ Args:
126
+ name: Header name
127
+ value: Header value
128
+ """
129
+ self._client.set_header(name, value)
130
+
131
+
132
+ class CookieJar(MutableMapping):
133
+ """
134
+ A dict-like container for managing HTTP cookies, compatible with requests.Session.cookies API.
135
+
136
+ Examples:
137
+ client = Client()
138
+
139
+ # Set cookies
140
+ client.cookies['session_id'] = 'abc123'
141
+ client.cookies['user_token'] = 'xyz789'
142
+
143
+ # Get cookies
144
+ value = client.cookies['session_id']
145
+ value = client.cookies.get('user_token', 'default')
146
+
147
+ # Update multiple cookies
148
+ client.cookies.update({'key1': 'value1', 'key2': 'value2'})
149
+
150
+ # Delete cookies
151
+ del client.cookies['session_id']
152
+
153
+ # Clear all cookies
154
+ client.cookies.clear()
155
+
156
+ # Check existence
157
+ if 'session_id' in client.cookies:
158
+ print("Session exists")
159
+
160
+ # Convert to dict
161
+ all_cookies = dict(client.cookies)
162
+ """
163
+
164
+ def __init__(self, client: RClient):
165
+ """Initialize CookieJar with a reference to the client."""
166
+ self._client = client
167
+
168
+ def __getitem__(self, name: str) -> str:
169
+ """Get a cookie value by name."""
170
+ value = self._client.get_cookie(name)
171
+ if value is None:
172
+ raise KeyError(name)
173
+ return value
174
+
175
+ def __setitem__(self, name: str, value: str) -> None:
176
+ """Set a cookie by name."""
177
+ self._client.set_cookie(name, value)
178
+
179
+ def __delitem__(self, name: str) -> None:
180
+ """Delete a cookie by name."""
181
+ # Check if cookie exists first
182
+ if self._client.get_cookie(name) is None:
183
+ raise KeyError(name)
184
+ self._client.delete_cookie(name)
185
+
186
+ def __iter__(self) -> Iterator[str]:
187
+ """Iterate over cookie names."""
188
+ return iter(self._client.get_all_cookies().keys())
189
+
190
+ def __len__(self) -> int:
191
+ """Return the number of cookies."""
192
+ return len(self._client.get_all_cookies())
193
+
194
+ def __contains__(self, name: object) -> bool:
195
+ """Check if a cookie exists."""
196
+ if not isinstance(name, str):
197
+ return False
198
+ return self._client.get_cookie(name) is not None
199
+
200
+ def __repr__(self) -> str:
201
+ """Return string representation of cookies."""
202
+ cookies = self._client.get_all_cookies()
203
+ return f"CookieJar({cookies})"
204
+
205
+ def get(self, name: str, default: str | None = None) -> str | None:
206
+ """Get a cookie value with a default fallback."""
207
+ value = self._client.get_cookie(name)
208
+ return value if value is not None else default
209
+
210
+ def update(self, cookies: dict[str, str], domain: str | None = None, path: str | None = None) -> None:
211
+ """
212
+ Update multiple cookies at once.
213
+
214
+ Args:
215
+ cookies: Dictionary of cookie names to values
216
+ domain: Optional domain for the cookies (e.g., ".example.com")
217
+ path: Optional path for the cookies (e.g., "/")
218
+ """
219
+ self._client.update_cookies(cookies, domain=domain, path=path)
220
+
221
+ def clear(self) -> None:
222
+ """Remove all cookies."""
223
+ self._client.clear_cookies()
224
+
225
+ def set(self, name: str, value: str, domain: str | None = None, path: str | None = None) -> None:
226
+ """
227
+ Set a single cookie with optional domain and path.
228
+
229
+ Args:
230
+ name: Cookie name
231
+ value: Cookie value
232
+ domain: Optional domain (e.g., ".example.com")
233
+ path: Optional path (e.g., "/")
234
+ """
235
+ self._client.set_cookie(name, value, domain=domain, path=path)
236
+
237
+
238
+ class Client(RClient):
239
+ """Initializes an HTTP client that can impersonate web browsers."""
240
+
241
+ def __init__(
242
+ self,
243
+ auth: tuple[str, str | None] | None = None,
244
+ auth_bearer: str | None = None,
245
+ params: dict[str, str] | None = None,
246
+ headers: dict[str, str] | None = None,
247
+ cookies: dict[str, str] | None = None,
248
+ cookie_store: bool | None = True,
249
+ split_cookies: bool | None = False,
250
+ referer: bool | None = True,
251
+ proxy: str | None = None,
252
+ timeout: float | None = 30,
253
+ impersonate: IMPERSONATE | None = None,
254
+ impersonate_os: IMPERSONATE_OS | None = None,
255
+ follow_redirects: bool | None = True,
256
+ max_redirects: int | None = 20,
257
+ verify: bool | None = True,
258
+ ca_cert_file: str | None = None,
259
+ https_only: bool | None = False,
260
+ http1_only: bool | None = False,
261
+ http2_only: bool | None = False,
262
+ pool_idle_timeout: float | None = None,
263
+ pool_max_idle_per_host: int | None = None,
264
+ tcp_nodelay: bool | None = None,
265
+ tcp_keepalive: float | None = None,
266
+ ):
267
+ """
268
+ Args:
269
+ auth: a tuple containing the username and an optional password for basic authentication. Default is None.
270
+ auth_bearer: a string representing the bearer token for bearer token authentication. Default is None.
271
+ params: a map of query parameters to append to the URL. Default is None.
272
+ headers: an optional ordered map of HTTP headers with strict order preservation.
273
+ Headers will be sent in the exact order specified, with automatic positioning of:
274
+ - Host (first position)
275
+ - Content-Length (second position for POST/PUT/PATCH)
276
+ - Content-Type (third position if auto-calculated)
277
+ - cookie (second-to-last position)
278
+ - priority (last position)
279
+ Example: {"User-Agent": "...", "Accept": "...", "Accept-Language": "..."}
280
+ Note: Python 3.7+ dict maintains insertion order by default.
281
+ cookies: initial cookies to set for the client. These cookies will be included in all requests.
282
+ Can be updated later using client.cookies.update(). Default is None.
283
+ cookie_store: enable a persistent cookie store. Received cookies will be preserved and included
284
+ in additional requests. Default is True.
285
+ split_cookies: split cookies into multiple `cookie` headers (HTTP/2 style) instead of a single
286
+ `Cookie` header. Useful for mimicking browser behavior in HTTP/2. Default is False.
287
+ When True: cookie: a=1 \n cookie: b=2 \n cookie: c=3
288
+ When False: Cookie: a=1; b=2; c=3
289
+ referer: automatic setting of the `Referer` header. Default is True.
290
+ proxy: proxy URL for HTTP requests, example: "socks5://127.0.0.1:9150". Default is None.
291
+ timeout: timeout for HTTP requests in seconds. Default is 30.
292
+ impersonate: impersonate browser. Supported browsers:
293
+ "chrome_100", "chrome_101", "chrome_104", "chrome_105", "chrome_106",
294
+ "chrome_107", "chrome_108", "chrome_109", "chrome_114", "chrome_116",
295
+ "chrome_117", "chrome_118", "chrome_119", "chrome_120", "chrome_123",
296
+ "chrome_124", "chrome_126", "chrome_127", "chrome_128", "chrome_129",
297
+ "chrome_130", "chrome_131", "chrome_133"
298
+ "safari_15.3", "safari_15.5", "safari_15.6.1", "safari_16",
299
+ "safari_16.5", "safari_17.0", "safari_17.2.1", "safari_17.4.1",
300
+ "safari_17.5", "safari_18", "safari_18.2",
301
+ "safari_ios_16.5", "safari_ios_17.2", "safari_ios_17.4.1", "safari_ios_18.1.1",
302
+ "safari_ipad_18",
303
+ "okhttp_3.9", "okhttp_3.11", "okhttp_3.13", "okhttp_3.14", "okhttp_4.9",
304
+ "okhttp_4.10", "okhttp_5",
305
+ "edge_101", "edge_122", "edge_127", "edge_131",
306
+ "firefox_109", "firefox_117", "firefox_128", "firefox_133", "firefox_135".
307
+ Default is None.
308
+ impersonate_os: impersonate OS. Supported OS:
309
+ "android", "ios", "linux", "macos", "windows". Default is None.
310
+ follow_redirects: a boolean to enable or disable following redirects. Default is True.
311
+ max_redirects: the maximum number of redirects if `follow_redirects` is True. Default is 20.
312
+ verify: an optional boolean indicating whether to verify SSL certificates. Default is True.
313
+ ca_cert_file: path to CA certificate store. Default is None.
314
+ https_only: restrict the Client to be used with HTTPS only requests. Default is False.
315
+ http1_only: if true - use only HTTP/1.1. Default is False.
316
+ http2_only: if true - use only HTTP/2. Default is False.
317
+ Note: http1_only and http2_only are mutually exclusive. If both are true, http1_only takes precedence.
318
+ """
319
+ super().__init__()
320
+ self._cookies_jar: CookieJar | None = None
321
+ self._headers_jar: HeadersJar | None = None
322
+
323
+ # Set initial cookies if provided
324
+ if cookies:
325
+ self.update_cookies(cookies)
326
+
327
+ @property
328
+ def headers(self) -> HeadersJar:
329
+ """
330
+ Access the headers for dict-like header management.
331
+
332
+ Returns:
333
+ HeadersJar: A dict-like container for managing headers.
334
+
335
+ Examples:
336
+ # Set headers
337
+ client.headers['User-Agent'] = 'CustomAgent/1.0'
338
+
339
+ # Get headers
340
+ value = client.headers['User-Agent']
341
+
342
+ # Update headers
343
+ client.headers.update({'Accept': 'application/json'})
344
+
345
+ # Delete headers
346
+ del client.headers['User-Agent']
347
+
348
+ # Clear all
349
+ client.headers.clear()
350
+ """
351
+ if self._headers_jar is None:
352
+ self._headers_jar = HeadersJar(self)
353
+ return self._headers_jar
354
+
355
+ @property
356
+ def cookies(self) -> CookieJar:
357
+ """
358
+ Access the cookie jar for dict-like cookie management.
359
+
360
+ Returns:
361
+ CookieJar: A dict-like container for managing cookies.
362
+
363
+ Examples:
364
+ # Set cookies
365
+ client.cookies['session_id'] = 'abc123'
366
+
367
+ # Get cookies
368
+ value = client.cookies['session_id']
369
+
370
+ # Update cookies
371
+ client.cookies.update({'key': 'value'})
372
+
373
+ # Delete cookies
374
+ del client.cookies['session_id']
375
+
376
+ # Clear all
377
+ client.cookies.clear()
378
+ """
379
+ if self._cookies_jar is None:
380
+ self._cookies_jar = CookieJar(self)
381
+ return self._cookies_jar
382
+
383
+ def __enter__(self) -> Client:
384
+ return self
385
+
386
+ def __exit__(self, *args):
387
+ del self
388
+
389
+ def request(self, method: HttpMethod, url: str, **kwargs: Unpack[RequestParams]) -> Response:
390
+ """
391
+ Send an HTTP request with support for requests-toolbelt MultipartEncoder.
392
+
393
+ Supports both native primp format and requests-toolbelt MultipartEncoder:
394
+ - Native: request(url, data={...}, files={...})
395
+ - Toolbelt: request(url, data=MultipartEncoder(...))
396
+ """
397
+ # Check if data is a MultipartEncoder from requests-toolbelt
398
+ data = kwargs.get('data')
399
+ if data is not None and hasattr(data, 'fields') and hasattr(data, 'content_type'):
400
+ # This looks like a MultipartEncoder
401
+ # Extract fields and convert to primp format
402
+ converted_data = {}
403
+ converted_files = {}
404
+
405
+ try:
406
+ # MultipartEncoder.fields is a dict-like object
407
+ for field_name, field_value in data.fields.items():
408
+ if isinstance(field_value, tuple):
409
+ # File field: (filename, file_obj, content_type)
410
+ if len(field_value) >= 2:
411
+ filename = field_value[0]
412
+ file_obj = field_value[1]
413
+
414
+ # Read the file content
415
+ if hasattr(file_obj, 'read'):
416
+ file_content = file_obj.read()
417
+ # Reset file pointer if possible
418
+ if hasattr(file_obj, 'seek'):
419
+ try:
420
+ file_obj.seek(0)
421
+ except:
422
+ pass
423
+ else:
424
+ file_content = file_obj
425
+
426
+ # Add mime type if provided
427
+ if len(field_value) >= 3:
428
+ mime_type = field_value[2]
429
+ converted_files[field_name] = (filename, file_content, mime_type)
430
+ else:
431
+ converted_files[field_name] = (filename, file_content)
432
+ else:
433
+ # Regular field
434
+ if isinstance(field_value, bytes):
435
+ converted_data[field_name] = field_value.decode('utf-8')
436
+ else:
437
+ converted_data[field_name] = str(field_value)
438
+
439
+ # Replace data and files in kwargs
440
+ if converted_data:
441
+ kwargs['data'] = converted_data
442
+ else:
443
+ kwargs.pop('data', None)
444
+
445
+ if converted_files:
446
+ kwargs['files'] = converted_files
447
+
448
+ except Exception as e:
449
+ # If conversion fails, fall back to treating it as raw content
450
+ # Read the encoder as bytes and send as content
451
+ if hasattr(data, 'read'):
452
+ kwargs['content'] = data.read()
453
+ kwargs.pop('data', None)
454
+
455
+ # Get content type from encoder
456
+ if hasattr(data, 'content_type'):
457
+ headers = kwargs.get('headers', {})
458
+ if not isinstance(headers, dict):
459
+ headers = dict(headers)
460
+ headers['Content-Type'] = data.content_type
461
+ kwargs['headers'] = headers
462
+
463
+ return super().request(method=method, url=url, **kwargs)
464
+
465
+ def get(self, url: str, **kwargs: Unpack[RequestParams]) -> Response:
466
+ return self.request(method="GET", url=url, **kwargs)
467
+
468
+ def head(self, url: str, **kwargs: Unpack[RequestParams]) -> Response:
469
+ return self.request(method="HEAD", url=url, **kwargs)
470
+
471
+ def options(self, url: str, **kwargs: Unpack[RequestParams]) -> Response:
472
+ return self.request(method="OPTIONS", url=url, **kwargs)
473
+
474
+ def delete(self, url: str, **kwargs: Unpack[RequestParams]) -> Response:
475
+ return self.request(method="DELETE", url=url, **kwargs)
476
+
477
+ def post(self, url: str, **kwargs: Unpack[RequestParams]) -> Response:
478
+ return self.request(method="POST", url=url, **kwargs)
479
+
480
+ def put(self, url: str, **kwargs: Unpack[RequestParams]) -> Response:
481
+ return self.request(method="PUT", url=url, **kwargs)
482
+
483
+ def patch(self, url: str, **kwargs: Unpack[RequestParams]) -> Response:
484
+ return self.request(method="PATCH", url=url, **kwargs)
485
+
486
+
487
+ class AsyncClient(Client):
488
+ def __init__(self,
489
+ auth: tuple[str, str | None] | None = None,
490
+ auth_bearer: str | None = None,
491
+ params: dict[str, str] | None = None,
492
+ headers: dict[str, str] | None = None,
493
+ cookies: dict[str, str] | None = None,
494
+ cookie_store: bool | None = True,
495
+ split_cookies: bool | None = False,
496
+ referer: bool | None = True,
497
+ proxy: str | None = None,
498
+ timeout: float | None = None,
499
+ impersonate: IMPERSONATE | None = None,
500
+ impersonate_os: IMPERSONATE_OS | None = None,
501
+ follow_redirects: bool | None = True,
502
+ max_redirects: int | None = 20,
503
+ verify: bool | None = True,
504
+ ca_cert_file: str | None = None,
505
+ https_only: bool | None = False,
506
+ http1_only: bool | None = False,
507
+ http2_only: bool | None = False,
508
+ # Performance optimization parameters
509
+ pool_idle_timeout: float | None = None,
510
+ pool_max_idle_per_host: int | None = None,
511
+ tcp_nodelay: bool | None = None,
512
+ tcp_keepalive: float | None = None,
513
+ ):
514
+ super().__init__(
515
+ auth=auth,
516
+ auth_bearer=auth_bearer,
517
+ params=params,
518
+ headers=headers,
519
+ cookies=cookies,
520
+ cookie_store=cookie_store,
521
+ split_cookies=split_cookies,
522
+ referer=referer,
523
+ proxy=proxy,
524
+ timeout=timeout,
525
+ impersonate=impersonate,
526
+ impersonate_os=impersonate_os,
527
+ follow_redirects=follow_redirects,
528
+ max_redirects=max_redirects,
529
+ verify=verify,
530
+ ca_cert_file=ca_cert_file,
531
+ https_only=https_only,
532
+ http1_only=http1_only,
533
+ http2_only=http2_only,
534
+ pool_idle_timeout=pool_idle_timeout,
535
+ pool_max_idle_per_host=pool_max_idle_per_host,
536
+ tcp_nodelay=tcp_nodelay,
537
+ tcp_keepalive=tcp_keepalive,
538
+ )
539
+
540
+ async def __aenter__(self) -> AsyncClient:
541
+ return self
542
+
543
+ async def __aexit__(self, *args):
544
+ del self
545
+
546
+ async def _run_sync_asyncio(self, fn, *args, **kwargs):
547
+ loop = asyncio.get_running_loop()
548
+ return await loop.run_in_executor(None, partial(fn, *args, **kwargs))
549
+
550
+ async def request(self, method: HttpMethod, url: str, **kwargs: Unpack[RequestParams]): # type: ignore
551
+ return await self._run_sync_asyncio(super().request, method=method, url=url, **kwargs)
552
+
553
+ async def get(self, url: str, **kwargs: Unpack[RequestParams]): # type: ignore
554
+ return await self.request(method="GET", url=url, **kwargs)
555
+
556
+ async def head(self, url: str, **kwargs: Unpack[RequestParams]): # type: ignore
557
+ return await self.request(method="HEAD", url=url, **kwargs)
558
+
559
+ async def options(self, url: str, **kwargs: Unpack[RequestParams]): # type: ignore
560
+ return await self.request(method="OPTIONS", url=url, **kwargs)
561
+
562
+ async def delete(self, url: str, **kwargs: Unpack[RequestParams]): # type: ignore
563
+ return await self.request(method="DELETE", url=url, **kwargs)
564
+
565
+ async def post(self, url: str, **kwargs: Unpack[RequestParams]): # type: ignore
566
+ return await self.request(method="POST", url=url, **kwargs)
567
+
568
+ async def put(self, url: str, **kwargs: Unpack[RequestParams]): # type: ignore
569
+ return await self.request(method="PUT", url=url, **kwargs)
570
+
571
+ async def patch(self, url: str, **kwargs: Unpack[RequestParams]): # type: ignore
572
+ return await self.request(method="PATCH", url=url, **kwargs)
573
+
574
+
575
+ def request(
576
+ method: HttpMethod,
577
+ url: str,
578
+ impersonate: IMPERSONATE | None = None,
579
+ impersonate_os: IMPERSONATE_OS | None = None,
580
+ verify: bool | None = True,
581
+ ca_cert_file: str | None = None,
582
+ **kwargs: Unpack[RequestParams],
583
+ ):
584
+ """
585
+ Args:
586
+ method: the HTTP method to use (e.g., "GET", "POST").
587
+ url: the URL to which the request will be made.
588
+ impersonate: impersonate browser. Supported browsers:
589
+ "chrome_100", "chrome_101", "chrome_104", "chrome_105", "chrome_106",
590
+ "chrome_107", "chrome_108", "chrome_109", "chrome_114", "chrome_116",
591
+ "chrome_117", "chrome_118", "chrome_119", "chrome_120", "chrome_123",
592
+ "chrome_124", "chrome_126", "chrome_127", "chrome_128", "chrome_129",
593
+ "chrome_130", "chrome_131", "chrome_133",
594
+ "safari_15.3", "safari_15.5", "safari_15.6.1", "safari_16",
595
+ "safari_16.5", "safari_17.0", "safari_17.2.1", "safari_17.4.1",
596
+ "safari_17.5", "safari_18", "safari_18.2",
597
+ "safari_ios_16.5", "safari_ios_17.2", "safari_ios_17.4.1", "safari_ios_18.1.1",
598
+ "safari_ipad_18",
599
+ "okhttp_3.9", "okhttp_3.11", "okhttp_3.13", "okhttp_3.14", "okhttp_4.9",
600
+ "okhttp_4.10", "okhttp_5",
601
+ "edge_101", "edge_122", "edge_127", "edge_131",
602
+ "firefox_109", "firefox_117", "firefox_128", "firefox_133", "firefox_135".
603
+ Default is None.
604
+ impersonate_os: impersonate OS. Supported OS:
605
+ "android", "ios", "linux", "macos", "windows". Default is None.
606
+ verify: an optional boolean indicating whether to verify SSL certificates. Default is True.
607
+ ca_cert_file: path to CA certificate store. Default is None.
608
+ auth: a tuple containing the username and an optional password for basic authentication. Default is None.
609
+ auth_bearer: a string representing the bearer token for bearer token authentication. Default is None.
610
+ params: a map of query parameters to append to the URL. Default is None.
611
+ headers: an optional map of HTTP headers to send with requests. If `impersonate` is set, this will be ignored.
612
+ cookies: an optional map of cookies to send with requests as the `Cookie` header.
613
+ timeout: the timeout for the request in seconds. Default is 30.
614
+ content: the content to send in the request body as bytes. Default is None.
615
+ data: the form data to send in the request body. Default is None.
616
+ json: a JSON serializable object to send in the request body. Default is None.
617
+ files: a map of file fields to file paths to be sent as multipart/form-data. Default is None.
618
+ """
619
+ with Client(
620
+ impersonate=impersonate,
621
+ impersonate_os=impersonate_os,
622
+ verify=verify,
623
+ ca_cert_file=ca_cert_file,
624
+ ) as client:
625
+ return client.request(method, url, **kwargs)
626
+
627
+
628
+ def get(url: str, **kwargs: Unpack[ClientRequestParams]):
629
+ return request(method="GET", url=url, **kwargs)
630
+
631
+
632
+ def head(url: str, **kwargs: Unpack[ClientRequestParams]):
633
+ return request(method="HEAD", url=url, **kwargs)
634
+
635
+
636
+ def options(url: str, **kwargs: Unpack[ClientRequestParams]):
637
+ return request(method="OPTIONS", url=url, **kwargs)
638
+
639
+
640
+ def delete(url: str, **kwargs: Unpack[ClientRequestParams]):
641
+ return request(method="DELETE", url=url, **kwargs)
642
+
643
+
644
+ def post(url: str, **kwargs: Unpack[ClientRequestParams]):
645
+ return request(method="POST", url=url, **kwargs)
646
+
647
+
648
+ def put(url: str, **kwargs: Unpack[ClientRequestParams]):
649
+ return request(method="PUT", url=url, **kwargs)
650
+
651
+
652
+ def patch(url: str, **kwargs: Unpack[ClientRequestParams]):
653
+ return request(method="PATCH", url=url, **kwargs)
Binary file