Renaming -> httpx (#129)

* Renaming -> httpx

* Renaming to httpx
This commit is contained in:
Tom Christie 2019-07-19 15:15:16 +01:00 committed by GitHub
parent 0e8dae4815
commit 2d09d5b36c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 307 additions and 295 deletions

View File

@ -1,16 +1,16 @@
# HTTP3 # HTTPX
<a href="https://travis-ci.org/encode/http3"> <a href="https://travis-ci.org/encode/httpx">
<img src="https://travis-ci.org/encode/http3.svg?branch=master" alt="Build Status"> <img src="https://travis-ci.org/encode/httpx.svg?branch=master" alt="Build Status">
</a> </a>
<a href="https://codecov.io/gh/encode/http3"> <a href="https://codecov.io/gh/encode/httpx">
<img src="https://codecov.io/gh/encode/http3/branch/master/graph/badge.svg" alt="Coverage"> <img src="https://codecov.io/gh/encode/httpx/branch/master/graph/badge.svg" alt="Coverage">
</a> </a>
<a href="https://pypi.org/project/http3/"> <a href="https://pypi.org/project/httpx/">
<img src="https://badge.fury.io/py/http3.svg" alt="Package version"> <img src="https://badge.fury.io/py/httpx.svg" alt="Package version">
</a> </a>
HTTP3 is a next-generation HTTP client for Python 3. HTTPX is a next-generation HTTP client for Python 3.
**Note**: *This project should be considered as an "alpha" release. It is substantially API complete, but there are still some areas that need more work.* **Note**: *This project should be considered as an "alpha" release. It is substantially API complete, but there are still some areas that need more work.*
@ -19,8 +19,8 @@ HTTP3 is a next-generation HTTP client for Python 3.
Let's get started... Let's get started...
```python ```python
>>> import http3 >>> import httpx
>>> r = http3.get('https://www.example.org/') >>> r = httpx.get('https://www.example.org/')
>>> r >>> r
<Response [200 OK]> <Response [200 OK]>
>>> r.status_code >>> r.status_code
@ -35,13 +35,13 @@ Let's get started...
## Features ## Features
HTTP3 builds on the well-established usability of `requests`, and gives you: HTTPX builds on the well-established usability of `requests`, and gives you:
* A requests-compatible API. * A requests-compatible API.
* HTTP/2 and HTTP/1.1 support. * HTTP/2 and HTTP/1.1 support.
* Support for [issuing HTTP requests in parallel](https://www.encode.io/http3/parallel/). *(Coming soon)* * Support for [issuing HTTP requests in parallel](https://www.encode.io/httpx/parallel/). *(Coming soon)*
* Standard synchronous interface, but [with `async`/`await` support if you need it](https://www.encode.io/http3/async/). * Standard synchronous interface, but [with `async`/`await` support if you need it](https://www.encode.io/httpx/async/).
* Ability to [make requests directly to WSGI or ASGI applications](https://www.encode.io/http3/advanced/#calling-into-python-web-apps). * Ability to [make requests directly to WSGI or ASGI applications](https://www.encode.io/httpx/advanced/#calling-into-python-web-apps).
* Strict timeouts everywhere. * Strict timeouts everywhere.
* Fully type annotated. * Fully type annotated.
* 100% test coverage. * 100% test coverage.
@ -69,26 +69,26 @@ Plus all the standard features of `requests`...
Install with pip: Install with pip:
```shell ```shell
$ pip install http3 $ pip install httpx
``` ```
HTTP3 requires Python 3.6+ httpx requires Python 3.6+
## Documentation ## Documentation
Project documentation is available at [www.encode.io/http3/](https://www.encode.io/http3/). Project documentation is available at [www.encode.io/httpx/](https://www.encode.io/httpx/).
For a run-through of all the basics, head over to the [QuickStart](https://www.encode.io/http3/quickstart/). For a run-through of all the basics, head over to the [QuickStart](https://www.encode.io/httpx/quickstart/).
For more advanced topics, see the [Advanced Usage](https://www.encode.io/http3/advanced/) section, or For more advanced topics, see the [Advanced Usage](https://www.encode.io/httpx/advanced/) section, or
the specific topics on making [Parallel Requests](https://www.encode.io/http3/parallel/) or using the the specific topics on making [Parallel Requests](https://www.encode.io/httpx/parallel/) or using the
[Async Client](https://www.encode.io/http3/async/). [Async Client](https://www.encode.io/httpx/async/).
The [Developer Interface](https://www.encode.io/http3/api/) provides a comprehensive API reference. The [Developer Interface](https://www.encode.io/httpx/api/) provides a comprehensive API reference.
## Dependencies ## Dependencies
The HTTP3 project relies on these excellent libraries: The httpx project relies on these excellent libraries:
* `h2` - HTTP/2 support. * `h2` - HTTP/2 support.
* `h11` - HTTP/1.1 support. * `h11` - HTTP/1.1 support.
@ -103,4 +103,4 @@ much of this work follows, as well as to `urllib3` for plenty of design
inspiration around the lower level networking details. inspiration around the lower level networking details.
<p align="center">&mdash; ⭐️ &mdash;</p> <p align="center">&mdash; ⭐️ &mdash;</p>
<p align="center"><i>HTTP3 is <a href="https://github.com/encode/http3/blob/master/LICENSE.md">BSD licensed</a> code. Designed & built in Brighton, England.</i></p> <p align="center"><i>httpx is <a href="https://github.com/encode/httpx/blob/master/LICENSE.md">BSD licensed</a> code. Designed & built in Brighton, England.</i></p>

View File

@ -7,7 +7,7 @@ will provide cookie persistence, and allows you to apply configuration across
all outgoing requests. all outgoing requests.
```python ```python
>>> client = http3.Client() >>> client = httpx.Client()
>>> r = client.get('https://example.org/') >>> r = client.get('https://example.org/')
>>> r >>> r
<Response [200 OK]> <Response [200 OK]>
@ -15,19 +15,19 @@ all outgoing requests.
## Calling into Python Web Apps ## Calling into Python Web Apps
You can configure an `http3` client to call directly into a Python web You can configure an `httpx` client to call directly into a Python web
application, using either the WSGI or ASGI protocol. application, using either the WSGI or ASGI protocol.
This is particularly useful for two main use-cases: This is particularly useful for two main use-cases:
* Using `http3` as a client, inside test cases. * Using `httpx` as a client, inside test cases.
* Mocking out external services, during tests or in dev/staging environments. * Mocking out external services, during tests or in dev/staging environments.
Here's an example of integrating against a Flask application: Here's an example of integrating against a Flask application:
```python ```python
from flask import Flask from flask import Flask
import http3 import httpx
app = Flask(__name__) app = Flask(__name__)
@ -36,7 +36,7 @@ app = Flask(__name__)
def hello(): def hello():
return "Hello World!" return "Hello World!"
client = http3.Client(app=app) client = httpx.Client(app=app)
r = client.get('http://example/') r = client.get('http://example/')
assert r.status_code == 200 assert r.status_code == 200
assert r.text == "Hello World!" assert r.text == "Hello World!"

View File

@ -16,7 +16,7 @@
*An HTTP client, with connection pooling, redirects, cookie persistence, etc.* *An HTTP client, with connection pooling, redirects, cookie persistence, etc.*
```python ```python
>>> client = http3.Client() >>> client = httpx.Client()
>>> response = client.get('https://example.org') >>> response = client.get('https://example.org')
``` ```
@ -63,7 +63,7 @@
what gets sent over the wire.* what gets sent over the wire.*
```python ```python
>>> request = http3.Request("GET", "https://example.org", headers={'host': 'example.org'}) >>> request = httpx.Request("GET", "https://example.org", headers={'host': 'example.org'})
>>> response = client.send(request) >>> response = client.send(request)
``` ```

View File

@ -1,6 +1,6 @@
# Async Client # Async Client
HTTP3 offers a standard synchronous API by default, but also gives you HTTPX offers a standard synchronous API by default, but also gives you
the option of an async client if you need it. the option of an async client if you need it.
Async is a concurrency model that is far more efficient than multi-threading, Async is a concurrency model that is far more efficient than multi-threading,
@ -15,7 +15,7 @@ async client for sending outgoing HTTP requests.
To make asynchronous requests, you'll need an `AsyncClient`. To make asynchronous requests, you'll need an `AsyncClient`.
```python ```python
>>> client = http3.AsyncClient() >>> client = httpx.AsyncClient()
>>> r = await client.get('https://www.example.com/') >>> r = await client.get('https://www.example.com/')
``` ```
@ -25,7 +25,7 @@ If you're using streaming responses then there are a few bits of API that
use async methods: use async methods:
```python ```python
>>> client = http3.AsyncClient() >>> client = httpx.AsyncClient()
>>> r = await client.get('https://www.example.com/', stream=True) >>> r = await client.get('https://www.example.com/', stream=True)
>>> try: >>> try:
>>> async for chunk in r.stream(): >>> async for chunk in r.stream():
@ -44,7 +44,7 @@ The async response methods are:
If you're making parallel requests, then you'll also need to use an async API: If you're making parallel requests, then you'll also need to use an async API:
```python ```python
>>> client = http3.AsyncClient() >>> client = httpx.AsyncClient()
>>> async with client.parallel() as parallel: >>> async with client.parallel() as parallel:
>>> pending_one = parallel.get('https://example.com/1') >>> pending_one = parallel.get('https://example.com/1')
>>> pending_two = parallel.get('https://example.com/2') >>> pending_two = parallel.get('https://example.com/2')

View File

@ -1,6 +1,6 @@
# Requests Compatibility Guide # Requests Compatibility Guide
HTTP3 aims to be compatible with the `requests` API wherever possible. HTTPX aims to be compatible with the `requests` API wherever possible.
This documentation outlines places where the API differs... This documentation outlines places where the API differs...
@ -10,7 +10,7 @@ Pretty much all the API mentioned in the `requests` QuickStart should be identic
to the API in our own documentation. The following exceptions apply: to the API in our own documentation. The following exceptions apply:
* `Response.url` - Returns a `URL` instance, rather than a string. Use `str(response.url)` if you need a string instance. * `Response.url` - Returns a `URL` instance, rather than a string. Use `str(response.url)` if you need a string instance.
* `http3.codes` - In our documentation we prefer the uppercased versions, such as `codes.NOT_FOUND`, * `httpx.codes` - In our documentation we prefer the uppercased versions, such as `codes.NOT_FOUND`,
but also provide lower-cased versions for API compatibility with `requests`. but also provide lower-cased versions for API compatibility with `requests`.
* `stream=True`. - Streaming responses provide the `.stream()` and `.raw()` byte iterator interfaces, rather than the `.iter_content()` method and the `.raw` socket interface. * `stream=True`. - Streaming responses provide the `.stream()` and `.raw()` byte iterator interfaces, rather than the `.iter_content()` method and the `.raw` socket interface.

BIN
docs/img/logo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,5 +1,15 @@
<h1 style="margin: 0">HTTP3</h1> <p align="center" style="margin: 0 0 10px">
<img width="350" height="208" src="http://127.0.0.1:8000/img/logo.jpg" alt='HTTPX'>
</p>
<h1 align="center" style="font-size: 3rem; margin: -15px 0">
HTTPX
</h1>
---
<div align="center">
<p>
<a href="https://travis-ci.org/encode/http3"> <a href="https://travis-ci.org/encode/http3">
<img src="https://travis-ci.org/encode/http3.svg?branch=master" alt="Build Status"> <img src="https://travis-ci.org/encode/http3.svg?branch=master" alt="Build Status">
</a> </a>
@ -9,8 +19,10 @@
<a href="https://pypi.org/project/http3/"> <a href="https://pypi.org/project/http3/">
<img src="https://badge.fury.io/py/http3.svg" alt="Package version"> <img src="https://badge.fury.io/py/http3.svg" alt="Package version">
</a> </a>
</p>
HTTP3 is a next-generation HTTP client for Python 3. <em>A next-generation HTTP client for Python.</em>
</div>
!!! warning !!! warning
This project should be considered as an "alpha" release. It is substantially This project should be considered as an "alpha" release. It is substantially
@ -21,8 +33,8 @@ HTTP3 is a next-generation HTTP client for Python 3.
Let's get started... Let's get started...
```python ```python
>>> import http3 >>> import httpx
>>> r = http3.get('https://www.example.org/') >>> r = httpx.get('https://www.example.org/')
>>> r >>> r
<Response [200 OK]> <Response [200 OK]>
>>> r.status_code >>> r.status_code
@ -37,7 +49,7 @@ Let's get started...
## Features ## Features
HTTP3 builds on the well-established usability of `requests`, and gives you: HTTPX builds on the well-established usability of `requests`, and gives you:
* A requests-compatible API. * A requests-compatible API.
* HTTP/2 and HTTP/1.1 support. * HTTP/2 and HTTP/1.1 support.
@ -78,7 +90,7 @@ The [Developer Interface](api.md) provides a comprehensive API reference.
## Dependencies ## Dependencies
The HTTP3 project relies on these excellent libraries: The HTTPX project relies on these excellent libraries:
* `h2` - HTTP/2 support. * `h2` - HTTP/2 support.
* `h11` - HTTP/1.1 support. * `h11` - HTTP/1.1 support.
@ -97,7 +109,7 @@ inspiration around the lower level networking details.
Install with pip: Install with pip:
```shell ```shell
$ pip install http3 $ pip install httpx
``` ```
HTTP3 requires Python 3.6+ HTTPX requires Python 3.6+

View File

@ -2,10 +2,10 @@
!!! warning !!! warning
This page documents some proposed functionality that is not yet released. This page documents some proposed functionality that is not yet released.
See [pull request #52](https://github.com/encode/http3/pull/52) for the See [pull request #52](https://github.com/encode/httpx/pull/52) for the
first-pass of an implementation. first-pass of an implementation.
HTTP3 allows you to make HTTP requests in parallel in a highly efficient way, HTTPX allows you to make HTTP requests in parallel in a highly efficient way,
using async under the hood, while still presenting a standard threaded interface. using async under the hood, while still presenting a standard threaded interface.
This has the huge benefit of allowing you to efficiently make parallel HTTP This has the huge benefit of allowing you to efficiently make parallel HTTP
@ -16,7 +16,7 @@ requests without having to switch out to using async all the way through.
Let's make two outgoing HTTP requests in parallel: Let's make two outgoing HTTP requests in parallel:
```python ```python
>>> with http3.parallel() as parallel: >>> with httpx.parallel() as parallel:
>>> pending_one = parallel.get('https://example.com/1') >>> pending_one = parallel.get('https://example.com/1')
>>> pending_two = parallel.get('https://example.com/2') >>> pending_two = parallel.get('https://example.com/2')
>>> response_one = pending_one.get_response() >>> response_one = pending_one.get_response()
@ -28,7 +28,7 @@ responses sequentially, but rather deal with each response that comes back
as soon as it's available: as soon as it's available:
```python ```python
>>> with http3.parallel() as parallel: >>> with httpx.parallel() as parallel:
>>> for counter in range(1, 10): >>> for counter in range(1, 10):
>>> parallel.get(f'https://example.com/{counter}') >>> parallel.get(f'https://example.com/{counter}')
>>> while parallel.has_pending_responses: >>> while parallel.has_pending_responses:
@ -49,7 +49,7 @@ control the authentication or dispatch behaviour for all requests within the
block. block.
```python ```python
>>> client = http3.Client() >>> client = httpx.Client()
>>> with client.parallel() as parallel: >>> with client.parallel() as parallel:
>>> ... >>> ...
``` ```
@ -60,7 +60,7 @@ If you're working within an async framework, then you'll want to use a fully
async API for making requests. async API for making requests.
```python ```python
>>> client = http3.AsyncClient() >>> client = httpx.AsyncClient()
>>> async with client.parallel() as parallel: >>> async with client.parallel() as parallel:
>>> pending_one = await parallel.get('https://example.com/1') >>> pending_one = await parallel.get('https://example.com/1')
>>> pending_two = await parallel.get('https://example.com/2') >>> pending_two = await parallel.get('https://example.com/2')

View File

@ -2,19 +2,19 @@
!!! note !!! note
This page closely follows the layout of the `requests` QuickStart documentation. This page closely follows the layout of the `requests` QuickStart documentation.
The `http3` library is designed to be API compatible with `requests` wherever The `httpx` library is designed to be API compatible with `requests` wherever
possible. possible.
First start by importing HTTP3: First start by importing HTTPX:
``` ```
>>> import http3 >>> import httpx
``` ```
Now, lets try to get a webpage. Now, lets try to get a webpage.
```python ```python
>>> r = http3.get('https://httpbin.org/get') >>> r = httpx.get('https://httpbin.org/get')
>>> r >>> r
<Response [200 OK]> <Response [200 OK]>
``` ```
@ -22,16 +22,16 @@ Now, lets try to get a webpage.
Similarly, to make an HTTP POST request: Similarly, to make an HTTP POST request:
```python ```python
>>> r = http3.post('https://httpbin.org/post', data={'key': 'value'}) >>> r = httpx.post('https://httpbin.org/post', data={'key': 'value'})
``` ```
The PUT, DELETE, HEAD, and OPTIONS requests all follow the same style: The PUT, DELETE, HEAD, and OPTIONS requests all follow the same style:
```python ```python
>>> r = http3.put('https://httpbin.org/put', data={'key': 'value'}) >>> r = httpx.put('https://httpbin.org/put', data={'key': 'value'})
>>> r = http3.delete('https://httpbin.org/delete') >>> r = httpx.delete('https://httpbin.org/delete')
>>> r = http3.head('https://httpbin.org/get') >>> r = httpx.head('https://httpbin.org/get')
>>> r = http3.options('https://httpbin.org/get') >>> r = httpx.options('https://httpbin.org/get')
``` ```
## Passing Parameters in URLs ## Passing Parameters in URLs
@ -40,7 +40,7 @@ To include URL query parameters in the request, use the `params` keyword:
```python ```python
>>> params = {'key1': 'value1', 'key2': 'value2'} >>> params = {'key1': 'value1', 'key2': 'value2'}
>>> r = http3.get('https://httpbin.org/get', params=params) >>> r = httpx.get('https://httpbin.org/get', params=params)
``` ```
To see how the values get encoding into the URL string, we can inspect the To see how the values get encoding into the URL string, we can inspect the
@ -55,17 +55,17 @@ You can also pass a list of items as a value:
```python ```python
>>> params = {'key1': 'value1', 'key2': ['value2', 'value3']} >>> params = {'key1': 'value1', 'key2': ['value2', 'value3']}
>>> r = http3.get('https://httpbin.org/get', params=params) >>> r = httpx.get('https://httpbin.org/get', params=params)
>>> r.url >>> r.url
URL('https://httpbin.org/get?key1=value1&key2=value2&key2=value3') URL('https://httpbin.org/get?key1=value1&key2=value2&key2=value3')
``` ```
## Response Content ## Response Content
HTTP3 will automatically handle decoding the response content into unicode text. HTTPX will automatically handle decoding the response content into unicode text.
```python ```python
>>> r = http3.get('https://www.example.org/') >>> r = httpx.get('https://www.example.org/')
>>> r.text >>> r.text
'<!doctype html>\n<html>\n<head>\n<title>Example Domain</title>...' '<!doctype html>\n<html>\n<head>\n<title>Example Domain</title>...'
``` ```
@ -110,7 +110,7 @@ For example, to create an image from binary data returned by a request, you can
Often Web API responses will be encoded as JSON. Often Web API responses will be encoded as JSON.
```python ```python
>>> r = http3.get('https://api.github.com/events') >>> r = httpx.get('https://api.github.com/events')
>>> r.json() >>> r.json()
[{u'repository': {u'open_issues': 0, u'url': 'https://github.com/...' ... }}] [{u'repository': {u'open_issues': 0, u'url': 'https://github.com/...' ... }}]
``` ```
@ -122,7 +122,7 @@ To include additional headers in the outgoing request, use the `headers` keyword
```python ```python
>>> url = 'http://httpbin.org/headers' >>> url = 'http://httpbin.org/headers'
>>> headers = {'user-agent': 'my-app/0.0.1'} >>> headers = {'user-agent': 'my-app/0.0.1'}
>>> r = http3.get(url, headers=headers) >>> r = httpx.get(url, headers=headers)
``` ```
## Sending Form Encoded Data ## Sending Form Encoded Data
@ -133,7 +133,7 @@ which is used for HTML forms.
```python ```python
>>> data = {'key1': 'value1', 'key2': 'value2'} >>> data = {'key1': 'value1', 'key2': 'value2'}
>>> r = http3.post("https://httpbin.org/post", data=data) >>> r = httpx.post("https://httpbin.org/post", data=data)
>>> print(r.text) >>> print(r.text)
{ {
... ...
@ -149,7 +149,7 @@ Form encoded data can also include multiple values form a given key.
```python ```python
>>> data = {'key1': ['value1', 'value2']} >>> data = {'key1': ['value1', 'value2']}
>>> r = http3.post("https://httpbin.org/post", data=data) >>> r = httpx.post("https://httpbin.org/post", data=data)
>>> print(r.text) >>> print(r.text)
{ {
... ...
@ -169,7 +169,7 @@ You can also upload files, using HTTP multipart encoding:
```python ```python
>>> files = {'upload-file': open('report.xls', 'rb')} >>> files = {'upload-file': open('report.xls', 'rb')}
>>> r = http3.post("https://httpbin.org/post", files=files) >>> r = httpx.post("https://httpbin.org/post", files=files)
>>> print(r.text) >>> print(r.text)
{ {
... ...
@ -185,7 +185,7 @@ of items for the file value:
```python ```python
>>> files = {'upload-file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel')} >>> files = {'upload-file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel')}
>>> r = http3.post("https://httpbin.org/post", files=files) >>> r = httpx.post("https://httpbin.org/post", files=files)
>>> print(r.text) >>> print(r.text)
{ {
... ...
@ -203,7 +203,7 @@ For more complicated data structures you'll often want to use JSON encoding inst
```python ```python
>>> data = {'integer': 123, 'boolean': True, 'list': ['a', 'b', 'c']} >>> data = {'integer': 123, 'boolean': True, 'list': ['a', 'b', 'c']}
>>> r = http3.post("https://httpbin.org/post", json=data) >>> r = httpx.post("https://httpbin.org/post", json=data)
>>> print(r.text) >>> print(r.text)
{ {
... ...
@ -233,29 +233,29 @@ binary data.
We can inspect the HTTP status code of the response: We can inspect the HTTP status code of the response:
```python ```python
>>> r = http3.get('https://httpbin.org/get') >>> r = httpx.get('https://httpbin.org/get')
>>> r.status_code >>> r.status_code
200 200
``` ```
HTTP3 also includes an easy shortcut for accessing status codes by their text phrase. HTTPX also includes an easy shortcut for accessing status codes by their text phrase.
```python ```python
>>> r.status_code == http3.codes.OK >>> r.status_code == httpx.codes.OK
True True
``` ```
We can raise an exception for any Client or Server error responses (4xx or 5xx status codes): We can raise an exception for any Client or Server error responses (4xx or 5xx status codes):
```python ```python
>>> not_found = http3.get('https://httpbin.org/status/404') >>> not_found = httpx.get('https://httpbin.org/status/404')
>>> not_found.status_code >>> not_found.status_code
404 404
>>> not_found.raise_for_status() >>> not_found.raise_for_status()
Traceback (most recent call last): Traceback (most recent call last):
File "/Users/tomchristie/GitHub/encode/httpcore/http3/models.py", line 776, in raise_for_status File "/Users/tomchristie/GitHub/encode/httpcore/httpx/models.py", line 776, in raise_for_status
raise HttpError(message) raise HttpError(message)
http3.exceptions.HttpError: 404 Not Found httpx.exceptions.HttpError: 404 Not Found
``` ```
Any successful response codes will simply return `None` rather than raising an exception. Any successful response codes will simply return `None` rather than raising an exception.
@ -301,7 +301,7 @@ value, as per [RFC 7230](https://tools.ietf.org/html/rfc7230#section-3.2):
Any cookies that are set on the response can be easily accessed: Any cookies that are set on the response can be easily accessed:
```python ```python
>>> r = http3.get('http://httpbin.org/cookies/set?chocolate=chip', allow_redirects=False) >>> r = httpx.get('http://httpbin.org/cookies/set?chocolate=chip', allow_redirects=False)
>>> r.cookies['chocolate'] >>> r.cookies['chocolate']
'chip' 'chip'
``` ```
@ -310,7 +310,7 @@ To include cookies in an outgoing request, use the `cookies` parameter:
```python ```python
>>> cookies = {"peanut": "butter"} >>> cookies = {"peanut": "butter"}
>>> r = http3.get('http://httpbin.org/cookies', cookies=cookies) >>> r = httpx.get('http://httpbin.org/cookies', cookies=cookies)
>>> r.json() >>> r.json()
{'cookies': {'peanut': 'butter'}} {'cookies': {'peanut': 'butter'}}
``` ```
@ -319,17 +319,17 @@ Cookies are returned in a `Cookies` instance, which is a dict-like data structur
with additional API for accessing cookies by their domain or path. with additional API for accessing cookies by their domain or path.
```python ```python
>>> cookies = http3.Cookies() >>> cookies = httpx.Cookies()
>>> cookies.set('cookie_on_domain', 'hello, there!', domain='httpbin.org') >>> cookies.set('cookie_on_domain', 'hello, there!', domain='httpbin.org')
>>> cookies.set('cookie_off_domain', 'nope.', domain='example.org') >>> cookies.set('cookie_off_domain', 'nope.', domain='example.org')
>>> r = http3.get('http://httpbin.org/cookies', cookies=cookies) >>> r = httpx.get('http://httpbin.org/cookies', cookies=cookies)
>>> r.json() >>> r.json()
{'cookies': {'cookie_on_domain': 'hello, there!'}} {'cookies': {'cookie_on_domain': 'hello, there!'}}
``` ```
## Redirection and History ## Redirection and History
By default HTTP3 will follow redirects for anything except `HEAD` requests. By default HTTPX will follow redirects for anything except `HEAD` requests.
The `history` property of the response can be used to inspect any followed redirects. The `history` property of the response can be used to inspect any followed redirects.
It contains a list of all any redirect responses that were followed, in the order It contains a list of all any redirect responses that were followed, in the order
@ -338,7 +338,7 @@ in which they were made.
For example, GitHub redirects all HTTP requests to HTTPS. For example, GitHub redirects all HTTP requests to HTTPS.
```python ```python
>>> r = http3.get('http://github.com/') >>> r = httpx.get('http://github.com/')
>>> r.url >>> r.url
URL('https://github.com/') URL('https://github.com/')
>>> r.status_code >>> r.status_code
@ -350,7 +350,7 @@ URL('https://github.com/')
You can modify the default redirection handling with the allow_redirects parameter: You can modify the default redirection handling with the allow_redirects parameter:
```python ```python
>>> r = http3.get('http://github.com/', allow_redirects=False) >>> r = httpx.get('http://github.com/', allow_redirects=False)
>>> r.status_code >>> r.status_code
301 301
>>> r.history >>> r.history
@ -360,7 +360,7 @@ You can modify the default redirection handling with the allow_redirects paramet
If youre making a `HEAD` request, you can use this to enable redirection: If youre making a `HEAD` request, you can use this to enable redirection:
```python ```python
>>> r = http3.head('http://github.com/', allow_redirects=True) >>> r = httpx.head('http://github.com/', allow_redirects=True)
>>> r.url >>> r.url
'https://github.com/' 'https://github.com/'
>>> r.history >>> r.history
@ -369,7 +369,7 @@ If youre making a `HEAD` request, you can use this to enable redirection:
## Timeouts ## Timeouts
HTTP3 defaults to including reasonable timeouts for all network operations, HTTPX defaults to including reasonable timeouts for all network operations,
meaning that if a connection is not properly established then it should always meaning that if a connection is not properly established then it should always
raise an error rather than hanging indefinitely. raise an error rather than hanging indefinitely.
@ -377,5 +377,5 @@ The default timeout for network inactivity is five seconds. You can modify the
value to be more or less strict: value to be more or less strict:
```python ```python
>>> http3.get('https://github.com/', timeout=0.001) >>> httpx.get('https://github.com/', timeout=0.001)
``` ```

View File

@ -1,3 +1,3 @@
__title__ = "http3" __title__ = "httpx"
__description__ = "A next generation HTTP client, for Python 3." __description__ = "A next generation HTTP client, for Python 3."
__version__ = "0.6.7" __version__ = "0.6.7"

View File

@ -12,7 +12,7 @@ VerifyTypes = typing.Union[str, bool]
TimeoutTypes = typing.Union[float, typing.Tuple[float, float, float], "TimeoutConfig"] TimeoutTypes = typing.Union[float, typing.Tuple[float, float, float], "TimeoutConfig"]
USER_AGENT = f"python-http3/{__version__}" USER_AGENT = f"python-httpx/{__version__}"
DEFAULT_CIPHERS = ":".join( DEFAULT_CIPHERS = ":".join(
[ [

View File

@ -15,7 +15,7 @@ class ASGIDispatch(AsyncDispatcher):
and will setup an appropriate dispatch class: and will setup an appropriate dispatch class:
``` ```
client = http3.Client(app=app) client = httpx.Client(app=app)
``` ```
Alternatively, you can setup the dispatch instance explicitly. Alternatively, you can setup the dispatch instance explicitly.
@ -23,12 +23,12 @@ class ASGIDispatch(AsyncDispatcher):
to the ASGIDispatch class: to the ASGIDispatch class:
``` ```
dispatch = http3.ASGIDispatch( dispatch = httpx.ASGIDispatch(
app=app, app=app,
root_path="/submount", root_path="/submount",
client=("1.2.3.4", 123) client=("1.2.3.4", 123)
) )
client = http3.Client(dispatch=dispatch) client = httpx.Client(dispatch=dispatch)
``` ```
""" """

View File

@ -15,7 +15,7 @@ class WSGIDispatch(Dispatcher):
and will setup an appropriate dispatch class: and will setup an appropriate dispatch class:
``` ```
client = http3.Client(app=app) client = httpx.Client(app=app)
``` ```
Alternatively, you can setup the dispatch instance explicitly. Alternatively, you can setup the dispatch instance explicitly.
@ -23,12 +23,12 @@ class WSGIDispatch(Dispatcher):
to the WSGIDispatch class: to the WSGIDispatch class:
``` ```
dispatch = http3.WSGIDispatch( dispatch = httpx.WSGIDispatch(
app=app, app=app,
script_name="/submount", script_name="/submount",
remote_addr="1.2.3.4" remote_addr="1.2.3.4"
) )
client = http3.Client(dispatch=dispatch) client = httpx.Client(dispatch=dispatch)
``` ```
""" """

View File

@ -1,11 +1,11 @@
site_name: HTTP3 site_name: HTTPX
site_description: The next generation HTTP client. site_description: A next-generation HTTP client for Python.
theme: theme:
name: 'material' name: 'material'
repo_name: encode/http3 repo_name: encode/httpx
repo_url: https://github.com/encode/http3 repo_url: https://github.com/encode/httpx
edit_uri: "" edit_uri: ""
nav: nav:

View File

@ -9,6 +9,6 @@ fi
if [ -d 'htmlcov' ] ; then if [ -d 'htmlcov' ] ; then
rm -r htmlcov rm -r htmlcov
fi fi
if [ -d 'http3.egg-info' ] ; then if [ -d 'httpx.egg-info' ] ; then
rm -r http3.egg-info rm -r httpx.egg-info
fi fi

View File

@ -7,10 +7,10 @@ fi
set -x set -x
${PREFIX}autoflake --in-place --recursive http3 tests setup.py ${PREFIX}autoflake --in-place --recursive httpx tests setup.py
${PREFIX}isort --multi-line=3 --trailing-comma --force-grid-wrap=0 --combine-as --line-width 88 --recursive --apply http3 tests setup.py ${PREFIX}isort --multi-line=3 --trailing-comma --force-grid-wrap=0 --combine-as --line-width 88 --recursive --apply httpx tests setup.py
${PREFIX}black http3 tests setup.py ${PREFIX}black httpx tests setup.py
${PREFIX}flake8 --max-line-length=88 --ignore=W503,E203 http3 tests setup.py ${PREFIX}flake8 --max-line-length=88 --ignore=W503,E203 httpx tests setup.py
${PREFIX}mypy http3 --ignore-missing-imports --disallow-untyped-defs ${PREFIX}mypy httpx --ignore-missing-imports --disallow-untyped-defs
scripts/clean scripts/clean

View File

@ -1,6 +1,6 @@
#!/bin/sh -e #!/bin/sh -e
export PACKAGE="http3" export PACKAGE="httpx"
export VERSION=`cat ${PACKAGE}/__version__.py | grep __version__ | sed "s/__version__ = //" | sed "s/'//g"` export VERSION=`cat ${PACKAGE}/__version__.py | grep __version__ | sed "s/__version__ = //" | sed "s/'//g"`
export PREFIX="" export PREFIX=""
if [ -d 'venv' ] ; then if [ -d 'venv' ] ; then

View File

@ -1,6 +1,6 @@
#!/bin/sh -e #!/bin/sh -e
export PACKAGE="http3" export PACKAGE="httpx"
export PREFIX="" export PREFIX=""
if [ -d 'venv' ] ; then if [ -d 'venv' ] ; then
export PREFIX="venv/bin/" export PREFIX="venv/bin/"

View File

@ -1,12 +1,12 @@
import pytest import pytest
import http3 import httpx
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_get(server): async def test_get(server):
url = "http://127.0.0.1:8000/" url = "http://127.0.0.1:8000/"
async with http3.AsyncClient() as client: async with httpx.AsyncClient() as client:
response = await client.get(url) response = await client.get(url)
assert response.status_code == 200 assert response.status_code == 200
assert response.text == "Hello, world!" assert response.text == "Hello, world!"
@ -18,7 +18,7 @@ async def test_get(server):
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_post(server): async def test_post(server):
url = "http://127.0.0.1:8000/" url = "http://127.0.0.1:8000/"
async with http3.AsyncClient() as client: async with httpx.AsyncClient() as client:
response = await client.post(url, data=b"Hello, world!") response = await client.post(url, data=b"Hello, world!")
assert response.status_code == 200 assert response.status_code == 200
@ -26,14 +26,14 @@ async def test_post(server):
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_post_json(server): async def test_post_json(server):
url = "http://127.0.0.1:8000/" url = "http://127.0.0.1:8000/"
async with http3.AsyncClient() as client: async with httpx.AsyncClient() as client:
response = await client.post(url, json={"text": "Hello, world!"}) response = await client.post(url, json={"text": "Hello, world!"})
assert response.status_code == 200 assert response.status_code == 200
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_stream_response(server): async def test_stream_response(server):
async with http3.AsyncClient() as client: async with httpx.AsyncClient() as client:
response = await client.request("GET", "http://127.0.0.1:8000/", stream=True) response = await client.request("GET", "http://127.0.0.1:8000/", stream=True)
assert response.status_code == 200 assert response.status_code == 200
body = await response.read() body = await response.read()
@ -43,10 +43,10 @@ async def test_stream_response(server):
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_access_content_stream_response(server): async def test_access_content_stream_response(server):
async with http3.AsyncClient() as client: async with httpx.AsyncClient() as client:
response = await client.request("GET", "http://127.0.0.1:8000/", stream=True) response = await client.request("GET", "http://127.0.0.1:8000/", stream=True)
assert response.status_code == 200 assert response.status_code == 200
with pytest.raises(http3.ResponseNotRead): with pytest.raises(httpx.ResponseNotRead):
response.content response.content
@ -56,7 +56,7 @@ async def test_stream_request(server):
yield b"Hello, " yield b"Hello, "
yield b"world!" yield b"world!"
async with http3.AsyncClient() as client: async with httpx.AsyncClient() as client:
response = await client.request( response = await client.request(
"POST", "http://127.0.0.1:8000/", data=hello_world() "POST", "http://127.0.0.1:8000/", data=hello_world()
) )
@ -65,14 +65,14 @@ async def test_stream_request(server):
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_raise_for_status(server): async def test_raise_for_status(server):
async with http3.AsyncClient() as client: async with httpx.AsyncClient() as client:
for status_code in (200, 400, 404, 500, 505): for status_code in (200, 400, 404, 500, 505):
response = await client.request( response = await client.request(
"GET", f"http://127.0.0.1:8000/status/{status_code}" "GET", f"http://127.0.0.1:8000/status/{status_code}"
) )
if 400 <= status_code < 600: if 400 <= status_code < 600:
with pytest.raises(http3.exceptions.HttpError): with pytest.raises(httpx.exceptions.HttpError):
response.raise_for_status() response.raise_for_status()
else: else:
assert response.raise_for_status() is None assert response.raise_for_status() is None
@ -81,7 +81,7 @@ async def test_raise_for_status(server):
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_options(server): async def test_options(server):
url = "http://127.0.0.1:8000/" url = "http://127.0.0.1:8000/"
async with http3.AsyncClient() as client: async with httpx.AsyncClient() as client:
response = await client.options(url) response = await client.options(url)
assert response.status_code == 200 assert response.status_code == 200
assert response.text == "Hello, world!" assert response.text == "Hello, world!"
@ -90,7 +90,7 @@ async def test_options(server):
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_head(server): async def test_head(server):
url = "http://127.0.0.1:8000/" url = "http://127.0.0.1:8000/"
async with http3.AsyncClient() as client: async with httpx.AsyncClient() as client:
response = await client.head(url) response = await client.head(url)
assert response.status_code == 200 assert response.status_code == 200
assert response.text == "" assert response.text == ""
@ -99,7 +99,7 @@ async def test_head(server):
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_put(server): async def test_put(server):
url = "http://127.0.0.1:8000/" url = "http://127.0.0.1:8000/"
async with http3.AsyncClient() as client: async with httpx.AsyncClient() as client:
response = await client.put(url, data=b"Hello, world!") response = await client.put(url, data=b"Hello, world!")
assert response.status_code == 200 assert response.status_code == 200
@ -107,7 +107,7 @@ async def test_put(server):
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_patch(server): async def test_patch(server):
url = "http://127.0.0.1:8000/" url = "http://127.0.0.1:8000/"
async with http3.AsyncClient() as client: async with httpx.AsyncClient() as client:
response = await client.patch(url, data=b"Hello, world!") response = await client.patch(url, data=b"Hello, world!")
assert response.status_code == 200 assert response.status_code == 200
@ -115,7 +115,7 @@ async def test_patch(server):
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_delete(server): async def test_delete(server):
url = "http://127.0.0.1:8000/" url = "http://127.0.0.1:8000/"
async with http3.AsyncClient() as client: async with httpx.AsyncClient() as client:
response = await client.delete(url) response = await client.delete(url)
assert response.status_code == 200 assert response.status_code == 200
assert response.text == "Hello, world!" assert response.text == "Hello, world!"
@ -127,7 +127,7 @@ async def test_100_continue(server):
headers = {"Expect": "100-continue"} headers = {"Expect": "100-continue"}
data = b"Echo request body" data = b"Echo request body"
async with http3.AsyncClient() as client: async with httpx.AsyncClient() as client:
response = await client.post(url, headers=headers, data=data) response = await client.post(url, headers=headers, data=data)
assert response.status_code == 200 assert response.status_code == 200

View File

@ -1,6 +1,6 @@
import json import json
from http3 import ( from httpx import (
AsyncDispatcher, AsyncDispatcher,
AsyncRequest, AsyncRequest,
AsyncResponse, AsyncResponse,

View File

@ -3,7 +3,7 @@ import functools
import pytest import pytest
import http3 import httpx
def threadpool(func): def threadpool(func):
@ -26,15 +26,15 @@ def threadpool(func):
@threadpool @threadpool
def test_get(server): def test_get(server):
url = "http://127.0.0.1:8000/" url = "http://127.0.0.1:8000/"
with http3.Client() as http: with httpx.Client() as http:
response = http.get(url) response = http.get(url)
assert response.status_code == 200 assert response.status_code == 200
assert response.url == http3.URL(url) assert response.url == httpx.URL(url)
assert response.content == b"Hello, world!" assert response.content == b"Hello, world!"
assert response.text == "Hello, world!" assert response.text == "Hello, world!"
assert response.protocol == "HTTP/1.1" assert response.protocol == "HTTP/1.1"
assert response.encoding == "iso-8859-1" assert response.encoding == "iso-8859-1"
assert response.request.url == http3.URL(url) assert response.request.url == httpx.URL(url)
assert response.headers assert response.headers
assert response.is_redirect is False assert response.is_redirect is False
assert repr(response) == "<Response [200 OK]>" assert repr(response) == "<Response [200 OK]>"
@ -42,7 +42,7 @@ def test_get(server):
@threadpool @threadpool
def test_post(server): def test_post(server):
with http3.Client() as http: with httpx.Client() as http:
response = http.post("http://127.0.0.1:8000/", data=b"Hello, world!") response = http.post("http://127.0.0.1:8000/", data=b"Hello, world!")
assert response.status_code == 200 assert response.status_code == 200
assert response.reason_phrase == "OK" assert response.reason_phrase == "OK"
@ -50,7 +50,7 @@ def test_post(server):
@threadpool @threadpool
def test_post_json(server): def test_post_json(server):
with http3.Client() as http: with httpx.Client() as http:
response = http.post("http://127.0.0.1:8000/", json={"text": "Hello, world!"}) response = http.post("http://127.0.0.1:8000/", json={"text": "Hello, world!"})
assert response.status_code == 200 assert response.status_code == 200
assert response.reason_phrase == "OK" assert response.reason_phrase == "OK"
@ -58,7 +58,7 @@ def test_post_json(server):
@threadpool @threadpool
def test_stream_response(server): def test_stream_response(server):
with http3.Client() as http: with httpx.Client() as http:
response = http.get("http://127.0.0.1:8000/", stream=True) response = http.get("http://127.0.0.1:8000/", stream=True)
assert response.status_code == 200 assert response.status_code == 200
content = response.read() content = response.read()
@ -67,7 +67,7 @@ def test_stream_response(server):
@threadpool @threadpool
def test_stream_iterator(server): def test_stream_iterator(server):
with http3.Client() as http: with httpx.Client() as http:
response = http.get("http://127.0.0.1:8000/", stream=True) response = http.get("http://127.0.0.1:8000/", stream=True)
assert response.status_code == 200 assert response.status_code == 200
body = b"" body = b""
@ -78,7 +78,7 @@ def test_stream_iterator(server):
@threadpool @threadpool
def test_raw_iterator(server): def test_raw_iterator(server):
with http3.Client() as http: with httpx.Client() as http:
response = http.get("http://127.0.0.1:8000/", stream=True) response = http.get("http://127.0.0.1:8000/", stream=True)
assert response.status_code == 200 assert response.status_code == 200
body = b"" body = b""
@ -90,14 +90,14 @@ def test_raw_iterator(server):
@threadpool @threadpool
def test_raise_for_status(server): def test_raise_for_status(server):
with http3.Client() as client: with httpx.Client() as client:
for status_code in (200, 400, 404, 500, 505): for status_code in (200, 400, 404, 500, 505):
response = client.request( response = client.request(
"GET", "http://127.0.0.1:8000/status/{}".format(status_code) "GET", "http://127.0.0.1:8000/status/{}".format(status_code)
) )
if 400 <= status_code < 600: if 400 <= status_code < 600:
with pytest.raises(http3.exceptions.HttpError): with pytest.raises(httpx.exceptions.HttpError):
response.raise_for_status() response.raise_for_status()
else: else:
assert response.raise_for_status() is None assert response.raise_for_status() is None
@ -105,7 +105,7 @@ def test_raise_for_status(server):
@threadpool @threadpool
def test_options(server): def test_options(server):
with http3.Client() as http: with httpx.Client() as http:
response = http.options("http://127.0.0.1:8000/") response = http.options("http://127.0.0.1:8000/")
assert response.status_code == 200 assert response.status_code == 200
assert response.reason_phrase == "OK" assert response.reason_phrase == "OK"
@ -113,7 +113,7 @@ def test_options(server):
@threadpool @threadpool
def test_head(server): def test_head(server):
with http3.Client() as http: with httpx.Client() as http:
response = http.head("http://127.0.0.1:8000/") response = http.head("http://127.0.0.1:8000/")
assert response.status_code == 200 assert response.status_code == 200
assert response.reason_phrase == "OK" assert response.reason_phrase == "OK"
@ -121,7 +121,7 @@ def test_head(server):
@threadpool @threadpool
def test_put(server): def test_put(server):
with http3.Client() as http: with httpx.Client() as http:
response = http.put("http://127.0.0.1:8000/", data=b"Hello, world!") response = http.put("http://127.0.0.1:8000/", data=b"Hello, world!")
assert response.status_code == 200 assert response.status_code == 200
assert response.reason_phrase == "OK" assert response.reason_phrase == "OK"
@ -129,7 +129,7 @@ def test_put(server):
@threadpool @threadpool
def test_patch(server): def test_patch(server):
with http3.Client() as http: with httpx.Client() as http:
response = http.patch("http://127.0.0.1:8000/", data=b"Hello, world!") response = http.patch("http://127.0.0.1:8000/", data=b"Hello, world!")
assert response.status_code == 200 assert response.status_code == 200
assert response.reason_phrase == "OK" assert response.reason_phrase == "OK"
@ -137,7 +137,7 @@ def test_patch(server):
@threadpool @threadpool
def test_delete(server): def test_delete(server):
with http3.Client() as http: with httpx.Client() as http:
response = http.delete("http://127.0.0.1:8000/") response = http.delete("http://127.0.0.1:8000/")
assert response.status_code == 200 assert response.status_code == 200
assert response.reason_phrase == "OK" assert response.reason_phrase == "OK"
@ -146,7 +146,7 @@ def test_delete(server):
@threadpool @threadpool
def test_base_url(server): def test_base_url(server):
base_url = "http://127.0.0.1:8000/" base_url = "http://127.0.0.1:8000/"
with http3.Client(base_url=base_url) as http: with httpx.Client(base_url=base_url) as http:
response = http.get("/") response = http.get("/")
assert response.status_code == 200 assert response.status_code == 200
assert str(response.url) == base_url assert str(response.url) == base_url

View File

@ -1,7 +1,7 @@
import json import json
from http.cookiejar import Cookie, CookieJar from http.cookiejar import Cookie, CookieJar
from http3 import ( from httpx import (
AsyncDispatcher, AsyncDispatcher,
AsyncRequest, AsyncRequest,
AsyncResponse, AsyncResponse,

View File

@ -3,7 +3,7 @@ from urllib.parse import parse_qs
import pytest import pytest
from http3 import ( from httpx import (
URL, URL,
AsyncClient, AsyncClient,
AsyncDispatcher, AsyncDispatcher,

View File

@ -1,6 +1,6 @@
import pytest import pytest
import http3 import httpx
@pytest.mark.asyncio @pytest.mark.asyncio
@ -8,7 +8,7 @@ async def test_keepalive_connections(server):
""" """
Connections should default to staying in a keep-alive state. Connections should default to staying in a keep-alive state.
""" """
async with http3.ConnectionPool() as http: async with httpx.ConnectionPool() as http:
response = await http.request("GET", "http://127.0.0.1:8000/") response = await http.request("GET", "http://127.0.0.1:8000/")
await response.read() await response.read()
assert len(http.active_connections) == 0 assert len(http.active_connections) == 0
@ -25,7 +25,7 @@ async def test_differing_connection_keys(server):
""" """
Connnections to differing connection keys should result in multiple connections. Connnections to differing connection keys should result in multiple connections.
""" """
async with http3.ConnectionPool() as http: async with httpx.ConnectionPool() as http:
response = await http.request("GET", "http://127.0.0.1:8000/") response = await http.request("GET", "http://127.0.0.1:8000/")
await response.read() await response.read()
assert len(http.active_connections) == 0 assert len(http.active_connections) == 0
@ -42,9 +42,9 @@ async def test_soft_limit(server):
""" """
The soft_limit config should limit the maximum number of keep-alive connections. The soft_limit config should limit the maximum number of keep-alive connections.
""" """
pool_limits = http3.PoolLimits(soft_limit=1) pool_limits = httpx.PoolLimits(soft_limit=1)
async with http3.ConnectionPool(pool_limits=pool_limits) as http: async with httpx.ConnectionPool(pool_limits=pool_limits) as http:
response = await http.request("GET", "http://127.0.0.1:8000/") response = await http.request("GET", "http://127.0.0.1:8000/")
await response.read() await response.read()
assert len(http.active_connections) == 0 assert len(http.active_connections) == 0
@ -61,7 +61,7 @@ async def test_streaming_response_holds_connection(server):
""" """
A streaming request should hold the connection open until the response is read. A streaming request should hold the connection open until the response is read.
""" """
async with http3.ConnectionPool() as http: async with httpx.ConnectionPool() as http:
response = await http.request("GET", "http://127.0.0.1:8000/") response = await http.request("GET", "http://127.0.0.1:8000/")
assert len(http.active_connections) == 1 assert len(http.active_connections) == 1
assert len(http.keepalive_connections) == 0 assert len(http.keepalive_connections) == 0
@ -77,7 +77,7 @@ async def test_multiple_concurrent_connections(server):
""" """
Multiple conncurrent requests should open multiple conncurrent connections. Multiple conncurrent requests should open multiple conncurrent connections.
""" """
async with http3.ConnectionPool() as http: async with httpx.ConnectionPool() as http:
response_a = await http.request("GET", "http://127.0.0.1:8000/") response_a = await http.request("GET", "http://127.0.0.1:8000/")
assert len(http.active_connections) == 1 assert len(http.active_connections) == 1
assert len(http.keepalive_connections) == 0 assert len(http.keepalive_connections) == 0
@ -101,7 +101,7 @@ async def test_close_connections(server):
Using a `Connection: close` header should close the connection. Using a `Connection: close` header should close the connection.
""" """
headers = [(b"connection", b"close")] headers = [(b"connection", b"close")]
async with http3.ConnectionPool() as http: async with httpx.ConnectionPool() as http:
response = await http.request("GET", "http://127.0.0.1:8000/", headers=headers) response = await http.request("GET", "http://127.0.0.1:8000/", headers=headers)
await response.read() await response.read()
assert len(http.active_connections) == 0 assert len(http.active_connections) == 0
@ -113,7 +113,7 @@ async def test_standard_response_close(server):
""" """
A standard close should keep the connection open. A standard close should keep the connection open.
""" """
async with http3.ConnectionPool() as http: async with httpx.ConnectionPool() as http:
response = await http.request("GET", "http://127.0.0.1:8000/") response = await http.request("GET", "http://127.0.0.1:8000/")
await response.read() await response.read()
await response.close() await response.close()
@ -126,7 +126,7 @@ async def test_premature_response_close(server):
""" """
A premature close should close the connection. A premature close should close the connection.
""" """
async with http3.ConnectionPool() as http: async with httpx.ConnectionPool() as http:
response = await http.request("GET", "http://127.0.0.1:8000/") response = await http.request("GET", "http://127.0.0.1:8000/")
await response.close() await response.close()
assert len(http.active_connections) == 0 assert len(http.active_connections) == 0

View File

@ -1,6 +1,6 @@
import pytest import pytest
from http3 import HTTPConnection from httpx import HTTPConnection
@pytest.mark.asyncio @pytest.mark.asyncio

View File

@ -1,6 +1,6 @@
import json import json
from http3 import Client, Response from httpx import Client, Response
from .utils import MockHTTP2Backend from .utils import MockHTTP2Backend

View File

@ -1,6 +1,6 @@
import json import json
from http3 import ( from httpx import (
CertTypes, CertTypes,
Client, Client,
Dispatcher, Dispatcher,

View File

@ -6,7 +6,7 @@ import h2.config
import h2.connection import h2.connection
import h2.events import h2.events
from http3 import ( from httpx import (
AsyncioBackend, AsyncioBackend,
BaseReader, BaseReader,
BaseWriter, BaseWriter,

View File

@ -1,6 +1,6 @@
import pytest import pytest
from http3 import CookieConflict, Cookies from httpx import CookieConflict, Cookies
def test_cookies(): def test_cookies():

View File

@ -1,8 +1,8 @@
import http3 import httpx
def test_headers(): def test_headers():
h = http3.Headers([("a", "123"), ("a", "456"), ("b", "789")]) h = httpx.Headers([("a", "123"), ("a", "456"), ("b", "789")])
assert "a" in h assert "a" in h
assert "A" in h assert "A" in h
assert "b" in h assert "b" in h
@ -18,10 +18,10 @@ def test_headers():
assert list(h) == ["a", "a", "b"] assert list(h) == ["a", "a", "b"]
assert dict(h) == {"a": "123, 456", "b": "789"} assert dict(h) == {"a": "123, 456", "b": "789"}
assert repr(h) == "Headers([('a', '123'), ('a', '456'), ('b', '789')])" assert repr(h) == "Headers([('a', '123'), ('a', '456'), ('b', '789')])"
assert h == http3.Headers([("a", "123"), ("b", "789"), ("a", "456")]) assert h == httpx.Headers([("a", "123"), ("b", "789"), ("a", "456")])
assert h != [("a", "123"), ("A", "456"), ("b", "789")] assert h != [("a", "123"), ("A", "456"), ("b", "789")]
h = http3.Headers({"a": "123", "b": "789"}) h = httpx.Headers({"a": "123", "b": "789"})
assert h["A"] == "123" assert h["A"] == "123"
assert h["B"] == "789" assert h["B"] == "789"
assert h.raw == [(b"a", b"123"), (b"b", b"789")] assert h.raw == [(b"a", b"123"), (b"b", b"789")]
@ -29,7 +29,7 @@ def test_headers():
def test_header_mutations(): def test_header_mutations():
h = http3.Headers() h = httpx.Headers()
assert dict(h) == {} assert dict(h) == {}
h["a"] = "1" h["a"] = "1"
assert dict(h) == {"a": "1"} assert dict(h) == {"a": "1"}
@ -45,31 +45,31 @@ def test_header_mutations():
def test_copy_headers(): def test_copy_headers():
headers = http3.Headers({"custom": "example"}) headers = httpx.Headers({"custom": "example"})
headers_copy = http3.Headers(headers) headers_copy = httpx.Headers(headers)
assert headers == headers_copy assert headers == headers_copy
def test_headers_insert_retains_ordering(): def test_headers_insert_retains_ordering():
headers = http3.Headers({"a": "a", "b": "b", "c": "c"}) headers = httpx.Headers({"a": "a", "b": "b", "c": "c"})
headers["b"] = "123" headers["b"] = "123"
assert list(headers.values()) == ["a", "123", "c"] assert list(headers.values()) == ["a", "123", "c"]
def test_headers_insert_appends_if_new(): def test_headers_insert_appends_if_new():
headers = http3.Headers({"a": "a", "b": "b", "c": "c"}) headers = httpx.Headers({"a": "a", "b": "b", "c": "c"})
headers["d"] = "123" headers["d"] = "123"
assert list(headers.values()) == ["a", "b", "c", "123"] assert list(headers.values()) == ["a", "b", "c", "123"]
def test_headers_insert_removes_all_existing(): def test_headers_insert_removes_all_existing():
headers = http3.Headers([("a", "123"), ("a", "456")]) headers = httpx.Headers([("a", "123"), ("a", "456")])
headers["a"] = "789" headers["a"] = "789"
assert dict(headers) == {"a": "789"} assert dict(headers) == {"a": "789"}
def test_headers_delete_removes_all_existing(): def test_headers_delete_removes_all_existing():
headers = http3.Headers([("a", "123"), ("a", "456")]) headers = httpx.Headers([("a", "123"), ("a", "456")])
del headers["a"] del headers["a"]
assert dict(headers) == {} assert dict(headers) == {}
@ -78,7 +78,7 @@ def test_headers_dict_repr():
""" """
Headers should display with a dict repr by default. Headers should display with a dict repr by default.
""" """
headers = http3.Headers({"custom": "example"}) headers = httpx.Headers({"custom": "example"})
assert repr(headers) == "Headers({'custom': 'example'})" assert repr(headers) == "Headers({'custom': 'example'})"
@ -86,7 +86,7 @@ def test_headers_encoding_in_repr():
""" """
Headers should display an encoding in the repr if required. Headers should display an encoding in the repr if required.
""" """
headers = http3.Headers({b"custom": "example ☃".encode("utf-8")}) headers = httpx.Headers({b"custom": "example ☃".encode("utf-8")})
assert repr(headers) == "Headers({'custom': 'example ☃'}, encoding='utf-8')" assert repr(headers) == "Headers({'custom': 'example ☃'}, encoding='utf-8')"
@ -94,7 +94,7 @@ def test_headers_list_repr():
""" """
Headers should display with a list repr if they include multiple identical keys. Headers should display with a list repr if they include multiple identical keys.
""" """
headers = http3.Headers([("custom", "example 1"), ("custom", "example 2")]) headers = httpx.Headers([("custom", "example 1"), ("custom", "example 2")])
assert ( assert (
repr(headers) == "Headers([('custom', 'example 1'), ('custom', 'example 2')])" repr(headers) == "Headers([('custom', 'example 1'), ('custom', 'example 2')])"
) )
@ -105,7 +105,7 @@ def test_headers_decode_ascii():
Headers should decode as ascii by default. Headers should decode as ascii by default.
""" """
raw_headers = [(b"Custom", b"Example")] raw_headers = [(b"Custom", b"Example")]
headers = http3.Headers(raw_headers) headers = httpx.Headers(raw_headers)
assert dict(headers) == {"custom": "Example"} assert dict(headers) == {"custom": "Example"}
assert headers.encoding == "ascii" assert headers.encoding == "ascii"
@ -115,7 +115,7 @@ def test_headers_decode_utf_8():
Headers containing non-ascii codepoints should default to decoding as utf-8. Headers containing non-ascii codepoints should default to decoding as utf-8.
""" """
raw_headers = [(b"Custom", "Code point: ☃".encode("utf-8"))] raw_headers = [(b"Custom", "Code point: ☃".encode("utf-8"))]
headers = http3.Headers(raw_headers) headers = httpx.Headers(raw_headers)
assert dict(headers) == {"custom": "Code point: ☃"} assert dict(headers) == {"custom": "Code point: ☃"}
assert headers.encoding == "utf-8" assert headers.encoding == "utf-8"
@ -125,7 +125,7 @@ def test_headers_decode_iso_8859_1():
Headers containing non-UTF-8 codepoints should default to decoding as iso-8859-1. Headers containing non-UTF-8 codepoints should default to decoding as iso-8859-1.
""" """
raw_headers = [(b"Custom", "Code point: ÿ".encode("iso-8859-1"))] raw_headers = [(b"Custom", "Code point: ÿ".encode("iso-8859-1"))]
headers = http3.Headers(raw_headers) headers = httpx.Headers(raw_headers)
assert dict(headers) == {"custom": "Code point: ÿ"} assert dict(headers) == {"custom": "Code point: ÿ"}
assert headers.encoding == "iso-8859-1" assert headers.encoding == "iso-8859-1"
@ -136,7 +136,7 @@ def test_headers_decode_explicit_encoding():
particular decoding. particular decoding.
""" """
raw_headers = [(b"Custom", "Code point: ☃".encode("utf-8"))] raw_headers = [(b"Custom", "Code point: ☃".encode("utf-8"))]
headers = http3.Headers(raw_headers) headers = httpx.Headers(raw_headers)
headers.encoding = "iso-8859-1" headers.encoding = "iso-8859-1"
assert dict(headers) == {"custom": "Code point: â\x98\x83"} assert dict(headers) == {"custom": "Code point: â\x98\x83"}
assert headers.encoding == "iso-8859-1" assert headers.encoding == "iso-8859-1"
@ -146,8 +146,8 @@ def test_multiple_headers():
""" """
Most headers should split by commas for `getlist`, except 'Set-Cookie'. Most headers should split by commas for `getlist`, except 'Set-Cookie'.
""" """
h = http3.Headers([("set-cookie", "a, b"), ("set-cookie", "c")]) h = httpx.Headers([("set-cookie", "a, b"), ("set-cookie", "c")])
h.getlist("Set-Cookie") == ["a, b", "b"] h.getlist("Set-Cookie") == ["a, b", "b"]
h = http3.Headers([("vary", "a, b"), ("vary", "c")]) h = httpx.Headers([("vary", "a, b"), ("vary", "c")])
h.getlist("Vary") == ["a", "b", "c"] h.getlist("Vary") == ["a", "b", "c"]

View File

@ -1,4 +1,4 @@
from http3 import QueryParams from httpx import QueryParams
def test_queryparams(): def test_queryparams():

View File

@ -1,32 +1,32 @@
import pytest import pytest
import http3 import httpx
def test_request_repr(): def test_request_repr():
request = http3.Request("GET", "http://example.org") request = httpx.Request("GET", "http://example.org")
assert repr(request) == "<Request('GET', 'http://example.org')>" assert repr(request) == "<Request('GET', 'http://example.org')>"
def test_no_content(): def test_no_content():
request = http3.Request("GET", "http://example.org") request = httpx.Request("GET", "http://example.org")
assert "Content-Length" not in request.headers assert "Content-Length" not in request.headers
def test_content_length_header(): def test_content_length_header():
request = http3.Request("POST", "http://example.org", data=b"test 123") request = httpx.Request("POST", "http://example.org", data=b"test 123")
assert request.headers["Content-Length"] == "8" assert request.headers["Content-Length"] == "8"
def test_url_encoded_data(): def test_url_encoded_data():
for RequestClass in (http3.Request, http3.AsyncRequest): for RequestClass in (httpx.Request, httpx.AsyncRequest):
request = RequestClass("POST", "http://example.org", data={"test": "123"}) request = RequestClass("POST", "http://example.org", data={"test": "123"})
assert request.headers["Content-Type"] == "application/x-www-form-urlencoded" assert request.headers["Content-Type"] == "application/x-www-form-urlencoded"
assert request.content == b"test=123" assert request.content == b"test=123"
def test_json_encoded_data(): def test_json_encoded_data():
for RequestClass in (http3.Request, http3.AsyncRequest): for RequestClass in (httpx.Request, httpx.AsyncRequest):
request = RequestClass("POST", "http://example.org", json={"test": 123}) request = RequestClass("POST", "http://example.org", json={"test": 123})
assert request.headers["Content-Type"] == "application/json" assert request.headers["Content-Type"] == "application/json"
assert request.content == b'{"test": 123}' assert request.content == b'{"test": 123}'
@ -38,7 +38,7 @@ def test_transfer_encoding_header():
data = streaming_body(b"test 123") data = streaming_body(b"test 123")
request = http3.Request("POST", "http://example.org", data=data) request = httpx.Request("POST", "http://example.org", data=data)
assert "Content-Length" not in request.headers assert "Content-Length" not in request.headers
assert request.headers["Transfer-Encoding"] == "chunked" assert request.headers["Transfer-Encoding"] == "chunked"
@ -46,14 +46,14 @@ def test_transfer_encoding_header():
def test_override_host_header(): def test_override_host_header():
headers = {"host": "1.2.3.4:80"} headers = {"host": "1.2.3.4:80"}
request = http3.Request("GET", "http://example.org", headers=headers) request = httpx.Request("GET", "http://example.org", headers=headers)
assert request.headers["Host"] == "1.2.3.4:80" assert request.headers["Host"] == "1.2.3.4:80"
def test_override_accept_encoding_header(): def test_override_accept_encoding_header():
headers = {"Accept-Encoding": "identity"} headers = {"Accept-Encoding": "identity"}
request = http3.Request("GET", "http://example.org", headers=headers) request = httpx.Request("GET", "http://example.org", headers=headers)
assert request.headers["Accept-Encoding"] == "identity" assert request.headers["Accept-Encoding"] == "identity"
@ -64,27 +64,27 @@ def test_override_content_length_header():
data = streaming_body(b"test 123") data = streaming_body(b"test 123")
headers = {"Content-Length": "8"} headers = {"Content-Length": "8"}
request = http3.Request("POST", "http://example.org", data=data, headers=headers) request = httpx.Request("POST", "http://example.org", data=data, headers=headers)
assert request.headers["Content-Length"] == "8" assert request.headers["Content-Length"] == "8"
def test_url(): def test_url():
url = "http://example.org" url = "http://example.org"
request = http3.Request("GET", url) request = httpx.Request("GET", url)
assert request.url.scheme == "http" assert request.url.scheme == "http"
assert request.url.port == 80 assert request.url.port == 80
assert request.url.full_path == "/" assert request.url.full_path == "/"
url = "https://example.org/abc?foo=bar" url = "https://example.org/abc?foo=bar"
request = http3.Request("GET", url) request = httpx.Request("GET", url)
assert request.url.scheme == "https" assert request.url.scheme == "https"
assert request.url.port == 443 assert request.url.port == 443
assert request.url.full_path == "/abc?foo=bar" assert request.url.full_path == "/abc?foo=bar"
def test_invalid_urls(): def test_invalid_urls():
with pytest.raises(http3.InvalidURL): with pytest.raises(httpx.InvalidURL):
http3.Request("GET", "example.org") httpx.Request("GET", "example.org")
with pytest.raises(http3.InvalidURL): with pytest.raises(httpx.InvalidURL):
http3.Request("GET", "http:///foo") httpx.Request("GET", "http:///foo")

View File

@ -3,7 +3,7 @@ from unittest import mock
import pytest import pytest
import http3 import httpx
def streaming_body(): def streaming_body():
@ -17,14 +17,14 @@ async def async_streaming_body():
def test_response(): def test_response():
response = http3.Response(200, content=b"Hello, world!") response = httpx.Response(200, content=b"Hello, world!")
assert response.status_code == 200 assert response.status_code == 200
assert response.reason_phrase == "OK" assert response.reason_phrase == "OK"
assert response.text == "Hello, world!" assert response.text == "Hello, world!"
def test_response_repr(): def test_response_repr():
response = http3.Response(200, content=b"Hello, world!") response = httpx.Response(200, content=b"Hello, world!")
assert repr(response) == "<Response [200 OK]>" assert repr(response) == "<Response [200 OK]>"
@ -34,7 +34,7 @@ def test_response_content_type_encoding():
""" """
headers = {"Content-Type": "text-plain; charset=latin-1"} headers = {"Content-Type": "text-plain; charset=latin-1"}
content = "Latin 1: ÿ".encode("latin-1") content = "Latin 1: ÿ".encode("latin-1")
response = http3.Response(200, content=content, headers=headers) response = httpx.Response(200, content=content, headers=headers)
assert response.text == "Latin 1: ÿ" assert response.text == "Latin 1: ÿ"
assert response.encoding == "latin-1" assert response.encoding == "latin-1"
@ -44,7 +44,7 @@ def test_response_autodetect_encoding():
Autodetect encoding if there is no charset info in a Content-Type header. Autodetect encoding if there is no charset info in a Content-Type header.
""" """
content = "おはようございます。".encode("EUC-JP") content = "おはようございます。".encode("EUC-JP")
response = http3.Response(200, content=content) response = httpx.Response(200, content=content)
assert response.text == "おはようございます。" assert response.text == "おはようございます。"
assert response.encoding == "EUC-JP" assert response.encoding == "EUC-JP"
@ -55,7 +55,7 @@ def test_response_fallback_to_autodetect():
""" """
headers = {"Content-Type": "text-plain; charset=invalid-codec-name"} headers = {"Content-Type": "text-plain; charset=invalid-codec-name"}
content = "おはようございます。".encode("EUC-JP") content = "おはようございます。".encode("EUC-JP")
response = http3.Response(200, content=content, headers=headers) response = httpx.Response(200, content=content, headers=headers)
assert response.text == "おはようございます。" assert response.text == "おはようございます。"
assert response.encoding == "EUC-JP" assert response.encoding == "EUC-JP"
@ -67,7 +67,7 @@ def test_response_default_text_encoding():
""" """
content = b"Hello, world!" content = b"Hello, world!"
headers = {"Content-Type": "text/plain"} headers = {"Content-Type": "text/plain"}
response = http3.Response(200, content=content, headers=headers) response = httpx.Response(200, content=content, headers=headers)
assert response.status_code == 200 assert response.status_code == 200
assert response.encoding == "iso-8859-1" assert response.encoding == "iso-8859-1"
assert response.text == "Hello, world!" assert response.text == "Hello, world!"
@ -77,7 +77,7 @@ def test_response_default_encoding():
""" """
Default to utf-8 if all else fails. Default to utf-8 if all else fails.
""" """
response = http3.Response(200, content=b"") response = httpx.Response(200, content=b"")
assert response.text == "" assert response.text == ""
assert response.encoding == "utf-8" assert response.encoding == "utf-8"
@ -87,7 +87,7 @@ def test_response_non_text_encoding():
Default to apparent encoding for non-text content-type headers. Default to apparent encoding for non-text content-type headers.
""" """
headers = {"Content-Type": "image/png"} headers = {"Content-Type": "image/png"}
response = http3.Response(200, content=b"xyz", headers=headers) response = httpx.Response(200, content=b"xyz", headers=headers)
assert response.text == "xyz" assert response.text == "xyz"
assert response.encoding == "ascii" assert response.encoding == "ascii"
@ -96,7 +96,7 @@ def test_response_set_explicit_encoding():
headers = { headers = {
"Content-Type": "text-plain; charset=utf-8" "Content-Type": "text-plain; charset=utf-8"
} # Deliberately incorrect charset } # Deliberately incorrect charset
response = http3.Response( response = httpx.Response(
200, content="Latin 1: ÿ".encode("latin-1"), headers=headers 200, content="Latin 1: ÿ".encode("latin-1"), headers=headers
) )
response.encoding = "latin-1" response.encoding = "latin-1"
@ -105,7 +105,7 @@ def test_response_set_explicit_encoding():
def test_response_force_encoding(): def test_response_force_encoding():
response = http3.Response(200, content="Snowman: ☃".encode("utf-8")) response = httpx.Response(200, content="Snowman: ☃".encode("utf-8"))
response.encoding = "iso-8859-1" response.encoding = "iso-8859-1"
assert response.status_code == 200 assert response.status_code == 200
assert response.reason_phrase == "OK" assert response.reason_phrase == "OK"
@ -114,7 +114,7 @@ def test_response_force_encoding():
def test_read_response(): def test_read_response():
response = http3.Response(200, content=b"Hello, world!") response = httpx.Response(200, content=b"Hello, world!")
assert response.status_code == 200 assert response.status_code == 200
assert response.text == "Hello, world!" assert response.text == "Hello, world!"
@ -129,7 +129,7 @@ def test_read_response():
def test_raw_interface(): def test_raw_interface():
response = http3.Response(200, content=b"Hello, world!") response = httpx.Response(200, content=b"Hello, world!")
raw = b"" raw = b""
for part in response.raw(): for part in response.raw():
@ -138,7 +138,7 @@ def test_raw_interface():
def test_stream_interface(): def test_stream_interface():
response = http3.Response(200, content=b"Hello, world!") response = httpx.Response(200, content=b"Hello, world!")
content = b"" content = b""
for part in response.stream(): for part in response.stream():
@ -148,7 +148,7 @@ def test_stream_interface():
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_async_stream_interface(): async def test_async_stream_interface():
response = http3.AsyncResponse(200, content=b"Hello, world!") response = httpx.AsyncResponse(200, content=b"Hello, world!")
content = b"" content = b""
async for part in response.stream(): async for part in response.stream():
@ -157,7 +157,7 @@ async def test_async_stream_interface():
def test_stream_interface_after_read(): def test_stream_interface_after_read():
response = http3.Response(200, content=b"Hello, world!") response = httpx.Response(200, content=b"Hello, world!")
response.read() response.read()
@ -169,7 +169,7 @@ def test_stream_interface_after_read():
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_async_stream_interface_after_read(): async def test_async_stream_interface_after_read():
response = http3.AsyncResponse(200, content=b"Hello, world!") response = httpx.AsyncResponse(200, content=b"Hello, world!")
await response.read() await response.read()
@ -180,7 +180,7 @@ async def test_async_stream_interface_after_read():
def test_streaming_response(): def test_streaming_response():
response = http3.Response(200, content=streaming_body()) response = httpx.Response(200, content=streaming_body())
assert response.status_code == 200 assert response.status_code == 200
assert not response.is_closed assert not response.is_closed
@ -194,7 +194,7 @@ def test_streaming_response():
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_async_streaming_response(): async def test_async_streaming_response():
response = http3.AsyncResponse(200, content=async_streaming_body()) response = httpx.AsyncResponse(200, content=async_streaming_body())
assert response.status_code == 200 assert response.status_code == 200
assert not response.is_closed assert not response.is_closed
@ -207,49 +207,49 @@ async def test_async_streaming_response():
def test_cannot_read_after_stream_consumed(): def test_cannot_read_after_stream_consumed():
response = http3.Response(200, content=streaming_body()) response = httpx.Response(200, content=streaming_body())
content = b"" content = b""
for part in response.stream(): for part in response.stream():
content += part content += part
with pytest.raises(http3.StreamConsumed): with pytest.raises(httpx.StreamConsumed):
response.read() response.read()
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_async_cannot_read_after_stream_consumed(): async def test_async_cannot_read_after_stream_consumed():
response = http3.AsyncResponse(200, content=async_streaming_body()) response = httpx.AsyncResponse(200, content=async_streaming_body())
content = b"" content = b""
async for part in response.stream(): async for part in response.stream():
content += part content += part
with pytest.raises(http3.StreamConsumed): with pytest.raises(httpx.StreamConsumed):
await response.read() await response.read()
def test_cannot_read_after_response_closed(): def test_cannot_read_after_response_closed():
response = http3.Response(200, content=streaming_body()) response = httpx.Response(200, content=streaming_body())
response.close() response.close()
with pytest.raises(http3.ResponseClosed): with pytest.raises(httpx.ResponseClosed):
response.read() response.read()
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_async_cannot_read_after_response_closed(): async def test_async_cannot_read_after_response_closed():
response = http3.AsyncResponse(200, content=async_streaming_body()) response = httpx.AsyncResponse(200, content=async_streaming_body())
await response.close() await response.close()
with pytest.raises(http3.ResponseClosed): with pytest.raises(httpx.ResponseClosed):
await response.read() await response.read()
def test_unknown_status_code(): def test_unknown_status_code():
response = http3.Response(600) response = httpx.Response(600)
assert response.status_code == 600 assert response.status_code == 600
assert response.reason_phrase == "" assert response.reason_phrase == ""
assert response.text == "" assert response.text == ""
@ -259,7 +259,7 @@ def test_json_with_specified_encoding():
data = dict(greeting="hello", recipient="world") data = dict(greeting="hello", recipient="world")
content = json.dumps(data).encode("utf-16") content = json.dumps(data).encode("utf-16")
headers = {"Content-Type": "application/json, charset=utf-16"} headers = {"Content-Type": "application/json, charset=utf-16"}
response = http3.Response(200, content=content, headers=headers) response = httpx.Response(200, content=content, headers=headers)
assert response.json() == data assert response.json() == data
@ -267,7 +267,7 @@ def test_json_with_options():
data = dict(greeting="hello", recipient="world", amount=1) data = dict(greeting="hello", recipient="world", amount=1)
content = json.dumps(data).encode("utf-16") content = json.dumps(data).encode("utf-16")
headers = {"Content-Type": "application/json, charset=utf-16"} headers = {"Content-Type": "application/json, charset=utf-16"}
response = http3.Response(200, content=content, headers=headers) response = httpx.Response(200, content=content, headers=headers)
assert response.json(parse_int=str)["amount"] == "1" assert response.json(parse_int=str)["amount"] == "1"
@ -275,7 +275,7 @@ def test_json_without_specified_encoding():
data = dict(greeting="hello", recipient="world") data = dict(greeting="hello", recipient="world")
content = json.dumps(data).encode("utf-32-be") content = json.dumps(data).encode("utf-32-be")
headers = {"Content-Type": "application/json"} headers = {"Content-Type": "application/json"}
response = http3.Response(200, content=content, headers=headers) response = httpx.Response(200, content=content, headers=headers)
assert response.json() == data assert response.json() == data
@ -284,7 +284,7 @@ def test_json_without_specified_encoding_decode_error():
content = json.dumps(data).encode("utf-32-be") content = json.dumps(data).encode("utf-32-be")
headers = {"Content-Type": "application/json"} headers = {"Content-Type": "application/json"}
# force incorrect guess from `guess_json_utf` to trigger error # force incorrect guess from `guess_json_utf` to trigger error
with mock.patch("http3.models.guess_json_utf", return_value="utf-32"): with mock.patch("httpx.models.guess_json_utf", return_value="utf-32"):
response = http3.Response(200, content=content, headers=headers) response = httpx.Response(200, content=content, headers=headers)
with pytest.raises(json.JSONDecodeError): with pytest.raises(json.JSONDecodeError):
response.json() response.json()

View File

@ -1,4 +1,4 @@
from http3 import URL from httpx import URL
def test_idna_url(): def test_idna_url():

View File

@ -3,7 +3,7 @@ import functools
import pytest import pytest
import http3 import httpx
def threadpool(func): def threadpool(func):
@ -25,7 +25,7 @@ def threadpool(func):
@threadpool @threadpool
def test_get(server): def test_get(server):
response = http3.get("http://127.0.0.1:8000/") response = httpx.get("http://127.0.0.1:8000/")
assert response.status_code == 200 assert response.status_code == 200
assert response.reason_phrase == "OK" assert response.reason_phrase == "OK"
assert response.text == "Hello, world!" assert response.text == "Hello, world!"
@ -33,7 +33,7 @@ def test_get(server):
@threadpool @threadpool
def test_post(server): def test_post(server):
response = http3.post("http://127.0.0.1:8000/", data=b"Hello, world!") response = httpx.post("http://127.0.0.1:8000/", data=b"Hello, world!")
assert response.status_code == 200 assert response.status_code == 200
assert response.reason_phrase == "OK" assert response.reason_phrase == "OK"
@ -45,47 +45,47 @@ def test_post_byte_iterator(server):
yield b", " yield b", "
yield b"world!" yield b"world!"
response = http3.post("http://127.0.0.1:8000/", data=data()) response = httpx.post("http://127.0.0.1:8000/", data=data())
assert response.status_code == 200 assert response.status_code == 200
assert response.reason_phrase == "OK" assert response.reason_phrase == "OK"
@threadpool @threadpool
def test_options(server): def test_options(server):
response = http3.options("http://127.0.0.1:8000/") response = httpx.options("http://127.0.0.1:8000/")
assert response.status_code == 200 assert response.status_code == 200
assert response.reason_phrase == "OK" assert response.reason_phrase == "OK"
@threadpool @threadpool
def test_head(server): def test_head(server):
response = http3.head("http://127.0.0.1:8000/") response = httpx.head("http://127.0.0.1:8000/")
assert response.status_code == 200 assert response.status_code == 200
assert response.reason_phrase == "OK" assert response.reason_phrase == "OK"
@threadpool @threadpool
def test_put(server): def test_put(server):
response = http3.put("http://127.0.0.1:8000/", data=b"Hello, world!") response = httpx.put("http://127.0.0.1:8000/", data=b"Hello, world!")
assert response.status_code == 200 assert response.status_code == 200
assert response.reason_phrase == "OK" assert response.reason_phrase == "OK"
@threadpool @threadpool
def test_patch(server): def test_patch(server):
response = http3.patch("http://127.0.0.1:8000/", data=b"Hello, world!") response = httpx.patch("http://127.0.0.1:8000/", data=b"Hello, world!")
assert response.status_code == 200 assert response.status_code == 200
assert response.reason_phrase == "OK" assert response.reason_phrase == "OK"
@threadpool @threadpool
def test_delete(server): def test_delete(server):
response = http3.delete("http://127.0.0.1:8000/") response = httpx.delete("http://127.0.0.1:8000/")
assert response.status_code == 200 assert response.status_code == 200
assert response.reason_phrase == "OK" assert response.reason_phrase == "OK"
@threadpool @threadpool
def test_get_invalid_url(server): def test_get_invalid_url(server):
with pytest.raises(http3.InvalidURL): with pytest.raises(httpx.InvalidURL):
http3.get("invalid://example.org") httpx.get("invalid://example.org")

View File

@ -1,6 +1,6 @@
import pytest import pytest
import http3 import httpx
async def hello_world(scope, receive, send): async def hello_world(scope, receive, send):
@ -40,26 +40,26 @@ async def raise_exc_after_response(scope, receive, send):
def test_asgi(): def test_asgi():
client = http3.Client(app=hello_world) client = httpx.Client(app=hello_world)
response = client.get("http://www.example.org/") response = client.get("http://www.example.org/")
assert response.status_code == 200 assert response.status_code == 200
assert response.text == "Hello, World!" assert response.text == "Hello, World!"
def test_asgi_upload(): def test_asgi_upload():
client = http3.Client(app=echo_body) client = httpx.Client(app=echo_body)
response = client.post("http://www.example.org/", data=b"example") response = client.post("http://www.example.org/", data=b"example")
assert response.status_code == 200 assert response.status_code == 200
assert response.text == "example" assert response.text == "example"
def test_asgi_exc(): def test_asgi_exc():
client = http3.Client(app=raise_exc) client = httpx.Client(app=raise_exc)
with pytest.raises(ValueError): with pytest.raises(ValueError):
client.get("http://www.example.org/") client.get("http://www.example.org/")
def test_asgi_exc_after_response(): def test_asgi_exc_after_response():
client = http3.Client(app=raise_exc_after_response) client = httpx.Client(app=raise_exc_after_response)
with pytest.raises(ValueError): with pytest.raises(ValueError):
client.get("http://www.example.org/") client.get("http://www.example.org/")

View File

@ -3,12 +3,12 @@ import ssl
import pytest import pytest
import http3 import httpx
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_load_ssl_config(): async def test_load_ssl_config():
ssl_config = http3.SSLConfig() ssl_config = httpx.SSLConfig()
context = await ssl_config.load_ssl_context() context = await ssl_config.load_ssl_context()
assert context.verify_mode == ssl.VerifyMode.CERT_REQUIRED assert context.verify_mode == ssl.VerifyMode.CERT_REQUIRED
assert context.check_hostname is True assert context.check_hostname is True
@ -16,14 +16,14 @@ async def test_load_ssl_config():
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_load_ssl_config_verify_non_existing_path(): async def test_load_ssl_config_verify_non_existing_path():
ssl_config = http3.SSLConfig(verify="/path/to/nowhere") ssl_config = httpx.SSLConfig(verify="/path/to/nowhere")
with pytest.raises(IOError): with pytest.raises(IOError):
await ssl_config.load_ssl_context() await ssl_config.load_ssl_context()
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_load_ssl_config_verify_existing_file(): async def test_load_ssl_config_verify_existing_file():
ssl_config = http3.SSLConfig(verify=http3.config.DEFAULT_CA_BUNDLE_PATH) ssl_config = httpx.SSLConfig(verify=httpx.config.DEFAULT_CA_BUNDLE_PATH)
context = await ssl_config.load_ssl_context() context = await ssl_config.load_ssl_context()
assert context.verify_mode == ssl.VerifyMode.CERT_REQUIRED assert context.verify_mode == ssl.VerifyMode.CERT_REQUIRED
assert context.check_hostname is True assert context.check_hostname is True
@ -31,8 +31,8 @@ async def test_load_ssl_config_verify_existing_file():
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_load_ssl_config_verify_directory(): async def test_load_ssl_config_verify_directory():
path = os.path.dirname(http3.config.DEFAULT_CA_BUNDLE_PATH) path = os.path.dirname(httpx.config.DEFAULT_CA_BUNDLE_PATH)
ssl_config = http3.SSLConfig(verify=path) ssl_config = httpx.SSLConfig(verify=path)
context = await ssl_config.load_ssl_context() context = await ssl_config.load_ssl_context()
assert context.verify_mode == ssl.VerifyMode.CERT_REQUIRED assert context.verify_mode == ssl.VerifyMode.CERT_REQUIRED
assert context.check_hostname is True assert context.check_hostname is True
@ -40,7 +40,7 @@ async def test_load_ssl_config_verify_directory():
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_load_ssl_config_cert_and_key(cert_pem_file, cert_private_key_file): async def test_load_ssl_config_cert_and_key(cert_pem_file, cert_private_key_file):
ssl_config = http3.SSLConfig(cert=(cert_pem_file, cert_private_key_file)) ssl_config = httpx.SSLConfig(cert=(cert_pem_file, cert_private_key_file))
context = await ssl_config.load_ssl_context() context = await ssl_config.load_ssl_context()
assert context.verify_mode == ssl.VerifyMode.CERT_REQUIRED assert context.verify_mode == ssl.VerifyMode.CERT_REQUIRED
assert context.check_hostname is True assert context.check_hostname is True
@ -51,7 +51,7 @@ async def test_load_ssl_config_cert_and_key(cert_pem_file, cert_private_key_file
async def test_load_ssl_config_cert_and_encrypted_key( async def test_load_ssl_config_cert_and_encrypted_key(
cert_pem_file, cert_encrypted_private_key_file, password cert_pem_file, cert_encrypted_private_key_file, password
): ):
ssl_config = http3.SSLConfig( ssl_config = httpx.SSLConfig(
cert=(cert_pem_file, cert_encrypted_private_key_file, password) cert=(cert_pem_file, cert_encrypted_private_key_file, password)
) )
context = await ssl_config.load_ssl_context() context = await ssl_config.load_ssl_context()
@ -63,7 +63,7 @@ async def test_load_ssl_config_cert_and_encrypted_key(
async def test_load_ssl_config_cert_and_key_invalid_password( async def test_load_ssl_config_cert_and_key_invalid_password(
cert_pem_file, cert_encrypted_private_key_file cert_pem_file, cert_encrypted_private_key_file
): ):
ssl_config = http3.SSLConfig( ssl_config = httpx.SSLConfig(
cert=(cert_pem_file, cert_encrypted_private_key_file, "password1") cert=(cert_pem_file, cert_encrypted_private_key_file, "password1")
) )
@ -73,29 +73,29 @@ async def test_load_ssl_config_cert_and_key_invalid_password(
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_load_ssl_config_cert_without_key_raises(cert_pem_file): async def test_load_ssl_config_cert_without_key_raises(cert_pem_file):
ssl_config = http3.SSLConfig(cert=cert_pem_file) ssl_config = httpx.SSLConfig(cert=cert_pem_file)
with pytest.raises(ssl.SSLError): with pytest.raises(ssl.SSLError):
await ssl_config.load_ssl_context() await ssl_config.load_ssl_context()
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_load_ssl_config_no_verify(): async def test_load_ssl_config_no_verify():
ssl_config = http3.SSLConfig(verify=False) ssl_config = httpx.SSLConfig(verify=False)
context = await ssl_config.load_ssl_context() context = await ssl_config.load_ssl_context()
assert context.verify_mode == ssl.VerifyMode.CERT_NONE assert context.verify_mode == ssl.VerifyMode.CERT_NONE
assert context.check_hostname is False assert context.check_hostname is False
def test_ssl_repr(): def test_ssl_repr():
ssl = http3.SSLConfig(verify=False) ssl = httpx.SSLConfig(verify=False)
assert repr(ssl) == "SSLConfig(cert=None, verify=False)" assert repr(ssl) == "SSLConfig(cert=None, verify=False)"
def test_timeout_repr(): def test_timeout_repr():
timeout = http3.TimeoutConfig(timeout=5.0) timeout = httpx.TimeoutConfig(timeout=5.0)
assert repr(timeout) == "TimeoutConfig(timeout=5.0)" assert repr(timeout) == "TimeoutConfig(timeout=5.0)"
timeout = http3.TimeoutConfig(read_timeout=5.0) timeout = httpx.TimeoutConfig(read_timeout=5.0)
assert ( assert (
repr(timeout) repr(timeout)
== "TimeoutConfig(connect_timeout=None, read_timeout=5.0, write_timeout=None)" == "TimeoutConfig(connect_timeout=None, read_timeout=5.0, write_timeout=None)"
@ -103,32 +103,32 @@ def test_timeout_repr():
def test_limits_repr(): def test_limits_repr():
limits = http3.PoolLimits(hard_limit=100) limits = httpx.PoolLimits(hard_limit=100)
assert ( assert (
repr(limits) == "PoolLimits(soft_limit=None, hard_limit=100, pool_timeout=None)" repr(limits) == "PoolLimits(soft_limit=None, hard_limit=100, pool_timeout=None)"
) )
def test_ssl_eq(): def test_ssl_eq():
ssl = http3.SSLConfig(verify=False) ssl = httpx.SSLConfig(verify=False)
assert ssl == http3.SSLConfig(verify=False) assert ssl == httpx.SSLConfig(verify=False)
def test_timeout_eq(): def test_timeout_eq():
timeout = http3.TimeoutConfig(timeout=5.0) timeout = httpx.TimeoutConfig(timeout=5.0)
assert timeout == http3.TimeoutConfig(timeout=5.0) assert timeout == httpx.TimeoutConfig(timeout=5.0)
def test_limits_eq(): def test_limits_eq():
limits = http3.PoolLimits(hard_limit=100) limits = httpx.PoolLimits(hard_limit=100)
assert limits == http3.PoolLimits(hard_limit=100) assert limits == httpx.PoolLimits(hard_limit=100)
def test_timeout_from_tuple(): def test_timeout_from_tuple():
timeout = http3.TimeoutConfig(timeout=(5.0, 5.0, 5.0)) timeout = httpx.TimeoutConfig(timeout=(5.0, 5.0, 5.0))
assert timeout == http3.TimeoutConfig(timeout=5.0) assert timeout == httpx.TimeoutConfig(timeout=5.0)
def test_timeout_from_config_instance(): def test_timeout_from_config_instance():
timeout = http3.TimeoutConfig(timeout=5.0) timeout = httpx.TimeoutConfig(timeout=5.0)
assert http3.TimeoutConfig(timeout) == http3.TimeoutConfig(timeout=5.0) assert httpx.TimeoutConfig(timeout) == httpx.TimeoutConfig(timeout=5.0)

View File

@ -3,7 +3,7 @@ import zlib
import brotli import brotli
import pytest import pytest
import http3 import httpx
def test_deflate(): def test_deflate():
@ -12,7 +12,7 @@ def test_deflate():
compressed_body = compressor.compress(body) + compressor.flush() compressed_body = compressor.compress(body) + compressor.flush()
headers = [(b"Content-Encoding", b"deflate")] headers = [(b"Content-Encoding", b"deflate")]
response = http3.Response(200, headers=headers, content=compressed_body) response = httpx.Response(200, headers=headers, content=compressed_body)
assert response.content == body assert response.content == body
@ -22,7 +22,7 @@ def test_gzip():
compressed_body = compressor.compress(body) + compressor.flush() compressed_body = compressor.compress(body) + compressor.flush()
headers = [(b"Content-Encoding", b"gzip")] headers = [(b"Content-Encoding", b"gzip")]
response = http3.Response(200, headers=headers, content=compressed_body) response = httpx.Response(200, headers=headers, content=compressed_body)
assert response.content == body assert response.content == body
@ -31,7 +31,7 @@ def test_brotli():
compressed_body = brotli.compress(body) compressed_body = brotli.compress(body)
headers = [(b"Content-Encoding", b"br")] headers = [(b"Content-Encoding", b"br")]
response = http3.Response(200, headers=headers, content=compressed_body) response = httpx.Response(200, headers=headers, content=compressed_body)
assert response.content == body assert response.content == body
@ -47,7 +47,7 @@ def test_multi():
) )
headers = [(b"Content-Encoding", b"deflate, gzip")] headers = [(b"Content-Encoding", b"deflate, gzip")]
response = http3.Response(200, headers=headers, content=compressed_body) response = httpx.Response(200, headers=headers, content=compressed_body)
assert response.content == body assert response.content == body
@ -56,11 +56,11 @@ def test_multi_with_identity():
compressed_body = brotli.compress(body) compressed_body = brotli.compress(body)
headers = [(b"Content-Encoding", b"br, identity")] headers = [(b"Content-Encoding", b"br, identity")]
response = http3.Response(200, headers=headers, content=compressed_body) response = httpx.Response(200, headers=headers, content=compressed_body)
assert response.content == body assert response.content == body
headers = [(b"Content-Encoding", b"identity, br")] headers = [(b"Content-Encoding", b"identity, br")]
response = http3.Response(200, headers=headers, content=compressed_body) response = httpx.Response(200, headers=headers, content=compressed_body)
assert response.content == body assert response.content == body
@ -73,7 +73,7 @@ def test_streaming():
yield compressor.flush() yield compressor.flush()
headers = [(b"Content-Encoding", b"gzip")] headers = [(b"Content-Encoding", b"gzip")]
response = http3.Response(200, headers=headers, content=compress(body)) response = httpx.Response(200, headers=headers, content=compress(body))
assert not hasattr(response, "body") assert not hasattr(response, "body")
assert response.read() == body assert response.read() == body
@ -83,6 +83,6 @@ def test_decoding_errors(header_value):
headers = [(b"Content-Encoding", header_value)] headers = [(b"Content-Encoding", header_value)]
body = b"test 123" body = b"test 123"
compressed_body = brotli.compress(body)[3:] compressed_body = brotli.compress(body)[3:]
with pytest.raises(http3.exceptions.DecodingError): with pytest.raises(httpx.exceptions.DecodingError):
response = http3.Response(200, headers=headers, content=compressed_body) response = httpx.Response(200, headers=headers, content=compressed_body)
response.content response.content

View File

@ -6,7 +6,7 @@ from unittest import mock
import pytest import pytest
from http3 import ( from httpx import (
CertTypes, CertTypes,
Client, Client,
Dispatcher, Dispatcher,

View File

@ -1,18 +1,18 @@
import http3 import httpx
def test_status_code_as_int(): def test_status_code_as_int():
assert http3.codes.NOT_FOUND == 404 assert httpx.codes.NOT_FOUND == 404
assert str(http3.codes.NOT_FOUND) == "404" assert str(httpx.codes.NOT_FOUND) == "404"
def test_lowercase_status_code(): def test_lowercase_status_code():
assert http3.codes.not_found == 404 assert httpx.codes.not_found == 404
def test_reason_phrase_for_status_code(): def test_reason_phrase_for_status_code():
assert http3.codes.get_reason_phrase(404) == "Not Found" assert httpx.codes.get_reason_phrase(404) == "Not Found"
def test_reason_phrase_for_unknown_status_code(): def test_reason_phrase_for_unknown_status_code():
assert http3.codes.get_reason_phrase(499) == "" assert httpx.codes.get_reason_phrase(499) == ""

View File

@ -1,6 +1,6 @@
import pytest import pytest
from http3 import ( from httpx import (
AsyncClient, AsyncClient,
ConnectTimeout, ConnectTimeout,
PoolLimits, PoolLimits,

View File

@ -1,6 +1,6 @@
import pytest import pytest
from http3.utils import guess_json_utf from httpx.utils import guess_json_utf
@pytest.mark.parametrize( @pytest.mark.parametrize(

View File

@ -2,7 +2,7 @@ import sys
import pytest import pytest
import http3 import httpx
def hello_world(environ, start_response): def hello_world(environ, start_response):
@ -69,27 +69,27 @@ def raise_exc(environ, start_response):
def test_wsgi(): def test_wsgi():
client = http3.Client(app=hello_world) client = httpx.Client(app=hello_world)
response = client.get("http://www.example.org/") response = client.get("http://www.example.org/")
assert response.status_code == 200 assert response.status_code == 200
assert response.text == "Hello, World!" assert response.text == "Hello, World!"
def test_wsgi_upload(): def test_wsgi_upload():
client = http3.Client(app=echo_body) client = httpx.Client(app=echo_body)
response = client.post("http://www.example.org/", data=b"example") response = client.post("http://www.example.org/", data=b"example")
assert response.status_code == 200 assert response.status_code == 200
assert response.text == "example" assert response.text == "example"
def test_wsgi_upload_with_response_stream(): def test_wsgi_upload_with_response_stream():
client = http3.Client(app=echo_body_with_response_stream) client = httpx.Client(app=echo_body_with_response_stream)
response = client.post("http://www.example.org/", data=b"example") response = client.post("http://www.example.org/", data=b"example")
assert response.status_code == 200 assert response.status_code == 200
assert response.text == "example" assert response.text == "example"
def test_wsgi_exc(): def test_wsgi_exc():
client = http3.Client(app=raise_exc) client = httpx.Client(app=raise_exc)
with pytest.raises(ValueError): with pytest.raises(ValueError):
client.get("http://www.example.org/") client.get("http://www.example.org/")