codekingpro/portable-devtools
115k
1"""2Our exception hierarchy:3 4* HTTPError5 x RequestError6 + TransportError7 - TimeoutException8 · ConnectTimeout9 · ReadTimeout10 · WriteTimeout11 · PoolTimeout12 - NetworkError13 · ConnectError14 · ReadError15 · WriteError16 · CloseError17 - ProtocolError18 · LocalProtocolError19 · RemoteProtocolError20 - ProxyError21 - UnsupportedProtocol22 + DecodingError23 + TooManyRedirects24 x HTTPStatusError25* InvalidURL26* CookieConflict27* StreamError28 x StreamConsumed29 x StreamClosed30 x ResponseNotRead31 x RequestNotRead32"""33 34from __future__ import annotations35 36import contextlib37import typing38 39if typing.TYPE_CHECKING:40 from ._models import Request, Response # pragma: no cover41 42__all__ = [43 "CloseError",44 "ConnectError",45 "ConnectTimeout",46 "CookieConflict",47 "DecodingError",48 "HTTPError",49 "HTTPStatusError",50 "InvalidURL",51 "LocalProtocolError",52 "NetworkError",53 "PoolTimeout",54 "ProtocolError",55 "ProxyError",56 "ReadError",57 "ReadTimeout",58 "RemoteProtocolError",59 "RequestError",60 "RequestNotRead",61 "ResponseNotRead",62 "StreamClosed",63 "StreamConsumed",64 "StreamError",65 "TimeoutException",66 "TooManyRedirects",67 "TransportError",68 "UnsupportedProtocol",69 "WriteError",70 "WriteTimeout",71]72 73 74class HTTPError(Exception):75 """76 Base class for `RequestError` and `HTTPStatusError`.77 78 Useful for `try...except` blocks when issuing a request,79 and then calling `.raise_for_status()`.80 81 For example:82 83 ```84 try:85 response = httpx.get("https://www.example.com")86 response.raise_for_status()87 except httpx.HTTPError as exc:88 print(f"HTTP Exception for {exc.request.url} - {exc}")89 ```90 """91 92 def __init__(self, message: str) -> None:93 super().__init__(message)94 self._request: Request | None = None95 96 @property97 def request(self) -> Request:98 if self._request is None:99 raise RuntimeError("The .request property has not been set.")100 return self._request101 102 @request.setter103 def request(self, request: Request) -> None:104 self._request = request105 106 107class RequestError(HTTPError):108 """109 Base class for all exceptions that may occur when issuing a `.request()`.110 """111 112 def __init__(self, message: str, *, request: Request | None = None) -> None:113 super().__init__(message)114 # At the point an exception is raised we won't typically have a request115 # instance to associate it with.116 #117 # The 'request_context' context manager is used within the Client and118 # Response methods in order to ensure that any raised exceptions119 # have a `.request` property set on them.120 self._request = request121 122 123class TransportError(RequestError):124 """125 Base class for all exceptions that occur at the level of the Transport API.126 """127 128 129# Timeout exceptions...130 131 132class TimeoutException(TransportError):133 """134 The base class for timeout errors.135 136 An operation has timed out.137 """138 139 140class ConnectTimeout(TimeoutException):141 """142 Timed out while connecting to the host.143 """144 145 146class ReadTimeout(TimeoutException):147 """148 Timed out while receiving data from the host.149 """150 151 152class WriteTimeout(TimeoutException):153 """154 Timed out while sending data to the host.155 """156 157 158class PoolTimeout(TimeoutException):159 """160 Timed out waiting to acquire a connection from the pool.161 """162 163 164# Core networking exceptions...165 166 167class NetworkError(TransportError):168 """169 The base class for network-related errors.170 171 An error occurred while interacting with the network.172 """173 174 175class ReadError(NetworkError):176 """177 Failed to receive data from the network.178 """179 180 181class WriteError(NetworkError):182 """183 Failed to send data through the network.184 """185 186 187class ConnectError(NetworkError):188 """189 Failed to establish a connection.190 """191 192 193class CloseError(NetworkError):194 """195 Failed to close a connection.196 """197 198 199# Other transport exceptions...200 201 202class ProxyError(TransportError):203 """204 An error occurred while establishing a proxy connection.205 """206 207 208class UnsupportedProtocol(TransportError):209 """210 Attempted to make a request to an unsupported protocol.211 212 For example issuing a request to `ftp://www.example.com`.213 """214 215 216class ProtocolError(TransportError):217 """218 The protocol was violated.219 """220 221 222class LocalProtocolError(ProtocolError):223 """224 A protocol was violated by the client.225 226 For example if the user instantiated a `Request` instance explicitly,227 failed to include the mandatory `Host:` header, and then issued it directly228 using `client.send()`.229 """230 231 232class RemoteProtocolError(ProtocolError):233 """234 The protocol was violated by the server.235 236 For example, returning malformed HTTP.237 """238 239 240# Other request exceptions...241 242 243class DecodingError(RequestError):244 """245 Decoding of the response failed, due to a malformed encoding.246 """247 248 249class TooManyRedirects(RequestError):250 """251 Too many redirects.252 """253 254 255# Client errors256 257 258class HTTPStatusError(HTTPError):259 """260 The response had an error HTTP status of 4xx or 5xx.261 262 May be raised when calling `response.raise_for_status()`263 """264 265 def __init__(self, message: str, *, request: Request, response: Response) -> None:266 super().__init__(message)267 self.request = request268 self.response = response269 270 271class InvalidURL(Exception):272 """273 URL is improperly formed or cannot be parsed.274 """275 276 def __init__(self, message: str) -> None:277 super().__init__(message)278 279 280class CookieConflict(Exception):281 """282 Attempted to lookup a cookie by name, but multiple cookies existed.283 284 Can occur when calling `response.cookies.get(...)`.285 """286 287 def __init__(self, message: str) -> None:288 super().__init__(message)289 290 291# Stream exceptions...292 293# These may occur as the result of a programming error, by accessing294# the request/response stream in an invalid manner.295 296 297class StreamError(RuntimeError):298 """299 The base class for stream exceptions.300 301 The developer made an error in accessing the request stream in302 an invalid way.303 """304 305 def __init__(self, message: str) -> None:306 super().__init__(message)307 308 309class StreamConsumed(StreamError):310 """311 Attempted to read or stream content, but the content has already312 been streamed.313 """314 315 def __init__(self) -> None:316 message = (317 "Attempted to read or stream some content, but the content has "318 "already been streamed. For requests, this could be due to passing "319 "a generator as request content, and then receiving a redirect "320 "response or a secondary request as part of an authentication flow."321 "For responses, this could be due to attempting to stream the response "322 "content more than once."323 )324 super().__init__(message)325 326 327class StreamClosed(StreamError):328 """329 Attempted to read or stream response content, but the request has been330 closed.331 """332 333 def __init__(self) -> None:334 message = (335 "Attempted to read or stream content, but the stream has " "been closed."336 )337 super().__init__(message)338 339 340class ResponseNotRead(StreamError):341 """342 Attempted to access streaming response content, without having called `read()`.343 """344 345 def __init__(self) -> None:346 message = (347 "Attempted to access streaming response content,"348 " without having called `read()`."349 )350 super().__init__(message)351 352 353class RequestNotRead(StreamError):354 """355 Attempted to access streaming request content, without having called `read()`.356 """357 358 def __init__(self) -> None:359 message = (360 "Attempted to access streaming request content,"361 " without having called `read()`."362 )363 super().__init__(message)364 365 366@contextlib.contextmanager367def request_context(368 request: Request | None = None,369) -> typing.Iterator[None]:370 """371 A context manager that can be used to attach the given request context372 to any `RequestError` exceptions that are raised within the block.373 """374 try:375 yield376 except RequestError as exc:377 if request is not None:378 exc.request = request379 raise exc380 