httpr 0.1.17__cp39-abi3-win_amd64.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.
httpr/__init__.py ADDED
@@ -0,0 +1,870 @@
1
+ """
2
+ httpr - Blazing fast HTTP client for Python, built in Rust.
3
+
4
+ httpr is a high-performance HTTP client that can be used as a drop-in replacement
5
+ for `httpx` and `requests` in most cases.
6
+
7
+ Example:
8
+ Simple GET request:
9
+
10
+ ```python
11
+ import httpr
12
+
13
+ response = httpr.get("https://httpbin.org/get")
14
+ print(response.json())
15
+ ```
16
+
17
+ Using a client for connection pooling:
18
+
19
+ ```python
20
+ import httpr
21
+
22
+ with httpr.Client() as client:
23
+ response = client.get("https://httpbin.org/get")
24
+ print(response.status_code)
25
+ ```
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import asyncio
31
+ import sys
32
+ from functools import partial
33
+ from typing import TYPE_CHECKING, Any, TypedDict
34
+
35
+ if sys.version_info <= (3, 11):
36
+ from typing_extensions import Unpack
37
+ else:
38
+ from typing import Unpack
39
+
40
+
41
+ from .httpr import RClient
42
+
43
+ if TYPE_CHECKING:
44
+ from .httpr import ClientRequestParams, HttpMethod, RequestParams, Response
45
+ else:
46
+
47
+ class _Unpack:
48
+ @staticmethod
49
+ def __getitem__(*args, **kwargs):
50
+ pass
51
+
52
+ Unpack = _Unpack()
53
+ RequestParams = ClientRequestParams = TypedDict
54
+
55
+
56
+ class Client(RClient):
57
+ """
58
+ A synchronous HTTP client with connection pooling.
59
+
60
+ The Client class provides a high-level interface for making HTTP requests.
61
+ It supports connection pooling, automatic cookie handling, and various
62
+ authentication methods.
63
+
64
+ Example:
65
+ Basic usage:
66
+
67
+ ```python
68
+ import httpr
69
+
70
+ # Using context manager (recommended)
71
+ with httpr.Client() as client:
72
+ response = client.get("https://httpbin.org/get")
73
+ print(response.json())
74
+
75
+ # Or manually
76
+ client = httpr.Client()
77
+ response = client.get("https://httpbin.org/get")
78
+ client.close()
79
+ ```
80
+
81
+ With configuration:
82
+
83
+ ```python
84
+ import httpr
85
+
86
+ client = httpr.Client(
87
+ auth_bearer="your-api-token",
88
+ headers={"User-Agent": "my-app/1.0"},
89
+ timeout=30,
90
+ )
91
+ ```
92
+
93
+ Attributes:
94
+ headers: Default headers sent with all requests. Excludes Cookie header.
95
+ cookies: Default cookies sent with all requests.
96
+ auth: Basic auth credentials as (username, password) tuple.
97
+ params: Default query parameters added to all requests.
98
+ timeout: Default timeout in seconds.
99
+ proxy: Proxy URL for requests.
100
+ """
101
+
102
+ def __init__(
103
+ self,
104
+ auth: tuple[str, str | None] | None = None,
105
+ auth_bearer: str | None = None,
106
+ params: dict[str, str] | None = None,
107
+ headers: dict[str, str] | None = None,
108
+ cookies: dict[str, str] | None = None,
109
+ cookie_store: bool | None = True,
110
+ referer: bool | None = True,
111
+ proxy: str | None = None,
112
+ timeout: float | None = 30,
113
+ follow_redirects: bool | None = True,
114
+ max_redirects: int | None = 20,
115
+ verify: bool | None = True,
116
+ ca_cert_file: str | None = None,
117
+ client_pem: str | None = None,
118
+ https_only: bool | None = False,
119
+ http2_only: bool | None = False,
120
+ ):
121
+ """
122
+ Initialize an HTTP client.
123
+
124
+ Args:
125
+ auth: Basic auth credentials as (username, password). Password can be None.
126
+ auth_bearer: Bearer token for Authorization header.
127
+ params: Default query parameters to include in all requests.
128
+ headers: Default headers to send with all requests.
129
+ cookies: Default cookies to send with all requests.
130
+ cookie_store: Enable persistent cookie store. Cookies from responses will be
131
+ preserved and included in subsequent requests. Default is True.
132
+ referer: Automatically set Referer header. Default is True.
133
+ proxy: Proxy URL (e.g., "http://proxy:8080" or "socks5://127.0.0.1:1080").
134
+ Falls back to HTTPR_PROXY environment variable.
135
+ timeout: Request timeout in seconds. Default is 30.
136
+ follow_redirects: Follow HTTP redirects. Default is True.
137
+ max_redirects: Maximum redirects to follow. Default is 20.
138
+ verify: Verify SSL certificates. Default is True.
139
+ ca_cert_file: Path to CA certificate bundle (PEM format).
140
+ client_pem: Path to client certificate for mTLS (PEM format).
141
+ https_only: Only allow HTTPS requests. Default is False.
142
+ http2_only: Use HTTP/2 only (False uses HTTP/1.1). Default is False.
143
+
144
+ Example:
145
+ ```python
146
+ import httpr
147
+
148
+ # Simple client
149
+ client = httpr.Client()
150
+
151
+ # Client with authentication
152
+ client = httpr.Client(
153
+ auth=("username", "password"),
154
+ timeout=60,
155
+ )
156
+
157
+ # Client with bearer token
158
+ client = httpr.Client(
159
+ auth_bearer="your-api-token",
160
+ headers={"Accept": "application/json"},
161
+ )
162
+
163
+ # Client with proxy
164
+ client = httpr.Client(proxy="http://proxy.example.com:8080")
165
+
166
+ # Client with mTLS
167
+ client = httpr.Client(
168
+ client_pem="/path/to/client.pem",
169
+ ca_cert_file="/path/to/ca.pem",
170
+ )
171
+ ```
172
+ """
173
+ super().__init__()
174
+
175
+ def __enter__(self) -> Client:
176
+ """Enter context manager."""
177
+ return self
178
+
179
+ def __exit__(self, *args):
180
+ """Exit context manager and close client."""
181
+ del self
182
+
183
+ def close(self) -> None:
184
+ """
185
+ Close the client and release resources.
186
+
187
+ Example:
188
+ ```python
189
+ client = httpr.Client()
190
+ try:
191
+ response = client.get("https://example.com")
192
+ finally:
193
+ client.close()
194
+ ```
195
+ """
196
+ del self
197
+
198
+ def request(
199
+ self,
200
+ method: HttpMethod,
201
+ url: str,
202
+ **kwargs: Unpack[RequestParams],
203
+ ) -> Response:
204
+ """
205
+ Make an HTTP request.
206
+
207
+ Args:
208
+ method: HTTP method (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS).
209
+ url: Request URL.
210
+ **kwargs: Request parameters (see below).
211
+
212
+ Keyword Args:
213
+ params (dict[str, str] | None): Query parameters to append to URL.
214
+ headers (dict[str, str] | None): Request headers (merged with client defaults).
215
+ cookies (dict[str, str] | None): Request cookies (merged with client defaults).
216
+ auth (tuple[str, str | None] | None): Basic auth credentials (overrides client default).
217
+ auth_bearer (str | None): Bearer token (overrides client default).
218
+ timeout (float | None): Request timeout in seconds (overrides client default).
219
+ content (bytes | None): Raw bytes for request body.
220
+ data (dict[str, Any] | None): Form data for request body (application/x-www-form-urlencoded).
221
+ json (Any | None): JSON data for request body (application/json).
222
+ files (dict[str, str] | None): Files for multipart upload (dict mapping field names to file paths).
223
+
224
+ Returns:
225
+ Response object with status, headers, and body.
226
+
227
+ Raises:
228
+ ValueError: If method is not a valid HTTP method.
229
+ Exception: If request fails (timeout, connection error, etc.).
230
+
231
+ Example:
232
+ ```python
233
+ response = client.request("GET", "https://httpbin.org/get")
234
+ response = client.request("POST", "https://httpbin.org/post", json={"key": "value"})
235
+ ```
236
+
237
+ Note:
238
+ Only one of `content`, `data`, `json`, or `files` can be specified per request.
239
+ """
240
+ if method not in ["GET", "HEAD", "OPTIONS", "DELETE", "POST", "PUT", "PATCH"]:
241
+ raise ValueError(f"Unsupported HTTP method: {method}")
242
+ if "params" in kwargs and kwargs["params"] is not None:
243
+ kwargs["params"] = {k: str(v) for k, v in kwargs["params"].items()}
244
+
245
+ return super().request(method=method, url=url, **kwargs)
246
+
247
+ def get(self, url: str, **kwargs: Unpack[RequestParams]) -> Response:
248
+ """
249
+ Make a GET request.
250
+
251
+ Args:
252
+ url: Request URL.
253
+ **kwargs: Request parameters (params, headers, cookies, auth, auth_bearer, timeout).
254
+
255
+ Returns:
256
+ Response object.
257
+
258
+ Example:
259
+ ```python
260
+ response = client.get(
261
+ "https://httpbin.org/get",
262
+ params={"key": "value"},
263
+ headers={"Accept": "application/json"},
264
+ )
265
+ print(response.json())
266
+ ```
267
+ """
268
+ return self.request(method="GET", url=url, **kwargs)
269
+
270
+ def head(self, url: str, **kwargs: Unpack[RequestParams]) -> Response:
271
+ """
272
+ Make a HEAD request.
273
+
274
+ Returns only headers, no response body.
275
+
276
+ Args:
277
+ url: Request URL.
278
+ **kwargs: Request parameters (params, headers, cookies, auth, auth_bearer, timeout).
279
+
280
+ Returns:
281
+ Response object (body will be empty).
282
+
283
+ Example:
284
+ ```python
285
+ response = client.head("https://httpbin.org/get")
286
+ print(response.headers["content-length"])
287
+ ```
288
+ """
289
+ return self.request(method="HEAD", url=url, **kwargs)
290
+
291
+ def options(self, url: str, **kwargs: Unpack[RequestParams]) -> Response:
292
+ """
293
+ Make an OPTIONS request.
294
+
295
+ Args:
296
+ url: Request URL.
297
+ **kwargs: Request parameters (params, headers, cookies, auth, auth_bearer, timeout).
298
+
299
+ Returns:
300
+ Response object.
301
+
302
+ Example:
303
+ ```python
304
+ response = client.options("https://httpbin.org/get")
305
+ print(response.headers.get("allow"))
306
+ ```
307
+ """
308
+ return self.request(method="OPTIONS", url=url, **kwargs)
309
+
310
+ def delete(self, url: str, **kwargs: Unpack[RequestParams]) -> Response:
311
+ """
312
+ Make a DELETE request.
313
+
314
+ Args:
315
+ url: Request URL.
316
+ **kwargs: Request parameters (params, headers, cookies, auth, auth_bearer, timeout).
317
+
318
+ Returns:
319
+ Response object.
320
+
321
+ Example:
322
+ ```python
323
+ response = client.delete("https://httpbin.org/delete")
324
+ print(response.status_code)
325
+ ```
326
+ """
327
+ return self.request(method="DELETE", url=url, **kwargs)
328
+
329
+ def post(self, url: str, **kwargs: Unpack[RequestParams]) -> Response:
330
+ """
331
+ Make a POST request.
332
+
333
+ Args:
334
+ url: Request URL.
335
+ **kwargs: Request parameters including body options.
336
+
337
+ Keyword Args:
338
+ params (dict[str, str] | None): Query parameters.
339
+ headers (dict[str, str] | None): Request headers.
340
+ cookies (dict[str, str] | None): Request cookies.
341
+ auth (tuple[str, str | None] | None): Basic auth credentials.
342
+ auth_bearer (str | None): Bearer token.
343
+ timeout (float | None): Request timeout.
344
+ content (bytes | None): Raw bytes body.
345
+ data (dict[str, Any] | None): Form-encoded body.
346
+ json (Any | None): JSON body.
347
+ files (dict[str, str] | None): Multipart file uploads.
348
+
349
+ Returns:
350
+ Response object.
351
+
352
+ Example:
353
+ ```python
354
+ # JSON body
355
+ response = client.post(
356
+ "https://httpbin.org/post",
357
+ json={"name": "httpr", "fast": True},
358
+ )
359
+
360
+ # Form data
361
+ response = client.post(
362
+ "https://httpbin.org/post",
363
+ data={"username": "user", "password": "pass"},
364
+ )
365
+
366
+ # File upload
367
+ response = client.post(
368
+ "https://httpbin.org/post",
369
+ files={"document": "/path/to/file.pdf"},
370
+ )
371
+ ```
372
+ """
373
+ return self.request(method="POST", url=url, **kwargs)
374
+
375
+ def put(self, url: str, **kwargs: Unpack[RequestParams]) -> Response:
376
+ """
377
+ Make a PUT request.
378
+
379
+ Args:
380
+ url: Request URL.
381
+ **kwargs: Request parameters including body options.
382
+
383
+ Returns:
384
+ Response object.
385
+
386
+ Example:
387
+ ```python
388
+ response = client.put(
389
+ "https://httpbin.org/put",
390
+ json={"key": "updated_value"},
391
+ )
392
+ ```
393
+ """
394
+ return self.request(method="PUT", url=url, **kwargs)
395
+
396
+ def patch(self, url: str, **kwargs: Unpack[RequestParams]) -> Response:
397
+ """
398
+ Make a PATCH request.
399
+
400
+ Args:
401
+ url: Request URL.
402
+ **kwargs: Request parameters including body options.
403
+
404
+ Returns:
405
+ Response object.
406
+
407
+ Example:
408
+ ```python
409
+ response = client.patch(
410
+ "https://httpbin.org/patch",
411
+ json={"field": "new_value"},
412
+ )
413
+ ```
414
+ """
415
+ return self.request(method="PATCH", url=url, **kwargs)
416
+
417
+
418
+ class AsyncClient(Client):
419
+ """
420
+ An asynchronous HTTP client for use with asyncio.
421
+
422
+ AsyncClient wraps the synchronous Client using asyncio.run_in_executor(),
423
+ providing an async interface while leveraging the Rust implementation's
424
+ performance.
425
+
426
+ Example:
427
+ Basic usage:
428
+
429
+ ```python
430
+ import asyncio
431
+ import httpr
432
+
433
+ async def main():
434
+ async with httpr.AsyncClient() as client:
435
+ response = await client.get("https://httpbin.org/get")
436
+ print(response.json())
437
+
438
+ asyncio.run(main())
439
+ ```
440
+
441
+ Concurrent requests:
442
+
443
+ ```python
444
+ import asyncio
445
+ import httpr
446
+
447
+ async def main():
448
+ async with httpr.AsyncClient() as client:
449
+ tasks = [
450
+ client.get("https://httpbin.org/get"),
451
+ client.get("https://httpbin.org/ip"),
452
+ ]
453
+ responses = await asyncio.gather(*tasks)
454
+ for response in responses:
455
+ print(response.json())
456
+
457
+ asyncio.run(main())
458
+ ```
459
+
460
+ Note:
461
+ AsyncClient runs synchronous Rust code in a thread executor.
462
+ It provides concurrency benefits for I/O-bound tasks but is not
463
+ native async I/O.
464
+ """
465
+
466
+ def __init__(self, *args, **kwargs):
467
+ """
468
+ Initialize an async HTTP client.
469
+
470
+ Accepts the same parameters as Client.
471
+ """
472
+ super().__init__(*args, **kwargs)
473
+
474
+ async def __aenter__(self) -> AsyncClient:
475
+ """Enter async context manager."""
476
+ return self
477
+
478
+ async def __aexit__(self, *args):
479
+ """Exit async context manager and close client."""
480
+ del self
481
+
482
+ async def aclose(self):
483
+ """
484
+ Close the async client.
485
+
486
+ Example:
487
+ ```python
488
+ client = httpr.AsyncClient()
489
+ try:
490
+ response = await client.get("https://example.com")
491
+ finally:
492
+ await client.aclose()
493
+ ```
494
+ """
495
+ del self
496
+ return
497
+
498
+ async def _run_sync_asyncio(self, fn, *args, **kwargs):
499
+ """Run a synchronous function in an executor."""
500
+ loop = asyncio.get_running_loop()
501
+ return await loop.run_in_executor(None, partial(fn, *args, **kwargs))
502
+
503
+ async def request( # type: ignore[override]
504
+ self,
505
+ method: HttpMethod,
506
+ url: str,
507
+ **kwargs: Unpack[RequestParams],
508
+ ) -> Response:
509
+ """
510
+ Make an async HTTP request.
511
+
512
+ Args:
513
+ method: HTTP method.
514
+ url: Request URL.
515
+ **kwargs: Request parameters.
516
+
517
+ Returns:
518
+ Response object.
519
+
520
+ Example:
521
+ ```python
522
+ response = await client.request("GET", "https://httpbin.org/get")
523
+ ```
524
+ """
525
+ if method not in ["GET", "HEAD", "OPTIONS", "DELETE", "POST", "PUT", "PATCH"]:
526
+ raise ValueError(f"Unsupported HTTP method: {method}")
527
+ if "params" in kwargs and kwargs["params"] is not None:
528
+ kwargs["params"] = {k: str(v) for k, v in kwargs["params"].items()}
529
+
530
+ return await self._run_sync_asyncio(super().request, method=method, url=url, **kwargs)
531
+
532
+ async def get( # type: ignore[override]
533
+ self,
534
+ url: str,
535
+ **kwargs: Unpack[RequestParams],
536
+ ) -> Response:
537
+ """
538
+ Make an async GET request.
539
+
540
+ Args:
541
+ url: Request URL.
542
+ **kwargs: Request parameters.
543
+
544
+ Returns:
545
+ Response object.
546
+
547
+ Example:
548
+ ```python
549
+ response = await client.get("https://httpbin.org/get")
550
+ ```
551
+ """
552
+ return await self.request(method="GET", url=url, **kwargs)
553
+
554
+ async def head( # type: ignore[override]
555
+ self,
556
+ url: str,
557
+ **kwargs: Unpack[RequestParams],
558
+ ) -> Response:
559
+ """
560
+ Make an async HEAD request.
561
+
562
+ Args:
563
+ url: Request URL.
564
+ **kwargs: Request parameters.
565
+
566
+ Returns:
567
+ Response object.
568
+ """
569
+ return await self.request(method="HEAD", url=url, **kwargs)
570
+
571
+ async def options( # type: ignore[override]
572
+ self,
573
+ url: str,
574
+ **kwargs: Unpack[RequestParams],
575
+ ) -> Response:
576
+ """
577
+ Make an async OPTIONS request.
578
+
579
+ Args:
580
+ url: Request URL.
581
+ **kwargs: Request parameters.
582
+
583
+ Returns:
584
+ Response object.
585
+ """
586
+ return await self.request(method="OPTIONS", url=url, **kwargs)
587
+
588
+ async def delete( # type: ignore[override]
589
+ self,
590
+ url: str,
591
+ **kwargs: Unpack[RequestParams],
592
+ ) -> Response:
593
+ """
594
+ Make an async DELETE request.
595
+
596
+ Args:
597
+ url: Request URL.
598
+ **kwargs: Request parameters.
599
+
600
+ Returns:
601
+ Response object.
602
+ """
603
+ return await self.request(method="DELETE", url=url, **kwargs)
604
+
605
+ async def post( # type: ignore[override]
606
+ self,
607
+ url: str,
608
+ **kwargs: Unpack[RequestParams],
609
+ ) -> Response:
610
+ """
611
+ Make an async POST request.
612
+
613
+ Args:
614
+ url: Request URL.
615
+ **kwargs: Request parameters including body options.
616
+
617
+ Returns:
618
+ Response object.
619
+
620
+ Example:
621
+ ```python
622
+ response = await client.post(
623
+ "https://httpbin.org/post",
624
+ json={"key": "value"},
625
+ )
626
+ ```
627
+ """
628
+ return await self.request(method="POST", url=url, **kwargs)
629
+
630
+ async def put( # type: ignore[override]
631
+ self,
632
+ url: str,
633
+ **kwargs: Unpack[RequestParams],
634
+ ) -> Response:
635
+ """
636
+ Make an async PUT request.
637
+
638
+ Args:
639
+ url: Request URL.
640
+ **kwargs: Request parameters including body options.
641
+
642
+ Returns:
643
+ Response object.
644
+ """
645
+ return await self.request(method="PUT", url=url, **kwargs)
646
+
647
+ async def patch( # type: ignore[override]
648
+ self,
649
+ url: str,
650
+ **kwargs: Unpack[RequestParams],
651
+ ) -> Response:
652
+ """
653
+ Make an async PATCH request.
654
+
655
+ Args:
656
+ url: Request URL.
657
+ **kwargs: Request parameters including body options.
658
+
659
+ Returns:
660
+ Response object.
661
+ """
662
+ return await self.request(method="PATCH", url=url, **kwargs)
663
+
664
+
665
+ def request(
666
+ method: HttpMethod,
667
+ url: str,
668
+ verify: bool | None = True,
669
+ ca_cert_file: str | None = None,
670
+ client_pem: str | None = None,
671
+ **kwargs: Unpack[RequestParams],
672
+ ) -> Response:
673
+ """
674
+ Make an HTTP request using a temporary client.
675
+
676
+ This is a convenience function for one-off requests. For multiple requests,
677
+ use a Client instance for better performance (connection pooling).
678
+
679
+ Args:
680
+ method: HTTP method (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS).
681
+ url: Request URL.
682
+ verify: Verify SSL certificates. Default is True.
683
+ ca_cert_file: Path to CA certificate bundle.
684
+ client_pem: Path to client certificate for mTLS.
685
+ **kwargs: Additional request parameters.
686
+
687
+ Returns:
688
+ Response object.
689
+
690
+ Example:
691
+ ```python
692
+ import httpr
693
+
694
+ response = httpr.request("GET", "https://httpbin.org/get")
695
+ response = httpr.request("POST", "https://httpbin.org/post", json={"key": "value"})
696
+ ```
697
+ """
698
+ with Client(
699
+ verify=verify,
700
+ ca_cert_file=ca_cert_file,
701
+ client_pem=client_pem,
702
+ ) as client:
703
+ return client.request(method, url, **kwargs)
704
+
705
+
706
+ def get(url: str, **kwargs: Unpack[ClientRequestParams]) -> Response:
707
+ """
708
+ Make a GET request using a temporary client.
709
+
710
+ Args:
711
+ url: Request URL.
712
+ **kwargs: Request parameters (params, headers, cookies, auth, timeout, etc.).
713
+
714
+ Returns:
715
+ Response object.
716
+
717
+ Example:
718
+ ```python
719
+ import httpr
720
+
721
+ response = httpr.get("https://httpbin.org/get", params={"key": "value"})
722
+ print(response.json())
723
+ ```
724
+ """
725
+ return request(method="GET", url=url, **kwargs)
726
+
727
+
728
+ def head(url: str, **kwargs: Unpack[ClientRequestParams]) -> Response:
729
+ """
730
+ Make a HEAD request using a temporary client.
731
+
732
+ Args:
733
+ url: Request URL.
734
+ **kwargs: Request parameters.
735
+
736
+ Returns:
737
+ Response object (body will be empty).
738
+
739
+ Example:
740
+ ```python
741
+ import httpr
742
+
743
+ response = httpr.head("https://httpbin.org/get")
744
+ print(response.headers)
745
+ ```
746
+ """
747
+ return request(method="HEAD", url=url, **kwargs)
748
+
749
+
750
+ def options(url: str, **kwargs: Unpack[ClientRequestParams]) -> Response:
751
+ """
752
+ Make an OPTIONS request using a temporary client.
753
+
754
+ Args:
755
+ url: Request URL.
756
+ **kwargs: Request parameters.
757
+
758
+ Returns:
759
+ Response object.
760
+
761
+ Example:
762
+ ```python
763
+ import httpr
764
+
765
+ response = httpr.options("https://httpbin.org/get")
766
+ ```
767
+ """
768
+ return request(method="OPTIONS", url=url, **kwargs)
769
+
770
+
771
+ def delete(url: str, **kwargs: Unpack[ClientRequestParams]) -> Response:
772
+ """
773
+ Make a DELETE request using a temporary client.
774
+
775
+ Args:
776
+ url: Request URL.
777
+ **kwargs: Request parameters.
778
+
779
+ Returns:
780
+ Response object.
781
+
782
+ Example:
783
+ ```python
784
+ import httpr
785
+
786
+ response = httpr.delete("https://httpbin.org/delete")
787
+ ```
788
+ """
789
+ return request(method="DELETE", url=url, **kwargs)
790
+
791
+
792
+ def post(url: str, **kwargs: Unpack[ClientRequestParams]) -> Response:
793
+ """
794
+ Make a POST request using a temporary client.
795
+
796
+ Args:
797
+ url: Request URL.
798
+ **kwargs: Request parameters (json, data, content, files, etc.).
799
+
800
+ Returns:
801
+ Response object.
802
+
803
+ Example:
804
+ ```python
805
+ import httpr
806
+
807
+ # JSON body
808
+ response = httpr.post("https://httpbin.org/post", json={"key": "value"})
809
+
810
+ # Form data
811
+ response = httpr.post("https://httpbin.org/post", data={"field": "value"})
812
+ ```
813
+ """
814
+ return request(method="POST", url=url, **kwargs)
815
+
816
+
817
+ def put(url: str, **kwargs: Unpack[ClientRequestParams]) -> Response:
818
+ """
819
+ Make a PUT request using a temporary client.
820
+
821
+ Args:
822
+ url: Request URL.
823
+ **kwargs: Request parameters.
824
+
825
+ Returns:
826
+ Response object.
827
+
828
+ Example:
829
+ ```python
830
+ import httpr
831
+
832
+ response = httpr.put("https://httpbin.org/put", json={"key": "value"})
833
+ ```
834
+ """
835
+ return request(method="PUT", url=url, **kwargs)
836
+
837
+
838
+ def patch(url: str, **kwargs: Unpack[ClientRequestParams]) -> Response:
839
+ """
840
+ Make a PATCH request using a temporary client.
841
+
842
+ Args:
843
+ url: Request URL.
844
+ **kwargs: Request parameters.
845
+
846
+ Returns:
847
+ Response object.
848
+
849
+ Example:
850
+ ```python
851
+ import httpr
852
+
853
+ response = httpr.patch("https://httpbin.org/patch", json={"field": "new_value"})
854
+ ```
855
+ """
856
+ return request(method="PATCH", url=url, **kwargs)
857
+
858
+
859
+ __all__ = [
860
+ "Client",
861
+ "AsyncClient",
862
+ "request",
863
+ "get",
864
+ "head",
865
+ "options",
866
+ "delete",
867
+ "post",
868
+ "put",
869
+ "patch",
870
+ ]
httpr/httpr.pyd ADDED
Binary file
httpr/httpr.pyi ADDED
@@ -0,0 +1,101 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+ from typing import Any, Literal, TypedDict
5
+
6
+ if sys.version_info <= (3, 11):
7
+ from typing_extensions import Unpack
8
+ else:
9
+ from typing import Unpack
10
+
11
+ HttpMethod = Literal["GET", "HEAD", "OPTIONS", "DELETE", "POST", "PUT", "PATCH"]
12
+
13
+ class RequestParams(TypedDict, total=False):
14
+ auth: tuple[str, str | None] | None
15
+ auth_bearer: str | None
16
+ params: dict[str, str] | None
17
+ headers: dict[str, str] | None
18
+ cookies: dict[str, str] | None
19
+ timeout: float | None
20
+ content: bytes | None
21
+ data: dict[str, Any] | None
22
+ json: Any | None
23
+ files: dict[str, str] | None
24
+
25
+ class ClientRequestParams(RequestParams):
26
+ verify: bool | None
27
+ ca_cert_file: str | None
28
+ client_pem: str | None
29
+
30
+ class Response:
31
+ @property
32
+ def content(self) -> bytes: ...
33
+ @property
34
+ def cookies(self) -> dict[str, str]: ...
35
+ @property
36
+ def headers(self) -> dict[str, str]: ...
37
+ @property
38
+ def status_code(self) -> int: ...
39
+ @property
40
+ def url(self) -> str: ...
41
+ @property
42
+ def encoding(self) -> str: ...
43
+ @property
44
+ def text(self) -> str: ...
45
+ def json(self) -> Any: ...
46
+ @property
47
+ def text_markdown(self) -> str: ...
48
+ @property
49
+ def text_plain(self) -> str: ...
50
+ @property
51
+ def text_rich(self) -> str: ...
52
+
53
+ class RClient:
54
+ def __init__(
55
+ self,
56
+ auth: tuple[str, str | None] | None = None,
57
+ auth_bearer: str | None = None,
58
+ params: dict[str, str] | None = None,
59
+ headers: dict[str, str] | None = None,
60
+ cookies: dict[str, str] | None = None,
61
+ timeout: float | None = None,
62
+ cookie_store: bool | None = True,
63
+ referer: bool | None = True,
64
+ proxy: str | None = None,
65
+ follow_redirects: bool | None = True,
66
+ max_redirects: int | None = 20,
67
+ verify: bool | None = True,
68
+ ca_cert_file: str | None = None,
69
+ client_pem: str | None = None,
70
+ https_only: bool | None = False,
71
+ http2_only: bool | None = False,
72
+ ): ...
73
+ @property
74
+ def headers(self) -> dict[str, str]: ...
75
+ @headers.setter
76
+ def headers(self, headers: dict[str, str]) -> None: ...
77
+ @property
78
+ def cookies(self) -> dict[str, str]: ...
79
+ @cookies.setter
80
+ def cookies(self, cookies: dict[str, str]) -> None: ...
81
+ @property
82
+ def proxy(self) -> str | None: ...
83
+ @proxy.setter
84
+ def proxy(self, proxy: str) -> None: ...
85
+ def request(self, method: HttpMethod, url: str, **kwargs: Unpack[RequestParams]) -> Response: ...
86
+ def get(self, url: str, **kwargs: Unpack[RequestParams]) -> Response: ...
87
+ def head(self, url: str, **kwargs: Unpack[RequestParams]) -> Response: ...
88
+ def options(self, url: str, **kwargs: Unpack[RequestParams]) -> Response: ...
89
+ def delete(self, url: str, **kwargs: Unpack[RequestParams]) -> Response: ...
90
+ def post(self, url: str, **kwargs: Unpack[RequestParams]) -> Response: ...
91
+ def put(self, url: str, **kwargs: Unpack[RequestParams]) -> Response: ...
92
+ def patch(self, url: str, **kwargs: Unpack[RequestParams]) -> Response: ...
93
+
94
+ def request(method: HttpMethod, url: str, **kwargs: Unpack[ClientRequestParams]) -> Response: ...
95
+ def get(url: str, **kwargs: Unpack[ClientRequestParams]) -> Response: ...
96
+ def head(url: str, **kwargs: Unpack[ClientRequestParams]) -> Response: ...
97
+ def options(url: str, **kwargs: Unpack[ClientRequestParams]) -> Response: ...
98
+ def delete(url: str, **kwargs: Unpack[ClientRequestParams]) -> Response: ...
99
+ def post(url: str, **kwargs: Unpack[ClientRequestParams]) -> Response: ...
100
+ def put(url: str, **kwargs: Unpack[ClientRequestParams]) -> Response: ...
101
+ def patch(url: str, **kwargs: Unpack[ClientRequestParams]) -> Response: ...
httpr/py.typed ADDED
File without changes
@@ -0,0 +1,49 @@
1
+ Metadata-Version: 2.4
2
+ Name: httpr
3
+ Version: 0.1.17
4
+ Classifier: Programming Language :: Rust
5
+ Classifier: Programming Language :: Python :: 3
6
+ Classifier: Programming Language :: Python :: 3 :: Only
7
+ Classifier: Programming Language :: Python :: 3.8
8
+ Classifier: Programming Language :: Python :: 3.9
9
+ Classifier: Programming Language :: Python :: 3.10
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: Programming Language :: Python :: Implementation :: CPython
14
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
15
+ Classifier: Topic :: Internet :: WWW/HTTP
16
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
+ Requires-Dist: certifi ; extra == 'dev'
18
+ Requires-Dist: pytest>=8.1.1 ; extra == 'dev'
19
+ Requires-Dist: pytest-asyncio>=0.25.3 ; extra == 'dev'
20
+ Requires-Dist: pytest-httpbin>=2.1.0 ; extra == 'dev'
21
+ Requires-Dist: typing-extensions ; python_full_version < '3.12' and extra == 'dev'
22
+ Requires-Dist: mypy>=1.14.1 ; extra == 'dev'
23
+ Requires-Dist: ruff>=0.9.2 ; extra == 'dev'
24
+ Requires-Dist: maturin ; extra == 'dev'
25
+ Requires-Dist: trustme ; extra == 'dev'
26
+ Requires-Dist: mkdocs-material[imaging] ; extra == 'docs'
27
+ Requires-Dist: mkdocstrings[python]>=0.27.0 ; extra == 'docs'
28
+ Requires-Dist: mkdocs-gen-files ; extra == 'docs'
29
+ Requires-Dist: mkdocs-literate-nav ; extra == 'docs'
30
+ Requires-Dist: httpr[dev] ; extra == 'scratch'
31
+ Requires-Dist: matplotlib ; extra == 'scratch'
32
+ Requires-Dist: pandas ; extra == 'scratch'
33
+ Requires-Dist: jupyter ; extra == 'scratch'
34
+ Requires-Dist: ipykernel ; extra == 'scratch'
35
+ Requires-Dist: httpx ; extra == 'scratch'
36
+ Requires-Dist: gunicorn ; extra == 'scratch'
37
+ Requires-Dist: uvicorn ; extra == 'scratch'
38
+ Requires-Dist: trustme ; extra == 'scratch'
39
+ Requires-Dist: starlette ; extra == 'scratch'
40
+ Requires-Dist: fastapi ; extra == 'scratch'
41
+ Provides-Extra: dev
42
+ Provides-Extra: docs
43
+ Provides-Extra: scratch
44
+ License-File: LICENSE
45
+ Summary: Fast HTTP client for Python
46
+ Keywords: python,request
47
+ Author: thomasht86
48
+ License: MIT License
49
+ Requires-Python: >=3.9
@@ -0,0 +1,8 @@
1
+ httpr-0.1.17.dist-info/METADATA,sha256=W9D8erBK9zt9tqon55skX41ATkiwcseTJG9idOwGbsk,2129
2
+ httpr-0.1.17.dist-info/WHEEL,sha256=W8IbRrW6aFuwgkpVWKTtkIq8XwJIIpO5tHf4goK_jm8,95
3
+ httpr-0.1.17.dist-info/licenses/LICENSE,sha256=O15TIxUAXq6sSpPu0K3CJu_dT5ZzCgIk7hQtZsf0lEk,1084
4
+ httpr/__init__.py,sha256=TQtmQx9A8g9mEHMghynFab2XC-bjmu1fK1FMjrYNJ18,25174
5
+ httpr/httpr.pyd,sha256=k87zTK5grPYfqo18BiJEvdTW8vfwhw2-NybbI_tFwss,4539904
6
+ httpr/httpr.pyi,sha256=VbROFo3ZXTacg2Fe0kvQWZ0RXXrAK08F4ivUL0cvGtY,3830
7
+ httpr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ httpr-0.1.17.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.10.2)
3
+ Root-Is-Purelib: false
4
+ Tag: cp39-abi3-win_amd64
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 deedy5
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.