diff options
| author | AlexSm <[email protected]> | 2024-01-04 15:09:05 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-01-04 15:09:05 +0100 |
| commit | dab291146f6cd7d35684e3a1150e5bb1c412982c (patch) | |
| tree | 36ef35f6cacb6432845a4a33f940c95871036b32 /contrib/python/httpcore | |
| parent | 63660ad5e7512029fd0218e7a636580695a24e1f (diff) | |
Library import 5, delete go dependencies (#832)
* Library import 5, delete go dependencies
* Fix yt client
Diffstat (limited to 'contrib/python/httpcore')
| -rw-r--r-- | contrib/python/httpcore/.dist-info/METADATA | 66 | ||||
| -rw-r--r-- | contrib/python/httpcore/README.md | 36 | ||||
| -rw-r--r-- | contrib/python/httpcore/httpcore/__init__.py | 2 | ||||
| -rw-r--r-- | contrib/python/httpcore/httpcore/_async/connection_pool.py | 20 | ||||
| -rw-r--r-- | contrib/python/httpcore/httpcore/_backends/auto.py | 5 | ||||
| -rw-r--r-- | contrib/python/httpcore/httpcore/_backends/sync.py | 6 | ||||
| -rw-r--r-- | contrib/python/httpcore/httpcore/_sync/connection_pool.py | 20 | ||||
| -rw-r--r-- | contrib/python/httpcore/httpcore/_synchronization.py | 108 | ||||
| -rw-r--r-- | contrib/python/httpcore/ya.make | 4 |
9 files changed, 165 insertions, 102 deletions
diff --git a/contrib/python/httpcore/.dist-info/METADATA b/contrib/python/httpcore/.dist-info/METADATA index 3776738cafc..07eab9de210 100644 --- a/contrib/python/httpcore/.dist-info/METADATA +++ b/contrib/python/httpcore/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: httpcore -Version: 0.18.0 +Version: 1.0.2 Summary: A minimal low-level HTTP client. Project-URL: Documentation, https://www.encode.io/httpcore Project-URL: Homepage, https://www.encode.io/httpcore/ @@ -21,16 +21,19 @@ Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 Classifier: Topic :: Internet :: WWW/HTTP Requires-Python: >=3.8 -Requires-Dist: anyio<5.0,>=3.0 Requires-Dist: certifi Requires-Dist: h11<0.15,>=0.13 -Requires-Dist: sniffio==1.* +Provides-Extra: asyncio +Requires-Dist: anyio<5.0,>=4.0; extra == 'asyncio' Provides-Extra: http2 Requires-Dist: h2<5,>=3; extra == 'http2' Provides-Extra: socks Requires-Dist: socksio==1.*; extra == 'socks' +Provides-Extra: trio +Requires-Dist: trio<0.23.0,>=0.22.0; extra == 'trio' Description-Content-Type: text/markdown # HTTP Core @@ -70,16 +73,10 @@ For HTTP/1.1 only support, install with: $ pip install httpcore ``` -For HTTP/1.1 and HTTP/2 support, install with: +There are also a number of optional extras available... ```shell -$ pip install httpcore[http2] -``` - -For SOCKS proxy support, install with: - -```shell -$ pip install httpcore[socks] +$ pip install httpcore['asyncio,trio,http2,socks'] ``` # Sending requests @@ -124,12 +121,59 @@ The motivation for `httpcore` is: * To provide a reusable low-level client library, that other packages can then build on top of. * To provide a *really clear interface split* between the networking code and client logic, so that each is easier to understand and reason about in isolation. + +## Dependencies + +The `httpcore` package has the following dependencies... + +* `h11` +* `certifi` + +And the following optional extras... + +* `anyio` - Required by `pip install httpcore['asyncio']`. +* `trio` - Required by `pip install httpcore['trio']`. +* `h2` - Required by `pip install httpcore['http2']`. +* `socksio` - Required by `pip install httpcore['socks']`. + +## Versioning + +We use [SEMVER for our versioning policy](https://semver.org/). + +For changes between package versions please see our [project changelog](CHANGELOG.md). + +We recommend pinning your requirements either the most current major version, or a more specific version range: + +```python +pip install 'httpcore==1.*' +``` # Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## 1.0.2 (November 10th, 2023) + +- Fix `float("inf")` timeouts in `Event.wait` function. (#846) + +## 1.0.1 (November 3rd, 2023) + +- Fix pool timeout to account for the total time spent retrying. (#823) +- Raise a neater RuntimeError when the correct async deps are not installed. (#826) +- Add support for synchronous TLS-in-TLS streams. (#840) + +## 1.0.0 (October 6th, 2023) + +From version 1.0 our async support is now optional, as the package has minimal dependencies by default. + +For async support use either `pip install 'httpcore[asyncio]'` or `pip install 'httpcore[trio]'`. + +The project versioning policy is now explicitly governed by SEMVER. See https://semver.org/. + +- Async support becomes fully optional. (#809) +- Add support for Python 3.12. (#807) + ## 0.18.0 (September 8th, 2023) - Add support for HTTPS proxies. (#745, #786) diff --git a/contrib/python/httpcore/README.md b/contrib/python/httpcore/README.md index 66a21500169..e7bfd5838f6 100644 --- a/contrib/python/httpcore/README.md +++ b/contrib/python/httpcore/README.md @@ -35,16 +35,10 @@ For HTTP/1.1 only support, install with: $ pip install httpcore ``` -For HTTP/1.1 and HTTP/2 support, install with: +There are also a number of optional extras available... ```shell -$ pip install httpcore[http2] -``` - -For SOCKS proxy support, install with: - -```shell -$ pip install httpcore[socks] +$ pip install httpcore['asyncio,trio,http2,socks'] ``` # Sending requests @@ -89,3 +83,29 @@ The motivation for `httpcore` is: * To provide a reusable low-level client library, that other packages can then build on top of. * To provide a *really clear interface split* between the networking code and client logic, so that each is easier to understand and reason about in isolation. + +## Dependencies + +The `httpcore` package has the following dependencies... + +* `h11` +* `certifi` + +And the following optional extras... + +* `anyio` - Required by `pip install httpcore['asyncio']`. +* `trio` - Required by `pip install httpcore['trio']`. +* `h2` - Required by `pip install httpcore['http2']`. +* `socksio` - Required by `pip install httpcore['socks']`. + +## Versioning + +We use [SEMVER for our versioning policy](https://semver.org/). + +For changes between package versions please see our [project changelog](CHANGELOG.md). + +We recommend pinning your requirements either the most current major version, or a more specific version range: + +```python +pip install 'httpcore==1.*' +``` diff --git a/contrib/python/httpcore/httpcore/__init__.py b/contrib/python/httpcore/httpcore/__init__.py index 65abe9716a1..eb3e577186b 100644 --- a/contrib/python/httpcore/httpcore/__init__.py +++ b/contrib/python/httpcore/httpcore/__init__.py @@ -130,7 +130,7 @@ __all__ = [ "WriteError", ] -__version__ = "0.18.0" +__version__ = "1.0.2" __locals = locals() diff --git a/contrib/python/httpcore/httpcore/_async/connection_pool.py b/contrib/python/httpcore/httpcore/_async/connection_pool.py index ddc0510e60e..0320c6d80e4 100644 --- a/contrib/python/httpcore/httpcore/_async/connection_pool.py +++ b/contrib/python/httpcore/httpcore/_async/connection_pool.py @@ -1,11 +1,12 @@ import ssl import sys +import time from types import TracebackType from typing import AsyncIterable, AsyncIterator, Iterable, List, Optional, Type from .._backends.auto import AutoBackend from .._backends.base import SOCKET_OPTION, AsyncNetworkBackend -from .._exceptions import ConnectionNotAvailable, UnsupportedProtocol +from .._exceptions import ConnectionNotAvailable, PoolTimeout, UnsupportedProtocol from .._models import Origin, Request, Response from .._synchronization import AsyncEvent, AsyncLock, AsyncShieldCancellation from .connection import AsyncHTTPConnection @@ -220,6 +221,13 @@ class AsyncConnectionPool(AsyncRequestInterface): ) status = RequestStatus(request) + timeouts = request.extensions.get("timeout", {}) + timeout = timeouts.get("pool", None) + + if timeout is not None: + deadline = time.monotonic() + timeout + else: + deadline = float("inf") async with self._pool_lock: self._requests.append(status) @@ -227,8 +235,6 @@ class AsyncConnectionPool(AsyncRequestInterface): await self._attempt_to_acquire_connection(status) while True: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("pool", None) try: connection = await status.wait_for_connection(timeout=timeout) except BaseException as exc: @@ -263,6 +269,10 @@ class AsyncConnectionPool(AsyncRequestInterface): else: break + timeout = deadline - time.monotonic() + if timeout < 0: + raise PoolTimeout # pragma: nocover + # When we return the response, we wrap the stream in a special class # that handles notifying the connection pool once the response # has been released. @@ -316,6 +326,10 @@ class AsyncConnectionPool(AsyncRequestInterface): self._requests = [] async def __aenter__(self) -> "AsyncConnectionPool": + # Acquiring the pool lock here ensures that we have the + # correct dependencies installed as early as possible. + async with self._pool_lock: + pass return self async def __aexit__( diff --git a/contrib/python/httpcore/httpcore/_backends/auto.py b/contrib/python/httpcore/httpcore/_backends/auto.py index b612ba071ca..3ac05f4da0b 100644 --- a/contrib/python/httpcore/httpcore/_backends/auto.py +++ b/contrib/python/httpcore/httpcore/_backends/auto.py @@ -1,15 +1,14 @@ import typing from typing import Optional -import sniffio - +from .._synchronization import current_async_library from .base import SOCKET_OPTION, AsyncNetworkBackend, AsyncNetworkStream class AutoBackend(AsyncNetworkBackend): async def _init_backend(self) -> None: if not (hasattr(self, "_backend")): - backend = sniffio.current_async_library() + backend = current_async_library() if backend == "trio": from .trio import TrioBackend diff --git a/contrib/python/httpcore/httpcore/_backends/sync.py b/contrib/python/httpcore/httpcore/_backends/sync.py index f2dbd32afa4..7b7b417dc19 100644 --- a/contrib/python/httpcore/httpcore/_backends/sync.py +++ b/contrib/python/httpcore/httpcore/_backends/sync.py @@ -145,12 +145,6 @@ class SyncStream(NetworkStream): server_hostname: typing.Optional[str] = None, timeout: typing.Optional[float] = None, ) -> NetworkStream: - if isinstance(self._sock, ssl.SSLSocket): # pragma: no cover - raise RuntimeError( - "Attempted to add a TLS layer on top of the existing " - "TLS stream, which is not supported by httpcore package" - ) - exc_map: ExceptionMapping = { socket.timeout: ConnectTimeout, OSError: ConnectError, diff --git a/contrib/python/httpcore/httpcore/_sync/connection_pool.py b/contrib/python/httpcore/httpcore/_sync/connection_pool.py index dbcaff1fcf1..ccfb8d22208 100644 --- a/contrib/python/httpcore/httpcore/_sync/connection_pool.py +++ b/contrib/python/httpcore/httpcore/_sync/connection_pool.py @@ -1,11 +1,12 @@ import ssl import sys +import time from types import TracebackType from typing import Iterable, Iterator, Iterable, List, Optional, Type from .._backends.sync import SyncBackend from .._backends.base import SOCKET_OPTION, NetworkBackend -from .._exceptions import ConnectionNotAvailable, UnsupportedProtocol +from .._exceptions import ConnectionNotAvailable, PoolTimeout, UnsupportedProtocol from .._models import Origin, Request, Response from .._synchronization import Event, Lock, ShieldCancellation from .connection import HTTPConnection @@ -220,6 +221,13 @@ class ConnectionPool(RequestInterface): ) status = RequestStatus(request) + timeouts = request.extensions.get("timeout", {}) + timeout = timeouts.get("pool", None) + + if timeout is not None: + deadline = time.monotonic() + timeout + else: + deadline = float("inf") with self._pool_lock: self._requests.append(status) @@ -227,8 +235,6 @@ class ConnectionPool(RequestInterface): self._attempt_to_acquire_connection(status) while True: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("pool", None) try: connection = status.wait_for_connection(timeout=timeout) except BaseException as exc: @@ -263,6 +269,10 @@ class ConnectionPool(RequestInterface): else: break + timeout = deadline - time.monotonic() + if timeout < 0: + raise PoolTimeout # pragma: nocover + # When we return the response, we wrap the stream in a special class # that handles notifying the connection pool once the response # has been released. @@ -316,6 +326,10 @@ class ConnectionPool(RequestInterface): self._requests = [] def __enter__(self) -> "ConnectionPool": + # Acquiring the pool lock here ensures that we have the + # correct dependencies installed as early as possible. + with self._pool_lock: + pass return self def __exit__( diff --git a/contrib/python/httpcore/httpcore/_synchronization.py b/contrib/python/httpcore/httpcore/_synchronization.py index bae27c1b112..119d89fc0d5 100644 --- a/contrib/python/httpcore/httpcore/_synchronization.py +++ b/contrib/python/httpcore/httpcore/_synchronization.py @@ -2,8 +2,6 @@ import threading from types import TracebackType from typing import Optional, Type -import sniffio - from ._exceptions import ExceptionMapping, PoolTimeout, map_exceptions # Our async synchronization primatives use either 'anyio' or 'trio' depending @@ -20,6 +18,32 @@ except ImportError: # pragma: nocover anyio = None # type: ignore +def current_async_library() -> str: + # Determine if we're running under trio or asyncio. + # See https://sniffio.readthedocs.io/en/latest/ + try: + import sniffio + except ImportError: # pragma: nocover + environment = "asyncio" + else: + environment = sniffio.current_async_library() + + if environment not in ("asyncio", "trio"): # pragma: nocover + raise RuntimeError("Running under an unsupported async environment.") + + if environment == "asyncio" and anyio is None: # pragma: nocover + raise RuntimeError( + "Running with asyncio requires installation of 'httpcore[asyncio]'." + ) + + if environment == "trio" and trio is None: # pragma: nocover + raise RuntimeError( + "Running with trio requires installation of 'httpcore[trio]'." + ) + + return environment + + class AsyncLock: def __init__(self) -> None: self._backend = "" @@ -29,18 +53,10 @@ class AsyncLock: Detect if we're running under 'asyncio' or 'trio' and create a lock with the correct implementation. """ - self._backend = sniffio.current_async_library() + self._backend = current_async_library() if self._backend == "trio": - if trio is None: # pragma: nocover - raise RuntimeError( - "Running under trio, requires the 'trio' package to be installed." - ) self._trio_lock = trio.Lock() - else: - if anyio is None: # pragma: nocover - raise RuntimeError( - "Running under asyncio requires the 'anyio' package to be installed." - ) + elif self._backend == "asyncio": self._anyio_lock = anyio.Lock() async def __aenter__(self) -> "AsyncLock": @@ -49,7 +65,7 @@ class AsyncLock: if self._backend == "trio": await self._trio_lock.acquire() - else: + elif self._backend == "asyncio": await self._anyio_lock.acquire() return self @@ -62,7 +78,7 @@ class AsyncLock: ) -> None: if self._backend == "trio": self._trio_lock.release() - else: + elif self._backend == "asyncio": self._anyio_lock.release() @@ -75,18 +91,10 @@ class AsyncEvent: Detect if we're running under 'asyncio' or 'trio' and create a lock with the correct implementation. """ - self._backend = sniffio.current_async_library() + self._backend = current_async_library() if self._backend == "trio": - if trio is None: # pragma: nocover - raise RuntimeError( - "Running under trio requires the 'trio' package to be installed." - ) self._trio_event = trio.Event() - else: - if anyio is None: # pragma: nocover - raise RuntimeError( - "Running under asyncio requires the 'anyio' package to be installed." - ) + elif self._backend == "asyncio": self._anyio_event = anyio.Event() def set(self) -> None: @@ -95,7 +103,7 @@ class AsyncEvent: if self._backend == "trio": self._trio_event.set() - else: + elif self._backend == "asyncio": self._anyio_event.set() async def wait(self, timeout: Optional[float] = None) -> None: @@ -103,22 +111,12 @@ class AsyncEvent: self.setup() if self._backend == "trio": - if trio is None: # pragma: nocover - raise RuntimeError( - "Running under trio requires the 'trio' package to be installed." - ) - trio_exc_map: ExceptionMapping = {trio.TooSlowError: PoolTimeout} timeout_or_inf = float("inf") if timeout is None else timeout with map_exceptions(trio_exc_map): with trio.fail_after(timeout_or_inf): await self._trio_event.wait() - else: - if anyio is None: # pragma: nocover - raise RuntimeError( - "Running under asyncio requires the 'anyio' package to be installed." - ) - + elif self._backend == "asyncio": anyio_exc_map: ExceptionMapping = {TimeoutError: PoolTimeout} with map_exceptions(anyio_exc_map): with anyio.fail_after(timeout): @@ -135,22 +133,12 @@ class AsyncSemaphore: Detect if we're running under 'asyncio' or 'trio' and create a semaphore with the correct implementation. """ - self._backend = sniffio.current_async_library() + self._backend = current_async_library() if self._backend == "trio": - if trio is None: # pragma: nocover - raise RuntimeError( - "Running under trio requires the 'trio' package to be installed." - ) - self._trio_semaphore = trio.Semaphore( initial_value=self._bound, max_value=self._bound ) - else: - if anyio is None: # pragma: nocover - raise RuntimeError( - "Running under asyncio requires the 'anyio' package to be installed." - ) - + elif self._backend == "asyncio": self._anyio_semaphore = anyio.Semaphore( initial_value=self._bound, max_value=self._bound ) @@ -161,13 +149,13 @@ class AsyncSemaphore: if self._backend == "trio": await self._trio_semaphore.acquire() - else: + elif self._backend == "asyncio": await self._anyio_semaphore.acquire() async def release(self) -> None: if self._backend == "trio": self._trio_semaphore.release() - else: + elif self._backend == "asyncio": self._anyio_semaphore.release() @@ -184,27 +172,17 @@ class AsyncShieldCancellation: Detect if we're running under 'asyncio' or 'trio' and create a shielded scope with the correct implementation. """ - self._backend = sniffio.current_async_library() + self._backend = current_async_library() if self._backend == "trio": - if trio is None: # pragma: nocover - raise RuntimeError( - "Running under trio requires the 'trio' package to be installed." - ) - self._trio_shield = trio.CancelScope(shield=True) - else: - if anyio is None: # pragma: nocover - raise RuntimeError( - "Running under asyncio requires the 'anyio' package to be installed." - ) - + elif self._backend == "asyncio": self._anyio_shield = anyio.CancelScope(shield=True) def __enter__(self) -> "AsyncShieldCancellation": if self._backend == "trio": self._trio_shield.__enter__() - else: + elif self._backend == "asyncio": self._anyio_shield.__enter__() return self @@ -216,7 +194,7 @@ class AsyncShieldCancellation: ) -> None: if self._backend == "trio": self._trio_shield.__exit__(exc_type, exc_value, traceback) - else: + elif self._backend == "asyncio": self._anyio_shield.__exit__(exc_type, exc_value, traceback) @@ -248,6 +226,8 @@ class Event: self._event.set() def wait(self, timeout: Optional[float] = None) -> None: + if timeout == float("inf"): # pragma: no cover + timeout = None if not self._event.wait(timeout=timeout): raise PoolTimeout() # pragma: nocover diff --git a/contrib/python/httpcore/ya.make b/contrib/python/httpcore/ya.make index e8516afe103..de7a3ac5a2f 100644 --- a/contrib/python/httpcore/ya.make +++ b/contrib/python/httpcore/ya.make @@ -2,15 +2,13 @@ PY3_LIBRARY() -VERSION(0.18.0) +VERSION(1.0.2) LICENSE(BSD-3-Clause) PEERDIR( - contrib/python/anyio contrib/python/certifi contrib/python/h11 - contrib/python/sniffio ) NO_LINT() |
