Make async dependencies optional.
This commit is contained in:
parent
59df8190a4
commit
0dd72fce4a
19
README.md
19
README.md
@ -97,10 +97,12 @@ Install with pip:
|
||||
$ pip install httpx
|
||||
```
|
||||
|
||||
Or, to include the optional HTTP/2 support, use:
|
||||
There are also a number of optional dependancies.
|
||||
|
||||
For example to include asyncio and HTTP/2 support, use:
|
||||
|
||||
```shell
|
||||
$ pip install httpx[http2]
|
||||
$ pip install 'httpx[asyncio,http2]'
|
||||
```
|
||||
|
||||
HTTPX requires Python 3.8+.
|
||||
@ -129,15 +131,16 @@ The HTTPX project relies on these excellent libraries:
|
||||
* `h11` - HTTP/1.1 support.
|
||||
* `certifi` - SSL certificates.
|
||||
* `idna` - Internationalized domain name support.
|
||||
* `sniffio` - Async library autodetection.
|
||||
|
||||
As well as these optional installs:
|
||||
|
||||
* `h2` - HTTP/2 support. *(Optional, with `httpx[http2]`)*
|
||||
* `socksio` - SOCKS proxy support. *(Optional, with `httpx[socks]`)*
|
||||
* `rich` - Rich terminal support. *(Optional, with `httpx[cli]`)*
|
||||
* `click` - Command line client support. *(Optional, with `httpx[cli]`)*
|
||||
* `brotli` or `brotlicffi` - Decoding for "brotli" compressed responses. *(Optional, with `httpx[brotli]`)*
|
||||
* `anyio`, `sniffio` - Async support for `asyncio`. *(Optional, with `httpx['asyncio']`)*
|
||||
* `trio`, `sniffio` - Async support for `trio`. *(Optional, with `httpx['trio']`)*
|
||||
* `h2` - HTTP/2 support. *(Optional, with `httpx['http2']`)*
|
||||
* `socksio` - SOCKS proxy support. *(Optional, with `httpx['socks']`)*
|
||||
* `rich` - Rich terminal support. *(Optional, with `httpx['cli']`)*
|
||||
* `click` - Command line client support. *(Optional, with `httpx['cli']`)*
|
||||
* `brotli` or `brotlicffi` - Decoding for "brotli" compressed responses. *(Optional, with `httpx['brotli']`)*
|
||||
|
||||
A huge amount of credit is due to `requests` for the API layout that
|
||||
much of this work follows, as well as to `urllib3` for plenty of design
|
||||
|
||||
@ -10,6 +10,24 @@ long-lived network connections such as WebSockets.
|
||||
If you're working with an async web framework then you'll also want to use an
|
||||
async client for sending outgoing HTTP requests.
|
||||
|
||||
## Enabling Async support
|
||||
|
||||
To enable async support you'll need to install some additional dependencies:
|
||||
|
||||
If you're using Python's [standard `asyncio` support](https://docs.python.org/3/library/asyncio.html) then:
|
||||
|
||||
```shell
|
||||
$ pip install httpx['asyncio']
|
||||
```
|
||||
|
||||
Or, if you're working with the [`trio` third party package](https://trio.readthedocs.io/en/stable/):
|
||||
|
||||
```shell
|
||||
$ pip install httpx['trio']
|
||||
```
|
||||
|
||||
We highly recommend `trio` for async support. The `trio` project [pioneered the principles of structured concurrency](https://en.wikipedia.org/wiki/Structured_concurrency), and has a more carefully constrained API against which to work from.
|
||||
|
||||
## Making Async requests
|
||||
|
||||
To make asynchronous requests, you'll need an `AsyncClient`.
|
||||
|
||||
@ -28,7 +28,7 @@ trying out our HTTP/2 support. You can do so by first making sure to install
|
||||
the optional HTTP/2 dependencies...
|
||||
|
||||
```shell
|
||||
$ pip install httpx[http2]
|
||||
$ pip install httpx['http2']
|
||||
```
|
||||
|
||||
And then instantiating a client with HTTP/2 support enabled:
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
import typing
|
||||
|
||||
import sniffio
|
||||
|
||||
from .._models import Request, Response
|
||||
from .._types import AsyncByteStream
|
||||
from .base import AsyncBaseTransport
|
||||
@ -25,6 +23,8 @@ _ASGIApp = typing.Callable[
|
||||
|
||||
|
||||
def create_event() -> "Event":
|
||||
import sniffio
|
||||
|
||||
if sniffio.current_async_library() == "trio":
|
||||
import trio
|
||||
|
||||
|
||||
@ -64,7 +64,7 @@ SOCKET_OPTION = typing.Union[
|
||||
def map_httpcore_exceptions() -> typing.Iterator[None]:
|
||||
try:
|
||||
yield
|
||||
except Exception as exc: # noqa: PIE-786
|
||||
except Exception as exc:
|
||||
mapped_exc = None
|
||||
|
||||
for from_exc, to_exc in HTTPCORE_EXC_MAP.items():
|
||||
@ -269,6 +269,13 @@ class AsyncHTTPTransport(AsyncBaseTransport):
|
||||
retries: int = 0,
|
||||
socket_options: typing.Optional[typing.Iterable[SOCKET_OPTION]] = None,
|
||||
) -> None:
|
||||
try:
|
||||
import sniffio # noqa: F401
|
||||
except ImportError: # pragma: nocover
|
||||
raise RuntimeError(
|
||||
"Using httpx in async mode, but neither httpx['asyncio'] or asyncio['trio'] is installed."
|
||||
)
|
||||
|
||||
ssl_context = create_ssl_context(verify=verify, cert=cert, trust_env=trust_env)
|
||||
|
||||
if proxy is None:
|
||||
|
||||
@ -9,8 +9,6 @@ import typing
|
||||
from pathlib import Path
|
||||
from urllib.request import getproxies
|
||||
|
||||
import sniffio
|
||||
|
||||
from ._types import PrimitiveData
|
||||
|
||||
if typing.TYPE_CHECKING: # pragma: no cover
|
||||
@ -322,33 +320,18 @@ def peek_filelike_length(stream: typing.Any) -> typing.Optional[int]:
|
||||
|
||||
|
||||
class Timer:
|
||||
async def _get_time(self) -> float:
|
||||
library = sniffio.current_async_library()
|
||||
if library == "trio":
|
||||
import trio
|
||||
|
||||
return trio.current_time()
|
||||
elif library == "curio": # pragma: no cover
|
||||
import curio
|
||||
|
||||
return typing.cast(float, await curio.clock())
|
||||
|
||||
import asyncio
|
||||
|
||||
return asyncio.get_event_loop().time()
|
||||
|
||||
def sync_start(self) -> None:
|
||||
self.started = time.perf_counter()
|
||||
|
||||
async def async_start(self) -> None:
|
||||
self.started = await self._get_time()
|
||||
self.started = time.perf_counter()
|
||||
|
||||
def sync_elapsed(self) -> float:
|
||||
now = time.perf_counter()
|
||||
return now - self.started
|
||||
|
||||
async def async_elapsed(self) -> float:
|
||||
now = await self._get_time()
|
||||
now = time.perf_counter()
|
||||
return now - self.started
|
||||
|
||||
|
||||
|
||||
@ -28,9 +28,8 @@ classifiers = [
|
||||
]
|
||||
dependencies = [
|
||||
"certifi",
|
||||
"httpcore>=0.18.0,<0.19.0",
|
||||
"httpcore>=1.0.0,<2.0.0",
|
||||
"idna",
|
||||
"sniffio",
|
||||
]
|
||||
dynamic = ["readme", "version"]
|
||||
|
||||
@ -45,10 +44,16 @@ cli = [
|
||||
"rich>=10,<14",
|
||||
]
|
||||
http2 = [
|
||||
"h2>=3,<5",
|
||||
"httpcore['http2']",
|
||||
]
|
||||
socks = [
|
||||
"socksio==1.*",
|
||||
"httpcore['socks']",
|
||||
]
|
||||
asyncio = [
|
||||
"httpcore['asyncio']"
|
||||
]
|
||||
trio = [
|
||||
"httpcore['trio']"
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
# On the other hand, we're not pinning package dependencies, because our tests
|
||||
# needs to pass with the latest version of the packages.
|
||||
# Reference: https://github.com/encode/httpx/pull/1721#discussion_r661241588
|
||||
-e .[brotli,cli,http2,socks]
|
||||
-e .[asyncio,trio,brotli,cli,http2,socks]
|
||||
|
||||
# Optional charset auto-detection
|
||||
# Used in our test cases
|
||||
@ -26,7 +26,6 @@ mypy==1.5.1
|
||||
types-certifi==2021.10.8.2
|
||||
pytest==7.4.0
|
||||
ruff==0.0.286
|
||||
trio==0.22.2
|
||||
trio-typing==0.8.0
|
||||
trustme==1.1.0
|
||||
uvicorn==0.22.0
|
||||
|
||||
Loading…
Reference in New Issue
Block a user