httpr 0.3.2__cp39-abi3-macosx_10_12_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.
httpr/httpr.abi3.so ADDED
Binary file
httpr/httpr.pyi ADDED
@@ -0,0 +1,706 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+ from collections.abc import Iterator
5
+ from contextlib import AbstractAsyncContextManager, AbstractContextManager
6
+ from typing import Any, Literal, TypedDict
7
+
8
+ if sys.version_info <= (3, 11):
9
+ from typing_extensions import Unpack
10
+ else:
11
+ from typing import Unpack
12
+
13
+ HttpMethod = Literal["GET", "HEAD", "OPTIONS", "DELETE", "POST", "PUT", "PATCH"]
14
+
15
+ class RequestParams(TypedDict, total=False):
16
+ auth: tuple[str, str | None] | None
17
+ auth_bearer: str | None
18
+ params: dict[str, str] | None
19
+ headers: dict[str, str] | None
20
+ cookies: dict[str, str] | None
21
+ timeout: float | None
22
+ content: bytes | None
23
+ data: dict[str, Any] | None
24
+ json: Any | None
25
+ files: dict[str, str] | None
26
+
27
+ class ClientRequestParams(RequestParams):
28
+ verify: bool | None
29
+ ca_cert_file: str | None
30
+ client_pem: str | None
31
+ client_pem_data: bytes | None
32
+
33
+ class CaseInsensitiveHeaderMap:
34
+ """
35
+ A case-insensitive dictionary-like class for HTTP headers.
36
+
37
+ HTTP headers are case-insensitive per the HTTP specification.
38
+ This class allows accessing headers using any case while preserving
39
+ the original case for iteration.
40
+
41
+ Example:
42
+ ```python
43
+ headers = response.headers
44
+ content_type = headers["Content-Type"] # Works
45
+ content_type = headers["content-type"] # Also works
46
+
47
+ if "Content-Type" in headers:
48
+ print("Has content type")
49
+
50
+ for key, value in headers.items():
51
+ print(f"{key}: {value}")
52
+ ```
53
+ """
54
+ def __getitem__(self, key: str) -> str:
55
+ """Get a header value by name (case-insensitive)."""
56
+ ...
57
+ def __contains__(self, key: str) -> bool:
58
+ """Check if a header exists (case-insensitive)."""
59
+ ...
60
+ def __iter__(self) -> Iterator[str]:
61
+ """Iterate over header names."""
62
+ ...
63
+ def items(self) -> list[tuple[str, str]]:
64
+ """Return a list of (name, value) tuples."""
65
+ ...
66
+ def keys(self) -> list[str]:
67
+ """Return a list of header names."""
68
+ ...
69
+ def values(self) -> list[str]:
70
+ """Return a list of header values."""
71
+ ...
72
+ def get(self, key: str, default: str | None = None) -> str:
73
+ """
74
+ Get a header value by name (case-insensitive).
75
+
76
+ Args:
77
+ key: Header name to look up.
78
+ default: Value to return if header is not found. Defaults to None.
79
+
80
+ Returns:
81
+ The header value, or the default if not found.
82
+ """
83
+ ...
84
+
85
+ class Response:
86
+ """
87
+ An HTTP response object.
88
+
89
+ This class provides access to the response status, headers, cookies,
90
+ and body content. The body can be accessed as bytes, text, JSON, or CBOR.
91
+
92
+ Example:
93
+ ```python
94
+ response = client.get("https://httpbin.org/get")
95
+
96
+ # Status
97
+ print(response.status_code) # 200
98
+ print(response.url) # Final URL after redirects
99
+
100
+ # Headers (case-insensitive access)
101
+ print(response.headers["content-type"])
102
+
103
+ # Body
104
+ print(response.text) # Decoded text
105
+ print(response.json()) # Parsed JSON
106
+ print(response.content) # Raw bytes
107
+ ```
108
+ """
109
+ @property
110
+ def content(self) -> bytes:
111
+ """Raw response body as bytes."""
112
+ ...
113
+ @property
114
+ def cookies(self) -> dict[str, str]:
115
+ """Response cookies as a dictionary."""
116
+ ...
117
+ @property
118
+ def headers(self) -> CaseInsensitiveHeaderMap:
119
+ """
120
+ Response headers as a case-insensitive dictionary-like object.
121
+
122
+ Headers can be accessed using any case (e.g., "Content-Type" or "content-type").
123
+ """
124
+ ...
125
+ @property
126
+ def status_code(self) -> int:
127
+ """HTTP status code (e.g., 200, 404, 500)."""
128
+ ...
129
+ @property
130
+ def url(self) -> str:
131
+ """Final URL after any redirects."""
132
+ ...
133
+ @property
134
+ def encoding(self) -> str:
135
+ """
136
+ Character encoding of the response.
137
+
138
+ Detected from Content-Type header or response body.
139
+ Can be set to override auto-detection.
140
+ """
141
+ ...
142
+ @encoding.setter
143
+ def encoding(self, value: str) -> None: ...
144
+ @property
145
+ def text(self) -> str:
146
+ """Response body decoded as text using the detected encoding."""
147
+ ...
148
+ def json(self) -> Any:
149
+ """
150
+ Parse response body as JSON.
151
+
152
+ If Content-Type is application/cbor, automatically deserializes as CBOR.
153
+
154
+ Returns:
155
+ Parsed JSON/CBOR data as Python objects.
156
+ """
157
+ ...
158
+ def cbor(self) -> Any:
159
+ """
160
+ Parse response body as CBOR (Concise Binary Object Representation).
161
+
162
+ Returns:
163
+ Parsed CBOR data as Python objects.
164
+ """
165
+ ...
166
+ @property
167
+ def text_markdown(self) -> str:
168
+ """
169
+ Response body converted from HTML to Markdown format.
170
+
171
+ Useful for reading HTML content as plain text.
172
+ """
173
+ ...
174
+ @property
175
+ def text_plain(self) -> str:
176
+ """
177
+ Response body converted from HTML to plain text.
178
+
179
+ Strips all formatting and returns only the text content.
180
+ """
181
+ ...
182
+ @property
183
+ def text_rich(self) -> str:
184
+ """
185
+ Response body converted from HTML to rich text format.
186
+
187
+ Preserves some formatting using Unicode characters.
188
+ """
189
+ ...
190
+
191
+ class TextIterator:
192
+ """Iterator for text chunks from a streaming response."""
193
+ def __iter__(self) -> TextIterator: ...
194
+ def __next__(self) -> str: ...
195
+
196
+ class LineIterator:
197
+ """Iterator for lines from a streaming response."""
198
+ def __iter__(self) -> LineIterator: ...
199
+ def __next__(self) -> str: ...
200
+
201
+ class StreamingResponse:
202
+ """
203
+ A streaming HTTP response that allows iterating over chunks of data.
204
+
205
+ This class provides methods to iterate over the response body in chunks
206
+ without buffering the entire response in memory.
207
+ """
208
+
209
+ @property
210
+ def cookies(self) -> dict[str, str]:
211
+ """Response cookies."""
212
+ ...
213
+ @property
214
+ def headers(self) -> CaseInsensitiveHeaderMap:
215
+ """Response headers (case-insensitive access)."""
216
+ ...
217
+ @property
218
+ def status_code(self) -> int:
219
+ """HTTP status code."""
220
+ ...
221
+ @property
222
+ def url(self) -> str:
223
+ """Final URL after any redirects."""
224
+ ...
225
+ @property
226
+ def is_closed(self) -> bool:
227
+ """Whether the stream has been closed."""
228
+ ...
229
+ @property
230
+ def is_consumed(self) -> bool:
231
+ """Whether the stream has been fully consumed."""
232
+ ...
233
+ def __iter__(self) -> Iterator[bytes]:
234
+ """Iterate over the response body as bytes chunks."""
235
+ ...
236
+ def __next__(self) -> bytes:
237
+ """Get the next chunk of bytes."""
238
+ ...
239
+ def iter_bytes(self) -> Iterator[bytes]:
240
+ """
241
+ Iterate over the response body as bytes chunks.
242
+
243
+ Yields chunks of bytes as they are received from the server.
244
+ """
245
+ ...
246
+ def iter_text(self) -> TextIterator:
247
+ """
248
+ Iterate over the response body as text chunks.
249
+
250
+ Decodes each chunk using the response's encoding.
251
+ """
252
+ ...
253
+ def iter_lines(self) -> LineIterator:
254
+ """
255
+ Iterate over the response body line by line.
256
+
257
+ Yields complete lines including newline characters.
258
+ """
259
+ ...
260
+ def read(self) -> bytes:
261
+ """
262
+ Read the entire remaining response body into memory.
263
+
264
+ This consumes the stream.
265
+ """
266
+ ...
267
+ def close(self) -> None:
268
+ """
269
+ Close the streaming response and release resources.
270
+ """
271
+ ...
272
+
273
+ class RClient:
274
+ def __init__(
275
+ self,
276
+ auth: tuple[str, str | None] | None = None,
277
+ auth_bearer: str | None = None,
278
+ params: dict[str, str] | None = None,
279
+ headers: dict[str, str] | None = None,
280
+ cookies: dict[str, str] | None = None,
281
+ timeout: float | None = None,
282
+ cookie_store: bool | None = True,
283
+ referer: bool | None = True,
284
+ proxy: str | None = None,
285
+ follow_redirects: bool | None = True,
286
+ max_redirects: int | None = 20,
287
+ verify: bool | None = True,
288
+ ca_cert_file: str | None = None,
289
+ client_pem: str | None = None,
290
+ client_pem_data: bytes | None = None,
291
+ https_only: bool | None = False,
292
+ http2_only: bool | None = False,
293
+ ): ...
294
+ @property
295
+ def headers(self) -> dict[str, str]: ...
296
+ @headers.setter
297
+ def headers(self, headers: dict[str, str] | None) -> None: ...
298
+ @property
299
+ def cookies(self) -> dict[str, str]: ...
300
+ @cookies.setter
301
+ def cookies(self, cookies: dict[str, str] | None) -> None: ...
302
+ @property
303
+ def proxy(self) -> str | None: ...
304
+ @proxy.setter
305
+ def proxy(self, proxy: str) -> None: ...
306
+ @property
307
+ def auth(self) -> tuple[str, str | None] | None: ...
308
+ @auth.setter
309
+ def auth(self, auth: tuple[str, str | None] | None) -> None: ...
310
+ @property
311
+ def auth_bearer(self) -> str | None: ...
312
+ @auth_bearer.setter
313
+ def auth_bearer(self, auth_bearer: str | None) -> None: ...
314
+ @property
315
+ def params(self) -> dict[str, str] | None: ...
316
+ @params.setter
317
+ def params(self, params: dict[str, str] | None) -> None: ...
318
+ @property
319
+ def timeout(self) -> float | None: ...
320
+ @timeout.setter
321
+ def timeout(self, timeout: float | None) -> None: ...
322
+ def request(self, method: HttpMethod, url: str, **kwargs: Unpack[RequestParams]) -> Response: ...
323
+ def _stream(self, method: HttpMethod, url: str, **kwargs: Unpack[RequestParams]) -> StreamingResponse: ...
324
+ def get(self, url: str, **kwargs: Unpack[RequestParams]) -> Response: ...
325
+ def head(self, url: str, **kwargs: Unpack[RequestParams]) -> Response: ...
326
+ def options(self, url: str, **kwargs: Unpack[RequestParams]) -> Response: ...
327
+ def delete(self, url: str, **kwargs: Unpack[RequestParams]) -> Response: ...
328
+ def post(self, url: str, **kwargs: Unpack[RequestParams]) -> Response: ...
329
+ def put(self, url: str, **kwargs: Unpack[RequestParams]) -> Response: ...
330
+ def patch(self, url: str, **kwargs: Unpack[RequestParams]) -> Response: ...
331
+
332
+ class Client(RClient):
333
+ """
334
+ A synchronous HTTP client with connection pooling.
335
+
336
+ The Client class provides a high-level interface for making HTTP requests.
337
+ It supports connection pooling, automatic cookie handling, and various
338
+ authentication methods.
339
+
340
+ Example:
341
+ ```python
342
+ import httpr
343
+
344
+ # Using context manager (recommended)
345
+ with httpr.Client() as client:
346
+ response = client.get("https://httpbin.org/get")
347
+ print(response.json())
348
+
349
+ # Or manually
350
+ client = httpr.Client()
351
+ response = client.get("https://httpbin.org/get")
352
+ client.close()
353
+ ```
354
+
355
+ Attributes:
356
+ headers: Default headers sent with all requests. Excludes Cookie header.
357
+ cookies: Default cookies sent with all requests.
358
+ auth: Basic auth credentials as (username, password) tuple.
359
+ params: Default query parameters added to all requests.
360
+ timeout: Default timeout in seconds.
361
+ proxy: Proxy URL for requests.
362
+ """
363
+ def __init__(
364
+ self,
365
+ auth: tuple[str, str | None] | None = None,
366
+ auth_bearer: str | None = None,
367
+ params: dict[str, str] | None = None,
368
+ headers: dict[str, str] | None = None,
369
+ cookies: dict[str, str] | None = None,
370
+ cookie_store: bool | None = True,
371
+ referer: bool | None = True,
372
+ proxy: str | None = None,
373
+ timeout: float | None = 30,
374
+ follow_redirects: bool | None = True,
375
+ max_redirects: int | None = 20,
376
+ verify: bool | None = True,
377
+ ca_cert_file: str | None = None,
378
+ client_pem: str | None = None,
379
+ client_pem_data: bytes | None = None,
380
+ https_only: bool | None = False,
381
+ http2_only: bool | None = False,
382
+ ) -> None:
383
+ """
384
+ Initialize an HTTP client.
385
+
386
+ Args:
387
+ auth: Basic auth credentials as (username, password). Password can be None.
388
+ auth_bearer: Bearer token for Authorization header.
389
+ params: Default query parameters to include in all requests.
390
+ headers: Default headers to send with all requests.
391
+ cookies: Default cookies to send with all requests.
392
+ cookie_store: Enable persistent cookie store. Default is True.
393
+ referer: Automatically set Referer header. Default is True.
394
+ proxy: Proxy URL (e.g., "http://proxy:8080" or "socks5://127.0.0.1:1080").
395
+ timeout: Request timeout in seconds. Default is 30.
396
+ follow_redirects: Follow HTTP redirects. Default is True.
397
+ max_redirects: Maximum redirects to follow. Default is 20.
398
+ verify: Verify SSL certificates. Default is True.
399
+ ca_cert_file: Path to CA certificate bundle (PEM format).
400
+ client_pem: Path to client certificate for mTLS (PEM format).
401
+ client_pem_data: Client certificate and key as bytes for mTLS (PEM format).
402
+ https_only: Only allow HTTPS requests. Default is False.
403
+ http2_only: Use HTTP/2 only. Default is False.
404
+ """
405
+ ...
406
+ def __enter__(self) -> Client: ...
407
+ def __exit__(self, *args: Any) -> None: ...
408
+ def close(self) -> None:
409
+ """Close the client and release resources."""
410
+ ...
411
+ def stream(
412
+ self, method: HttpMethod, url: str, **kwargs: Unpack[RequestParams]
413
+ ) -> AbstractContextManager[StreamingResponse]:
414
+ """
415
+ Make a streaming HTTP request.
416
+
417
+ Returns a context manager that yields a StreamingResponse for iterating
418
+ over the response body in chunks.
419
+
420
+ Args:
421
+ method: HTTP method (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS).
422
+ url: Request URL.
423
+ **kwargs: Request parameters.
424
+
425
+ Yields:
426
+ StreamingResponse: A response object that can be iterated.
427
+
428
+ Example:
429
+ ```python
430
+ with client.stream("GET", "https://example.com/large-file") as response:
431
+ for chunk in response.iter_bytes():
432
+ process(chunk)
433
+ ```
434
+ """
435
+ ...
436
+
437
+ class AsyncClient(Client):
438
+ """
439
+ An asynchronous HTTP client for use with asyncio.
440
+
441
+ AsyncClient wraps the synchronous Client using asyncio.run_in_executor(),
442
+ providing an async interface while leveraging the Rust implementation's
443
+ performance.
444
+
445
+ Example:
446
+ ```python
447
+ import asyncio
448
+ import httpr
449
+
450
+ async def main():
451
+ async with httpr.AsyncClient() as client:
452
+ response = await client.get("https://httpbin.org/get")
453
+ print(response.json())
454
+
455
+ asyncio.run(main())
456
+ ```
457
+
458
+ Note:
459
+ AsyncClient runs synchronous Rust code in a thread executor.
460
+ It provides concurrency benefits for I/O-bound tasks but is not
461
+ native async I/O.
462
+ """
463
+ def __init__(
464
+ self,
465
+ auth: tuple[str, str | None] | None = None,
466
+ auth_bearer: str | None = None,
467
+ params: dict[str, str] | None = None,
468
+ headers: dict[str, str] | None = None,
469
+ cookies: dict[str, str] | None = None,
470
+ cookie_store: bool | None = True,
471
+ referer: bool | None = True,
472
+ proxy: str | None = None,
473
+ timeout: float | None = 30,
474
+ follow_redirects: bool | None = True,
475
+ max_redirects: int | None = 20,
476
+ verify: bool | None = True,
477
+ ca_cert_file: str | None = None,
478
+ client_pem: str | None = None,
479
+ client_pem_data: bytes | None = None,
480
+ https_only: bool | None = False,
481
+ http2_only: bool | None = False,
482
+ ) -> None:
483
+ """Initialize an async HTTP client. Accepts the same parameters as Client."""
484
+ ...
485
+ async def __aenter__(self) -> AsyncClient: ...
486
+ async def __aexit__(self, *args: Any) -> None: ...
487
+ async def aclose(self) -> None:
488
+ """Close the async client."""
489
+ ...
490
+ async def request( # type: ignore[override]
491
+ self, method: HttpMethod, url: str, **kwargs: Unpack[RequestParams]
492
+ ) -> Response:
493
+ """Make an async HTTP request."""
494
+ ...
495
+ async def get( # type: ignore[override]
496
+ self, url: str, **kwargs: Unpack[RequestParams]
497
+ ) -> Response:
498
+ """Make an async GET request."""
499
+ ...
500
+ async def head( # type: ignore[override]
501
+ self, url: str, **kwargs: Unpack[RequestParams]
502
+ ) -> Response:
503
+ """Make an async HEAD request."""
504
+ ...
505
+ async def options( # type: ignore[override]
506
+ self, url: str, **kwargs: Unpack[RequestParams]
507
+ ) -> Response:
508
+ """Make an async OPTIONS request."""
509
+ ...
510
+ async def delete( # type: ignore[override]
511
+ self, url: str, **kwargs: Unpack[RequestParams]
512
+ ) -> Response:
513
+ """Make an async DELETE request."""
514
+ ...
515
+ async def post( # type: ignore[override]
516
+ self, url: str, **kwargs: Unpack[RequestParams]
517
+ ) -> Response:
518
+ """Make an async POST request."""
519
+ ...
520
+ async def put( # type: ignore[override]
521
+ self, url: str, **kwargs: Unpack[RequestParams]
522
+ ) -> Response:
523
+ """Make an async PUT request."""
524
+ ...
525
+ async def patch( # type: ignore[override]
526
+ self, url: str, **kwargs: Unpack[RequestParams]
527
+ ) -> Response:
528
+ """Make an async PATCH request."""
529
+ ...
530
+ def stream( # type: ignore[override]
531
+ self, method: HttpMethod, url: str, **kwargs: Unpack[RequestParams]
532
+ ) -> AbstractAsyncContextManager[StreamingResponse]:
533
+ """
534
+ Make an async streaming HTTP request.
535
+
536
+ Returns an async context manager that yields a StreamingResponse.
537
+
538
+ Example:
539
+ ```python
540
+ async with client.stream("GET", "https://example.com/large-file") as response:
541
+ for chunk in response.iter_bytes():
542
+ process(chunk)
543
+ ```
544
+ """
545
+ ...
546
+
547
+ def request(method: HttpMethod, url: str, **kwargs: Unpack[ClientRequestParams]) -> Response: ...
548
+ def get(url: str, **kwargs: Unpack[ClientRequestParams]) -> Response: ...
549
+ def head(url: str, **kwargs: Unpack[ClientRequestParams]) -> Response: ...
550
+ def options(url: str, **kwargs: Unpack[ClientRequestParams]) -> Response: ...
551
+ def delete(url: str, **kwargs: Unpack[ClientRequestParams]) -> Response: ...
552
+ def post(url: str, **kwargs: Unpack[ClientRequestParams]) -> Response: ...
553
+ def put(url: str, **kwargs: Unpack[ClientRequestParams]) -> Response: ...
554
+ def patch(url: str, **kwargs: Unpack[ClientRequestParams]) -> Response: ...
555
+
556
+ # Exception hierarchy - Base exceptions
557
+ class HTTPError(Exception):
558
+ """Base class for all httpr exceptions."""
559
+
560
+ class RequestError(HTTPError):
561
+ """Base class for all exceptions that may occur when issuing a .request()."""
562
+
563
+ class TransportError(RequestError):
564
+ """Base class for all exceptions that occur at the level of the Transport API."""
565
+
566
+ class NetworkError(TransportError):
567
+ """The base class for network-related errors."""
568
+
569
+ class TimeoutException(TransportError):
570
+ """The base class for timeout errors."""
571
+
572
+ class ProtocolError(TransportError):
573
+ """The protocol was violated."""
574
+
575
+ class StreamError(Exception):
576
+ """The base class for stream exceptions."""
577
+
578
+ # Timeout exceptions
579
+ class ConnectTimeout(TimeoutException):
580
+ """Timed out while connecting to the host."""
581
+
582
+ class ReadTimeout(TimeoutException):
583
+ """Timed out while receiving data from the host."""
584
+
585
+ class WriteTimeout(TimeoutException):
586
+ """Timed out while sending data to the host."""
587
+
588
+ class PoolTimeout(TimeoutException):
589
+ """Timed out waiting to acquire a connection from the pool."""
590
+
591
+ # Network exceptions
592
+ class ConnectError(NetworkError):
593
+ """Failed to establish a connection."""
594
+
595
+ class ReadError(NetworkError):
596
+ """Failed to receive data from the network."""
597
+
598
+ class WriteError(NetworkError):
599
+ """Failed to send data through the network."""
600
+
601
+ class CloseError(NetworkError):
602
+ """Failed to close a connection."""
603
+
604
+ # Protocol exceptions
605
+ class LocalProtocolError(ProtocolError):
606
+ """A protocol was violated by the client."""
607
+
608
+ class RemoteProtocolError(ProtocolError):
609
+ """The protocol was violated by the server."""
610
+
611
+ # Other transport/request exceptions
612
+ class UnsupportedProtocol(TransportError):
613
+ """Attempted to make a request to an unsupported protocol."""
614
+
615
+ class ProxyError(TransportError):
616
+ """An error occurred while establishing a proxy connection."""
617
+
618
+ class TooManyRedirects(RequestError):
619
+ """Too many redirects."""
620
+
621
+ class HTTPStatusError(HTTPError):
622
+ """The response had an error HTTP status of 4xx or 5xx."""
623
+
624
+ class DecodingError(RequestError):
625
+ """Decoding of the response failed, due to a malformed encoding."""
626
+
627
+ # Stream exceptions
628
+ class StreamConsumed(StreamError):
629
+ """Attempted to read or stream content, but the content has already been consumed."""
630
+
631
+ class ResponseNotRead(StreamError):
632
+ """Attempted to access streaming response content, without having called read()."""
633
+
634
+ class RequestNotRead(StreamError):
635
+ """Attempted to access streaming request content, without having called read()."""
636
+
637
+ class StreamClosed(StreamError):
638
+ """Attempted to read or stream response content, but the request has been closed."""
639
+
640
+ # Other exceptions
641
+ class InvalidURL(Exception):
642
+ """URL is improperly formed or cannot be parsed."""
643
+
644
+ class CookieConflict(Exception):
645
+ """Attempted to lookup a cookie by name, but multiple cookies existed."""
646
+
647
+ __all__ = [
648
+ # Type aliases
649
+ "HttpMethod",
650
+ "RequestParams",
651
+ "ClientRequestParams",
652
+ # Response types
653
+ "Response",
654
+ "StreamingResponse",
655
+ "CaseInsensitiveHeaderMap",
656
+ "TextIterator",
657
+ "LineIterator",
658
+ # Client classes
659
+ "RClient",
660
+ "Client",
661
+ "AsyncClient",
662
+ # Module-level functions
663
+ "request",
664
+ "get",
665
+ "head",
666
+ "options",
667
+ "delete",
668
+ "post",
669
+ "put",
670
+ "patch",
671
+ # Base exceptions
672
+ "HTTPError",
673
+ "RequestError",
674
+ "TransportError",
675
+ "NetworkError",
676
+ "TimeoutException",
677
+ "ProtocolError",
678
+ "StreamError",
679
+ # Timeout exceptions
680
+ "ConnectTimeout",
681
+ "ReadTimeout",
682
+ "WriteTimeout",
683
+ "PoolTimeout",
684
+ # Network exceptions
685
+ "ConnectError",
686
+ "ReadError",
687
+ "WriteError",
688
+ "CloseError",
689
+ # Protocol exceptions
690
+ "LocalProtocolError",
691
+ "RemoteProtocolError",
692
+ # Other transport/request exceptions
693
+ "UnsupportedProtocol",
694
+ "ProxyError",
695
+ "TooManyRedirects",
696
+ "HTTPStatusError",
697
+ "DecodingError",
698
+ # Stream exceptions
699
+ "StreamConsumed",
700
+ "ResponseNotRead",
701
+ "RequestNotRead",
702
+ "StreamClosed",
703
+ # Other exceptions
704
+ "InvalidURL",
705
+ "CookieConflict",
706
+ ]
httpr/py.typed ADDED
File without changes