Skip to content

Commit

Permalink
Merge pull request #10 from encode/master
Browse files Browse the repository at this point in the history
Sync Fork from Upstream Repo
  • Loading branch information
sthagen authored Feb 4, 2021
2 parents 47ac842 + 89fb0cb commit 4c49905
Show file tree
Hide file tree
Showing 29 changed files with 548 additions and 238 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ HTTPX is a fully featured HTTP client for Python 3, which provides sync and asyn

**Note**: _HTTPX should be considered in beta. We believe we've got the public API to
a stable point now, but would strongly recommend pinning your dependencies to the `0.16.*`
release, so that you're able to properly review [API changes between package updates](https://github.com/encode/httpx/blob/master/CHANGELOG.md). A 1.0 release is expected to be issued sometime in late 2020._
release, so that you're able to properly review [API changes between package updates](https://github.com/encode/httpx/blob/master/CHANGELOG.md). A 1.0 release is expected to be issued sometime in 2021._

---

Expand Down
90 changes: 61 additions & 29 deletions docs/advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,10 @@ with httpx.Client(proxies=proxies) as client:
r = client.get("http://example.com")
```

### Troubleshooting proxies

If you encounter issues when setting up proxies, please refer to our [Troubleshooting guide](troubleshooting.md#proxies).

## Timeout Configuration

HTTPX is careful to enforce timeouts everywhere by default.
Expand Down Expand Up @@ -967,46 +971,36 @@ sending of the requests.
### Usage

For some advanced configuration you might need to instantiate a transport
class directly, and pass it to the client instance. The `httpcore` package
provides a `local_address` configuration that is only available via this
low-level API.
class directly, and pass it to the client instance. One example is the
`local_address` configuration which is only available via this low-level API.

```pycon
>>> import httpx, httpcore
>>> ssl_context = httpx.create_ssl_context()
>>> transport = httpcore.SyncConnectionPool(
... ssl_context=ssl_context,
... max_connections=100,
... max_keepalive_connections=20,
... keepalive_expiry=5.0,
... local_address="0.0.0.0"
... ) # Use the standard HTTPX defaults, but with an IPv4 only 'local_address'.
>>> import httpx
>>> transport = httpx.HTTPTransport(local_address="0.0.0.0")
>>> client = httpx.Client(transport=transport)
```

Similarly, `httpcore` provides a `uds` option for connecting via a Unix Domain Socket that is only available via this low-level API:
Connection retries are also available via this interface.

```python
>>> import httpx, httpcore
>>> ssl_context = httpx.create_ssl_context()
>>> transport = httpcore.SyncConnectionPool(
... ssl_context=ssl_context,
... max_connections=100,
... max_keepalive_connections=20,
... keepalive_expiry=5.0,
... uds="/var/run/docker.sock",
... ) # Connect to the Docker API via a Unix Socket.
```pycon
>>> import httpx
>>> transport = httpx.HTTPTransport(retries=1)
>>> client = httpx.Client(transport=transport)
```

Similarly, instantiating a transport directly provides a `uds` option for
connecting via a Unix Domain Socket that is only available via this low-level API:

```pycon
>>> import httpx
>>> # Connect to the Docker API via a Unix Socket.
>>> transport = httpx.HTTPTransport(uds="/var/run/docker.sock")
>>> client = httpx.Client(transport=transport)
>>> response = client.get("http://docker/info")
>>> response.json()
{"ID": "...", "Containers": 4, "Images": 74, ...}
```

Unlike the `httpx.Client()`, the lower-level `httpcore` transport instances
do not include any default values for configuring aspects such as the
connection pooling details, so you'll need to provide more explicit
configuration when using this API.

### urllib3 transport

This [public gist](https://gist.github.com/florimondmanca/d56764d78d748eb9f73165da388e546e) provides a transport that uses the excellent [`urllib3` library](https://urllib3.readthedocs.io/en/latest/), and can be used with the sync `Client`...
Expand Down Expand Up @@ -1058,6 +1052,31 @@ Which we can use in the same way:
{"text": "Hello, world!"}
```

### Mock transports

During testing it can often be useful to be able to mock out a transport,
and return pre-determined responses, rather than making actual network requests.

The `httpx.MockTransport` class accepts a handler function, which can be used
to map requests onto pre-determined responses:

```python
def handler(request):
return httpx.Response(200, json={"text": "Hello, world!"})


# Switch to a mock transport, if the TESTING environment variable is set.
if os.environ['TESTING'].upper() == "TRUE":
transport = httpx.MockTransport(handler)
else:
transport = httpx.HTTPTransport()

client = httpx.Client(transport=transport)
```

For more advanced use-cases you might want to take a look at either [the third-party
mocking library, RESPX](https://lundberg.github.io/respx/), or the [pytest-httpx library](https://github.com/Colin-b/pytest_httpx).

### Mounting transports

You can also mount transports against given schemes or domains, to control
Expand Down Expand Up @@ -1092,12 +1111,25 @@ client = httpx.Client(mounts=mounts)

A couple of other sketches of how you might take advantage of mounted transports...

Disabling HTTP/2 on a single given domain...

```python
mounts = {
"all://": httpx.HTTPTransport(http2=True),
"all://*example.org": httpx.HTTPTransport()
}
client = httpx.Client(mounts=mounts)
```

Mocking requests to a given domain:

```python
# All requests to "example.org" should be mocked out.
# Other requests occur as usual.
mounts = {"all://example.org": MockTransport()}
def handler(request):
return httpx.Response(200, json={"text": "Hello, World!"})

mounts = {"all://example.org": httpx.MockTransport(handler)}
client = httpx.Client(mounts=mounts)
```

Expand Down
34 changes: 34 additions & 0 deletions docs/async.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,19 @@ async def upload_bytes():
await client.post(url, data=upload_bytes())
```

### Explicit transport instances

When instantiating a transport instance directly, you need to use `httpx.AsyncHTTPTransport`.

For instance:

```pycon
>>> import httpx
>>> transport = httpx.AsyncHTTPTransport(retries=1)
>>> async with httpx.AsyncClient(transport=transport) as client:
>>> ...
```

## Supported async environments

HTTPX supports either `asyncio` or `trio` as an async environment.
Expand Down Expand Up @@ -156,6 +169,27 @@ trio.run(main)
!!! important
The `trio` package must be installed to use the Trio backend.


### [Curio](https://github.com/dabeaz/curio)

Curio is a [coroutine-based library](https://curio.readthedocs.io/en/latest/tutorial.html)
for concurrent Python systems programming.

```python
import httpx
import curio

async def main():
async with httpx.AsyncClient() as client:
response = await client.get('https://www.example.com/')
print(response)

curio.run(main)
```

!!! important
The `curio` package must be installed to use the Curio backend.

## Calling into Python Web Apps

Just as `httpx.Client` allows you to call directly into WSGI web applications,
Expand Down
8 changes: 8 additions & 0 deletions docs/compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,11 @@ while request is not None:
response = client.send(request, allow_redirects=False)
request = response.next_request
```

## Event Hooks

`requests` allows event hooks to mutate `Request` and `Response` objects. See [examples](https://requests.readthedocs.io/en/master/user/advanced/#event-hooks) given in the documentation for `requests`.

In HTTPX, event hooks may access properties of requests and responses, but event hook callbacks cannot mutate the original request/response.

If you are looking for more control, consider checking out [Custom Transports](advanced.md#custom-transports).
2 changes: 1 addition & 1 deletion docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ To run the documentation site locally (useful for previewing changes), use:
$ scripts/docs
```

## Resolving Build / Travis Failures
## Resolving Build / CI Failures

Once you've submitted your pull request, the test suite will automatically run, and the results will show up in GitHub.
If the test suite fails, you'll want to click through to the "Details" link, and try to identify why the test suite failed.
Expand Down
4 changes: 2 additions & 2 deletions docs/exceptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ while issuing an HTTP request. These exceptions include a `.request` attribute.
try:
response = httpx.get("https://www.example.com/")
except httpx.RequestError as exc:
print(f"An error occured while requesting {exc.request.url!r}.")
print(f"An error occurred while requesting {exc.request.url!r}.")
```

The `HTTPStatusError` class is raised by `response.raise_for_status()` on 4xx and 5xx responses.
Expand Down Expand Up @@ -45,7 +45,7 @@ try:
response = httpx.get("https://www.example.com/")
response.raise_for_status()
except httpx.RequestError as exc:
print(f"An error occured while requesting {exc.request.url!r}.")
print(f"An error occurred while requesting {exc.request.url!r}.")
except httpx.HTTPStatusError as exc:
print(f"Error response {exc.response.status_code} while requesting {exc.request.url!r}.")
```
Expand Down
2 changes: 1 addition & 1 deletion docs/http2.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ the optional HTTP/2 dependencies...
$ pip install httpx[http2]
```

And then then instantiating a client with HTTP/2 support enabled:
And then instantiating a client with HTTP/2 support enabled:

```python
client = httpx.AsyncClient(http2=True)
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ HTTPX is a fully featured HTTP client for Python 3, which provides sync and asyn

We believe we've got the public API to a stable point now, but would strongly recommend pinning your dependencies to the `0.16.*` release, so that you're able to properly review [API changes between package updates](https://github.com/encode/httpx/blob/master/CHANGELOG.md).

A 1.0 release is expected to be issued sometime in late 2020.
A 1.0 release is expected to be issued sometime in 2021.

---

Expand Down
61 changes: 61 additions & 0 deletions docs/troubleshooting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Troubleshooting

This page lists some common problems or issues you could encounter while developing with HTTPX, as well as possible solutions.

## Proxies

---

### "`The handshake operation timed out`" on HTTPS requests when using a proxy

**Description**: When using a proxy and making an HTTPS request, you see an exception looking like this:

```console
httpx.ProxyError: _ssl.c:1091: The handshake operation timed out
```

**Similar issues**: [encode/httpx#1412](https://github.com/encode/httpx/issues/1412), [encode/httpx#1433](https://github.com/encode/httpx/issues/1433)

**Resolution**: it is likely that you've set up your proxies like this...

```python
proxies = {
"http": "http://myproxy.org",
"https": "https://myproxy.org",
}
```

Using this setup, you're telling HTTPX to connect to the proxy using HTTP for HTTP requests, and using HTTPS for HTTPS requests.

But if you get the error above, it is likely that your proxy doesn't support connecting via HTTPS. Don't worry: that's a [common gotcha](advanced.md#example).

Change the scheme of your HTTPS proxy to `http://...` instead of `https://...`:

```python
proxies = {
"http": "http://myproxy.org",
"https": "http://myproxy.org",
}
```

This can be simplified to:

```python
proxies = "http://myproxy.org"
```

For more information, see [Proxies: FORWARD vs TUNNEL](advanced.md#forward-vs-tunnel).

---

### Error when making requests to an HTTPS proxy

**Description**: your proxy _does_ support connecting via HTTPS, but you are seeing errors along the lines of...

```console
httpx.ProxyError: [SSL: PRE_MAC_LENGTH_TOO_LONG] invalid alert (_ssl.c:1091)
```

**Similar issues**: [encode/httpx#1424](https://github.com/encode/httpx/issues/1424).

**Resolution**: HTTPX does not properly support HTTPS proxies at this time. If that's something you're interested in having, please see [encode/httpx#1434](https://github.com/encode/httpx/issues/1434) and consider lending a hand there.
5 changes: 5 additions & 0 deletions httpx/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
from ._models import URL, Cookies, Headers, QueryParams, Request, Response
from ._status_codes import StatusCode, codes
from ._transports.asgi import ASGITransport
from ._transports.default import AsyncHTTPTransport, HTTPTransport
from ._transports.mock import MockTransport
from ._transports.wsgi import WSGITransport

__all__ = [
Expand All @@ -44,6 +46,7 @@
"__version__",
"ASGITransport",
"AsyncClient",
"AsyncHTTPTransport",
"Auth",
"BasicAuth",
"Client",
Expand All @@ -62,9 +65,11 @@
"Headers",
"HTTPError",
"HTTPStatusError",
"HTTPTransport",
"InvalidURL",
"Limits",
"LocalProtocolError",
"MockTransport",
"NetworkError",
"options",
"patch",
Expand Down
2 changes: 1 addition & 1 deletion httpx/_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def request(
`HEAD`, `POST`, `PUT`, `PATCH`, or `DELETE`.
* **url** - URL for the new `Request` object.
* **params** - *(optional)* Query parameters to include in the URL, as a
string, dictionary, or list of two-tuples.
string, dictionary, or sequence of two-tuples.
* **content** - *(optional)* Binary content to include in the body of the
request, as bytes or a byte iterator.
* **data** - *(optional)* Form data to include in the body of the request,
Expand Down
Loading

0 comments on commit 4c49905

Please sign in to comment.