Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version 1.0 #809

Merged
merged 14 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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`, `sniffio` - Required by `pip install httpcore['asyncio']`.
* `trio`, `sniffio` - 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.*'
```
16 changes: 16 additions & 0 deletions docs/async.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,22 @@ If you're working with an async web framework then you'll also want to use an as

Launching concurrent async tasks is far more resource efficient than spawning multiple threads. The Python interpreter should be able to comfortably handle switching between over 1000 concurrent tasks, while a sensible number of threads in a thread pool might be to enable around 10 or 20 concurrent threads.

## Enabling Async support

If you're using async with [Python's stdlib `asyncio` support](https://docs.python.org/3/library/asyncio.html), install the optional dependencies using:

```shell
$ pip install 'httpcore[asyncio]'
```

Alternatively, if you're working with [the Python `trio` package](https://trio.readthedocs.io/en/stable/):

```shell
$ pip install 'httpcore[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.

## API differences

When using async support, you need make sure to use an async connection pool class:
Expand Down
2 changes: 2 additions & 0 deletions docs/extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ The following event types are currently exposed...
* `"http2.receive_response_body"`
* `"http2.response_closed"`

The exact set of trace events may be subject to change across different versions of `httpcore`. If you need to rely on a particular set of events it is recommended that you pin installation of the package to a fixed version.

### `"sni_hostname"`

The server's hostname, which is used to confirm the hostname supplied by the SSL certificate.
Expand Down
2 changes: 1 addition & 1 deletion docs/http2.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ When using the `httpcore` client, HTTP/2 support is not enabled by default, beca
If you're issuing highly concurrent requests you might want to consider trying out our HTTP/2 support. You can do so by first making sure to install the optional HTTP/2 dependencies...

```shell
$ pip install httpcore[http2]
$ pip install 'httpcore[http2]'
```

And then instantiating a connection pool with HTTP/2 support enabled:
Expand Down
2 changes: 1 addition & 1 deletion docs/proxies.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ If you use proxies, keep in mind that the `httpcore` package only supports proxi

The `httpcore` package also supports proxies using the SOCKS5 protocol.

Make sure to install the optional dependancy using `pip install httpcore[socks]`.
Make sure to install the optional dependancy using `pip install 'httpcore[socks]'`.

The `SOCKSProxy` class should be using instead of a standard connection pool:

Expand Down
2 changes: 1 addition & 1 deletion httpcore/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def __init__(self, *args, **kwargs): # type: ignore
"WriteError",
]

__version__ = "0.18.0"
__version__ = "1.0.0"


__locals = locals()
Expand Down
4 changes: 2 additions & 2 deletions httpcore/_backends/auto.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import typing
from typing import Optional

import sniffio

from .base import SOCKET_OPTION, AsyncNetworkBackend, AsyncNetworkStream


class AutoBackend(AsyncNetworkBackend):
async def _init_backend(self) -> None:
if not (hasattr(self, "_backend")):
import sniffio

backend = sniffio.current_async_library()
if backend == "trio":
from .trio import TrioBackend
Expand Down
28 changes: 16 additions & 12 deletions httpcore/_synchronization.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
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
Expand All @@ -19,6 +17,12 @@
except ImportError: # pragma: nocover
anyio = None # type: ignore

try:
import sniffio
except ImportError: # pragma: nocover
trio = None # type: ignore
anyio = None # type: ignore


class AsyncLock:
def __init__(self) -> None:
Expand All @@ -33,13 +37,13 @@ def setup(self) -> None:
if self._backend == "trio":
if trio is None: # pragma: nocover
raise RuntimeError(
"Running under trio, requires the 'trio' package to be installed."
"Running with trio requires installation of 'httpcore[trio]'."
)
self._trio_lock = trio.Lock()
else:
if anyio is None: # pragma: nocover
raise RuntimeError(
"Running under asyncio requires the 'anyio' package to be installed."
"Running with asyncio requires installation of 'httpcore[asyncio]'."
)
self._anyio_lock = anyio.Lock()

Expand Down Expand Up @@ -79,13 +83,13 @@ def setup(self) -> None:
if self._backend == "trio":
if trio is None: # pragma: nocover
raise RuntimeError(
"Running under trio requires the 'trio' package to be installed."
"Running with trio requires installation of 'httpcore[trio]'."
)
self._trio_event = trio.Event()
else:
if anyio is None: # pragma: nocover
raise RuntimeError(
"Running under asyncio requires the 'anyio' package to be installed."
"Running with asyncio requires installation of 'httpcore[asyncio]'."
)
self._anyio_event = anyio.Event()

Expand All @@ -105,7 +109,7 @@ async def wait(self, timeout: Optional[float] = None) -> None:
if self._backend == "trio":
if trio is None: # pragma: nocover
raise RuntimeError(
"Running under trio requires the 'trio' package to be installed."
"Running with trio requires installation of 'httpcore[trio]'."
)

trio_exc_map: ExceptionMapping = {trio.TooSlowError: PoolTimeout}
Expand All @@ -116,7 +120,7 @@ async def wait(self, timeout: Optional[float] = None) -> None:
else:
if anyio is None: # pragma: nocover
raise RuntimeError(
"Running under asyncio requires the 'anyio' package to be installed."
"Running with asyncio requires installation of 'httpcore[asyncio]'."
)

anyio_exc_map: ExceptionMapping = {TimeoutError: PoolTimeout}
Expand All @@ -139,7 +143,7 @@ def setup(self) -> None:
if self._backend == "trio":
if trio is None: # pragma: nocover
raise RuntimeError(
"Running under trio requires the 'trio' package to be installed."
"Running with trio requires installation of 'httpcore[trio]'."
)

self._trio_semaphore = trio.Semaphore(
Expand All @@ -148,7 +152,7 @@ def setup(self) -> None:
else:
if anyio is None: # pragma: nocover
raise RuntimeError(
"Running under asyncio requires the 'anyio' package to be installed."
"Running with asyncio requires installation of 'httpcore[asyncio]'."
)

self._anyio_semaphore = anyio.Semaphore(
Expand Down Expand Up @@ -189,14 +193,14 @@ def __init__(self) -> None:
if self._backend == "trio":
if trio is None: # pragma: nocover
raise RuntimeError(
"Running under trio requires the 'trio' package to be installed."
"Running with trio requires installation of 'httpcore[trio]'."
)

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."
"Running with asyncio requires installation of 'httpcore[asyncio]'."
)

self._anyio_shield = anyio.CancelScope(shield=True)
Expand Down
10 changes: 8 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,8 @@ classifiers = [
"Topic :: Internet :: WWW/HTTP",
]
dependencies = [
"anyio>=3.0,<5.0",
"certifi",
"h11>=0.13,<0.15",
"sniffio==1.*",
]

[project.optional-dependencies]
Expand All @@ -42,6 +40,14 @@ http2 = [
socks = [
"socksio==1.*",
]
trio = [
"trio>=0.21.0,<0.22.0",
tomchristie marked this conversation as resolved.
Show resolved Hide resolved
"sniffio==1.*",
]
asyncio = [
"anyio>=3.0,<5.0",
"sniffio==1.*",
]

[project.urls]
Documentation = "https://www.encode.io/httpcore"
Expand Down
5 changes: 1 addition & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
-e .[http2,socks]

# Optionals
trio==0.21.0
-e .[asyncio,trio,http2,socks]

# Docs
mkdocs==1.4.2
Expand Down