| from __future__ import annotations |
|
|
| import contextlib |
| import typing |
|
|
| from .._models import ( |
| URL, |
| Extensions, |
| HeaderTypes, |
| Origin, |
| Request, |
| Response, |
| enforce_bytes, |
| enforce_headers, |
| enforce_url, |
| include_request_headers, |
| ) |
|
|
|
|
| class RequestInterface: |
| def request( |
| self, |
| method: bytes | str, |
| url: URL | bytes | str, |
| *, |
| headers: HeaderTypes = None, |
| content: bytes | typing.Iterator[bytes] | None = None, |
| extensions: Extensions | None = None, |
| ) -> Response: |
| |
| method = enforce_bytes(method, name="method") |
| url = enforce_url(url, name="url") |
| headers = enforce_headers(headers, name="headers") |
|
|
| |
| headers = include_request_headers(headers, url=url, content=content) |
|
|
| request = Request( |
| method=method, |
| url=url, |
| headers=headers, |
| content=content, |
| extensions=extensions, |
| ) |
| response = self.handle_request(request) |
| try: |
| response.read() |
| finally: |
| response.close() |
| return response |
|
|
| @contextlib.contextmanager |
| def stream( |
| self, |
| method: bytes | str, |
| url: URL | bytes | str, |
| *, |
| headers: HeaderTypes = None, |
| content: bytes | typing.Iterator[bytes] | None = None, |
| extensions: Extensions | None = None, |
| ) -> typing.Iterator[Response]: |
| |
| method = enforce_bytes(method, name="method") |
| url = enforce_url(url, name="url") |
| headers = enforce_headers(headers, name="headers") |
|
|
| |
| headers = include_request_headers(headers, url=url, content=content) |
|
|
| request = Request( |
| method=method, |
| url=url, |
| headers=headers, |
| content=content, |
| extensions=extensions, |
| ) |
| response = self.handle_request(request) |
| try: |
| yield response |
| finally: |
| response.close() |
|
|
| def handle_request(self, request: Request) -> Response: |
| raise NotImplementedError() |
|
|
|
|
| class ConnectionInterface(RequestInterface): |
| def close(self) -> None: |
| raise NotImplementedError() |
|
|
| def info(self) -> str: |
| raise NotImplementedError() |
|
|
| def can_handle_request(self, origin: Origin) -> bool: |
| raise NotImplementedError() |
|
|
| def is_available(self) -> bool: |
| """ |
| Return `True` if the connection is currently able to accept an |
| outgoing request. |
| |
| An HTTP/1.1 connection will only be available if it is currently idle. |
| |
| An HTTP/2 connection will be available so long as the stream ID space is |
| not yet exhausted, and the connection is not in an error state. |
| |
| While the connection is being established we may not yet know if it is going |
| to result in an HTTP/1.1 or HTTP/2 connection. The connection should be |
| treated as being available, but might ultimately raise `NewConnectionRequired` |
| required exceptions if multiple requests are attempted over a connection |
| that ends up being established as HTTP/1.1. |
| """ |
| raise NotImplementedError() |
|
|
| def has_expired(self) -> bool: |
| """ |
| Return `True` if the connection is in a state where it should be closed. |
| |
| This either means that the connection is idle and it has passed the |
| expiry time on its keep-alive, or that server has sent an EOF. |
| """ |
| raise NotImplementedError() |
|
|
| def is_idle(self) -> bool: |
| """ |
| Return `True` if the connection is currently idle. |
| """ |
| raise NotImplementedError() |
|
|
| def is_closed(self) -> bool: |
| """ |
| Return `True` if the connection has been closed. |
| |
| Used when a response is closed to determine if the connection may be |
| returned to the connection pool or not. |
| """ |
| raise NotImplementedError() |
|
|