| """ |
| Our exception hierarchy: |
| |
| * HTTPError |
| x RequestError |
| + TransportError |
| - TimeoutException |
| 路 ConnectTimeout |
| 路 ReadTimeout |
| 路 WriteTimeout |
| 路 PoolTimeout |
| - NetworkError |
| 路 ConnectError |
| 路 ReadError |
| 路 WriteError |
| 路 CloseError |
| - ProtocolError |
| 路 LocalProtocolError |
| 路 RemoteProtocolError |
| - ProxyError |
| - UnsupportedProtocol |
| + DecodingError |
| + TooManyRedirects |
| x HTTPStatusError |
| * InvalidURL |
| * CookieConflict |
| * StreamError |
| x StreamConsumed |
| x StreamClosed |
| x ResponseNotRead |
| x RequestNotRead |
| """ |
|
|
| from __future__ import annotations |
|
|
| import contextlib |
| import typing |
|
|
| if typing.TYPE_CHECKING: |
| from ._models import Request, Response |
|
|
| __all__ = [ |
| "CloseError", |
| "ConnectError", |
| "ConnectTimeout", |
| "CookieConflict", |
| "DecodingError", |
| "HTTPError", |
| "HTTPStatusError", |
| "InvalidURL", |
| "LocalProtocolError", |
| "NetworkError", |
| "PoolTimeout", |
| "ProtocolError", |
| "ProxyError", |
| "ReadError", |
| "ReadTimeout", |
| "RemoteProtocolError", |
| "RequestError", |
| "RequestNotRead", |
| "ResponseNotRead", |
| "StreamClosed", |
| "StreamConsumed", |
| "StreamError", |
| "TimeoutException", |
| "TooManyRedirects", |
| "TransportError", |
| "UnsupportedProtocol", |
| "WriteError", |
| "WriteTimeout", |
| ] |
|
|
|
|
| class HTTPError(Exception): |
| """ |
| Base class for `RequestError` and `HTTPStatusError`. |
| |
| Useful for `try...except` blocks when issuing a request, |
| and then calling `.raise_for_status()`. |
| |
| For example: |
| |
| ``` |
| try: |
| response = httpx.get("https://www.example.com") |
| response.raise_for_status() |
| except httpx.HTTPError as exc: |
| print(f"HTTP Exception for {exc.request.url} - {exc}") |
| ``` |
| """ |
|
|
| def __init__(self, message: str) -> None: |
| super().__init__(message) |
| self._request: Request | None = None |
|
|
| @property |
| def request(self) -> Request: |
| if self._request is None: |
| raise RuntimeError("The .request property has not been set.") |
| return self._request |
|
|
| @request.setter |
| def request(self, request: Request) -> None: |
| self._request = request |
|
|
|
|
| class RequestError(HTTPError): |
| """ |
| Base class for all exceptions that may occur when issuing a `.request()`. |
| """ |
|
|
| def __init__(self, message: str, *, request: Request | None = None) -> None: |
| super().__init__(message) |
| |
| |
| |
| |
| |
| |
| self._request = request |
|
|
|
|
| class TransportError(RequestError): |
| """ |
| Base class for all exceptions that occur at the level of the Transport API. |
| """ |
|
|
|
|
| |
|
|
|
|
| class TimeoutException(TransportError): |
| """ |
| The base class for timeout errors. |
| |
| An operation has timed out. |
| """ |
|
|
|
|
| class ConnectTimeout(TimeoutException): |
| """ |
| Timed out while connecting to the host. |
| """ |
|
|
|
|
| class ReadTimeout(TimeoutException): |
| """ |
| Timed out while receiving data from the host. |
| """ |
|
|
|
|
| class WriteTimeout(TimeoutException): |
| """ |
| Timed out while sending data to the host. |
| """ |
|
|
|
|
| class PoolTimeout(TimeoutException): |
| """ |
| Timed out waiting to acquire a connection from the pool. |
| """ |
|
|
|
|
| |
|
|
|
|
| class NetworkError(TransportError): |
| """ |
| The base class for network-related errors. |
| |
| An error occurred while interacting with the network. |
| """ |
|
|
|
|
| class ReadError(NetworkError): |
| """ |
| Failed to receive data from the network. |
| """ |
|
|
|
|
| class WriteError(NetworkError): |
| """ |
| Failed to send data through the network. |
| """ |
|
|
|
|
| class ConnectError(NetworkError): |
| """ |
| Failed to establish a connection. |
| """ |
|
|
|
|
| class CloseError(NetworkError): |
| """ |
| Failed to close a connection. |
| """ |
|
|
|
|
| |
|
|
|
|
| class ProxyError(TransportError): |
| """ |
| An error occurred while establishing a proxy connection. |
| """ |
|
|
|
|
| class UnsupportedProtocol(TransportError): |
| """ |
| Attempted to make a request to an unsupported protocol. |
| |
| For example issuing a request to `ftp://www.example.com`. |
| """ |
|
|
|
|
| class ProtocolError(TransportError): |
| """ |
| The protocol was violated. |
| """ |
|
|
|
|
| class LocalProtocolError(ProtocolError): |
| """ |
| A protocol was violated by the client. |
| |
| For example if the user instantiated a `Request` instance explicitly, |
| failed to include the mandatory `Host:` header, and then issued it directly |
| using `client.send()`. |
| """ |
|
|
|
|
| class RemoteProtocolError(ProtocolError): |
| """ |
| The protocol was violated by the server. |
| |
| For example, returning malformed HTTP. |
| """ |
|
|
|
|
| |
|
|
|
|
| class DecodingError(RequestError): |
| """ |
| Decoding of the response failed, due to a malformed encoding. |
| """ |
|
|
|
|
| class TooManyRedirects(RequestError): |
| """ |
| Too many redirects. |
| """ |
|
|
|
|
| |
|
|
|
|
| class HTTPStatusError(HTTPError): |
| """ |
| The response had an error HTTP status of 4xx or 5xx. |
| |
| May be raised when calling `response.raise_for_status()` |
| """ |
|
|
| def __init__(self, message: str, *, request: Request, response: Response) -> None: |
| super().__init__(message) |
| self.request = request |
| self.response = response |
|
|
|
|
| class InvalidURL(Exception): |
| """ |
| URL is improperly formed or cannot be parsed. |
| """ |
|
|
| def __init__(self, message: str) -> None: |
| super().__init__(message) |
|
|
|
|
| class CookieConflict(Exception): |
| """ |
| Attempted to lookup a cookie by name, but multiple cookies existed. |
| |
| Can occur when calling `response.cookies.get(...)`. |
| """ |
|
|
| def __init__(self, message: str) -> None: |
| super().__init__(message) |
|
|
|
|
| |
|
|
| |
| |
|
|
|
|
| class StreamError(RuntimeError): |
| """ |
| The base class for stream exceptions. |
| |
| The developer made an error in accessing the request stream in |
| an invalid way. |
| """ |
|
|
| def __init__(self, message: str) -> None: |
| super().__init__(message) |
|
|
|
|
| class StreamConsumed(StreamError): |
| """ |
| Attempted to read or stream content, but the content has already |
| been streamed. |
| """ |
|
|
| def __init__(self) -> None: |
| message = ( |
| "Attempted to read or stream some content, but the content has " |
| "already been streamed. For requests, this could be due to passing " |
| "a generator as request content, and then receiving a redirect " |
| "response or a secondary request as part of an authentication flow." |
| "For responses, this could be due to attempting to stream the response " |
| "content more than once." |
| ) |
| super().__init__(message) |
|
|
|
|
| class StreamClosed(StreamError): |
| """ |
| Attempted to read or stream response content, but the request has been |
| closed. |
| """ |
|
|
| def __init__(self) -> None: |
| message = ( |
| "Attempted to read or stream content, but the stream has " "been closed." |
| ) |
| super().__init__(message) |
|
|
|
|
| class ResponseNotRead(StreamError): |
| """ |
| Attempted to access streaming response content, without having called `read()`. |
| """ |
|
|
| def __init__(self) -> None: |
| message = ( |
| "Attempted to access streaming response content," |
| " without having called `read()`." |
| ) |
| super().__init__(message) |
|
|
|
|
| class RequestNotRead(StreamError): |
| """ |
| Attempted to access streaming request content, without having called `read()`. |
| """ |
|
|
| def __init__(self) -> None: |
| message = ( |
| "Attempted to access streaming request content," |
| " without having called `read()`." |
| ) |
| super().__init__(message) |
|
|
|
|
| @contextlib.contextmanager |
| def request_context( |
| request: Request | None = None, |
| ) -> typing.Iterator[None]: |
| """ |
| A context manager that can be used to attach the given request context |
| to any `RequestError` exceptions that are raised within the block. |
| """ |
| try: |
| yield |
| except RequestError as exc: |
| if request is not None: |
| exc.request = request |
| raise exc |
|
|