]> git.ipfire.org Git - thirdparty/httpx.git/commitdiff
http3 (#86)
authorTom Christie <tom@tomchristie.com>
Wed, 12 Jun 2019 14:02:16 +0000 (15:02 +0100)
committerGitHub <noreply@github.com>
Wed, 12 Jun 2019 14:02:16 +0000 (15:02 +0100)
* Start fleshing out documentation

* Docs work

* http3

* Update docs

* Include lowercase status codes, for requests compat

* Updating docs

* Docs tweaks

51 files changed:
README.md
docs/api.md [new file with mode: 0644]
docs/async.md [new file with mode: 0644]
docs/compatibility.md [new file with mode: 0644]
docs/index.md [new file with mode: 0644]
docs/parallel.md [new file with mode: 0644]
docs/quickstart.md [new file with mode: 0644]
http3/__init__.py [moved from httpcore/__init__.py with 97% similarity]
http3/api.py [moved from httpcore/api.py with 100% similarity]
http3/auth.py [moved from httpcore/auth.py with 100% similarity]
http3/client.py [moved from httpcore/client.py with 100% similarity]
http3/concurrency.py [moved from httpcore/concurrency.py with 100% similarity]
http3/config.py [moved from httpcore/config.py with 100% similarity]
http3/decoders.py [moved from httpcore/decoders.py with 89% similarity]
http3/dispatch/__init__.py [moved from httpcore/dispatch/__init__.py with 100% similarity]
http3/dispatch/connection.py [moved from httpcore/dispatch/connection.py with 100% similarity]
http3/dispatch/connection_pool.py [moved from httpcore/dispatch/connection_pool.py with 100% similarity]
http3/dispatch/http11.py [moved from httpcore/dispatch/http11.py with 100% similarity]
http3/dispatch/http2.py [moved from httpcore/dispatch/http2.py with 100% similarity]
http3/dispatch/threaded.py [moved from httpcore/dispatch/threaded.py with 100% similarity]
http3/exceptions.py [moved from httpcore/exceptions.py with 100% similarity]
http3/interfaces.py [moved from httpcore/interfaces.py with 100% similarity]
http3/models.py [moved from httpcore/models.py with 99% similarity]
http3/status_codes.py [moved from httpcore/status_codes.py with 97% similarity]
http3/utils.py [moved from httpcore/utils.py with 100% similarity]
mkdocs.yml [new file with mode: 0644]
scripts/clean
scripts/lint
scripts/publish
scripts/test
setup.py
tests/client/test_async_client.py
tests/client/test_auth.py
tests/client/test_client.py
tests/client/test_cookies.py
tests/client/test_redirects.py
tests/dispatch/test_connection_pools.py
tests/dispatch/test_connections.py
tests/dispatch/test_http2.py
tests/dispatch/test_threaded.py
tests/dispatch/utils.py
tests/models/test_cookies.py
tests/models/test_headers.py
tests/models/test_queryparams.py
tests/models/test_requests.py
tests/models/test_responses.py
tests/models/test_url.py
tests/test_api.py
tests/test_config.py
tests/test_decoders.py
tests/test_timeouts.py

index c044c0568ca4265b14061394874f2a2da67316bc..7abaa28444ccbdd79d1be39d3166892ca22028ac 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,13 +1,13 @@
-# HTTPCore
+# HTTP3
 
-<a href="https://travis-ci.org/encode/httpcore">
-    <img src="https://travis-ci.org/encode/httpcore.svg?branch=master" alt="Build Status">
+<a href="https://travis-ci.org/encode/http3">
+    <img src="https://travis-ci.org/encode/http3.svg?branch=master" alt="Build Status">
 </a>
-<a href="https://codecov.io/gh/encode/httpcore">
-    <img src="https://codecov.io/gh/encode/httpcore/branch/master/graph/badge.svg" alt="Coverage">
+<a href="https://codecov.io/gh/encode/http3">
+    <img src="https://codecov.io/gh/encode/http3/branch/master/graph/badge.svg" alt="Coverage">
 </a>
-<a href="https://pypi.org/project/httpcore/">
-    <img src="https://badge.fury.io/py/httpcore.svg" alt="Package version">
+<a href="https://pypi.org/project/http3/">
+    <img src="https://badge.fury.io/py/http3.svg" alt="Package version">
 </a>
 
 ## Feature support
@@ -41,8 +41,8 @@ Plus all the standard features of requests...
 Making a request:
 
 ```python
->>> import httpcore
->>> client = httpcore.Client()
+>>> import http3
+>>> client = http3.Client()
 >>> response = client.get('https://example.com')
 >>> response.status_code
 <HTTPStatus.OK: 200>
@@ -57,8 +57,8 @@ Alternatively, async requests:
 **Note**: Use `ipython` to try this from the console, since it supports `await`.
 
 ```python
->>> import httpcore
->>> client = httpcore.AsyncClient()
+>>> import http3
+>>> client = http3.AsyncClient()
 >>> response = await client.get('https://example.com')
 >>> response.status_code
 <StatusCode.OK: 200>
@@ -93,7 +93,7 @@ inspiration around the lower level networking details.
 *An HTTP client, with connection pooling, redirects, cookie persistence, etc.*
 
 ```python
->>> client = Client()
+>>> client = http3.Client()
 >>> response = client.get('https://example.org')
 ```
 
@@ -140,7 +140,7 @@ inspiration around the lower level networking details.
 what gets sent over the wire.*
 
 ```python
->>> request = Request("GET", "https://example.org", headers={'host': 'example.org'})
+>>> request = http3.Request("GET", "https://example.org", headers={'host': 'example.org'})
 >>> response = client.send(request)
 ```
 
diff --git a/docs/api.md b/docs/api.md
new file mode 100644 (file)
index 0000000..40d90dd
--- /dev/null
@@ -0,0 +1,146 @@
+# Developer Interface
+
+## Main Interface
+
+* `get(url, [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
+* `options(url, [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
+* `head(url, [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
+* `post(url, [data], [json], [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
+* `put(url, [data], [json], [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
+* `patch(url, [data], [json], [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
+* `delete(url, [data], [json], [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
+* `request(method, url, [data], [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
+
+## `Client`
+
+*An HTTP client, with connection pooling, redirects, cookie persistence, etc.*
+
+```python
+>>> client = http3.Client()
+>>> response = client.get('https://example.org')
+```
+
+* `def __init__([auth], [cookies], [verify], [cert], [timeout], [pool_limits], [max_redirects], [dispatch])`
+* `def .get(url, [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
+* `def .options(url, [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
+* `def .head(url, [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
+* `def .post(url, [data], [json], [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
+* `def .put(url, [data], [json], [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
+* `def .patch(url, [data], [json], [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
+* `def .delete(url, [data], [json], [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
+* `def .request(method, url, [data], [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
+* `def .send(request, [stream], [allow_redirects], [verify], [cert], [timeout])`
+* `def .close()`
+
+## `Response`
+
+*An HTTP response.*
+
+* `def __init__(...)`
+* `.status_code` - **int** *(Typically a `StatusCode` IntEnum.)*
+* `.reason_phrase` - **str**
+* `.protocol` - `"HTTP/2"` or `"HTTP/1.1"`
+* `.url` - **URL**
+* `.headers` - **Headers**
+* `.content` - **bytes**
+* `.text` - **str**
+* `.encoding` - **str**
+* `.is_redirect` - **bool**
+* `.request` - **Request**
+* `.cookies` - **Cookies**
+* `.history` - **List[Response]**
+* `def .raise_for_status()` - **None**
+* `def .json()` - **Any**
+* `def .read()` - **bytes**
+* `def .stream()` - **bytes iterator**
+* `def .raw()` - **bytes iterator**
+* `def .close()` - **None**
+* `def .next()` - **Response**
+
+## `Request`
+
+*An HTTP request. Can be constructed explicitly for more control over exactly
+what gets sent over the wire.*
+
+```python
+>>> request = http3.Request("GET", "https://example.org", headers={'host': 'example.org'})
+>>> response = client.send(request)
+```
+
+* `def __init__(method, url, [params], [data], [json], [headers], [cookies])`
+* `.method` - **str**
+* `.url` - **URL**
+* `.content` - **byte** or **byte async iterator**
+* `.headers` - **Headers**
+* `.cookies` - **Cookies**
+
+## `URL`
+
+*A normalized, IDNA supporting URL.*
+
+```python
+>>> url = URL("https://example.org/")
+>>> url.host
+'example.org'
+```
+
+* `def __init__(url, allow_relative=False, params=None)`
+* `.scheme` - **str**
+* `.authority` - **str**
+* `.host` - **str**
+* `.port` - **int**
+* `.path` - **str**
+* `.query` - **str**
+* `.full_path` - **str**
+* `.fragment` - **str**
+* `.is_ssl` - **bool**
+* `.origin` - **Origin**
+* `.is_absolute_url` - **bool**
+* `.is_relative_url` - **bool**
+* `def .copy_with([scheme], [authority], [path], [query], [fragment])` - **URL**
+* `def .resolve_with(url)` - **URL**
+
+## `Origin`
+
+*A normalized, IDNA supporting set of scheme/host/port info.*
+
+```python
+>>> Origin('https://example.org') == Origin('HTTPS://EXAMPLE.ORG:443')
+True
+```
+
+* `def __init__(url)`
+* `.is_ssl` - **bool**
+* `.host` - **str**
+* `.port` - **int**
+
+## `Headers`
+
+*A case-insensitive multi-dict.*
+
+```python
+>>> headers = Headers({'Content-Type': 'application/json'})
+>>> headers['content-type']
+'application/json'
+```
+
+* `def __init__(self, headers)`
+
+## `Cookies`
+
+*A dict-like cookie store.*
+
+```python
+>>> cookies = Cookies()
+>>> cookies.set("name", "value", domain="example.org")
+```
+
+* `def __init__(cookies: [dict, Cookies, CookieJar])`
+* `.jar` - **CookieJar**
+* `def extract_cookies(response)`
+* `def set_cookie_header(request)`
+* `def set(name, value, [domain], [path])`
+* `def get(name, [domain], [path])`
+* `def delete(name, [domain], [path])`
+* `def clear([domain], [path])`
+* *Standard mutable mapping interface*
diff --git a/docs/async.md b/docs/async.md
new file mode 100644 (file)
index 0000000..7822d35
--- /dev/null
@@ -0,0 +1,60 @@
+# Async Client
+
+HTTP3 offers a standard synchronous API by default, but also gives you
+the option of an async client if you need it.
+
+Async is a concurrency model that is far more efficient than multi-threading,
+and can provide significant performance benefits and enable the use of
+long-lived network connections such as WebSockets.
+
+If you're working with an async web framework such as Sanic, Starlette, FastAPI,
+Responder or Bocadillo, then you'll also want to use an async client for sending
+outgoing HTTP requests.
+
+## Making Async requests
+
+To make asynchronous requests, you'll need an `AsyncClient`.
+
+```python
+>>> client = http3.AsyncClient()
+>>> r = await client.get('https://www.example.com/')
+```
+
+## API Differences
+
+If you're using streaming responses then there are a few bits of API that
+use async methods:
+
+```python
+>>> client = http3.AsyncClient()
+>>> r = await client.get('https://www.example.com/', stream=True)
+>>> try:
+>>>     async for chunk in r.stream():
+>>>         ...
+>>> finally:
+>>>     await r.close()
+```
+
+The async response methods are:
+
+* `.read()`
+* `.stream()`
+* `.raw()`
+* `.close()`
+
+If you're making parallel requests, then you'll also need to use an async API:
+
+```python
+>>> client = http3.AsyncClient()
+>>> async with client.parallel() as parallel:
+>>>     pending_one = parallel.get('https://example.com/1')
+>>>     pending_two = parallel.get('https://example.com/2')
+>>>     response_one = await pending_one.get_response()
+>>>     response_two = await pending_two.get_response()
+```
+
+The async parallel methods are:
+
+* `.parallel()` *Used as an "async with" context manager.*
+* `.get_response()`
+* `.next_response()`
diff --git a/docs/compatibility.md b/docs/compatibility.md
new file mode 100644 (file)
index 0000000..34d9e5a
--- /dev/null
@@ -0,0 +1,7 @@
+# Requests Compatibility Guide
+
+HTTP3 aims to be compatible with the `requests` API wherever possible.
+
+This documentation outlines places where the API differs...
+
+**TODO**
diff --git a/docs/index.md b/docs/index.md
new file mode 100644 (file)
index 0000000..41c8ee9
--- /dev/null
@@ -0,0 +1,88 @@
+# HTTP3
+
+<a href="https://travis-ci.org/encode/http3">
+    <img src="https://travis-ci.org/encode/http3.svg?branch=master" alt="Build Status">
+</a>
+<a href="https://codecov.io/gh/encode/http3">
+    <img src="https://codecov.io/gh/encode/http3/branch/master/graph/badge.svg" alt="Coverage">
+</a>
+<a href="https://pypi.org/project/http3/">
+    <img src="https://badge.fury.io/py/http3.svg" alt="Package version">
+</a>
+
+HTTP3 is a next-generation HTTP client for Python.
+
+!!! warning
+    This project should be considered as an "alpha" release. It is substantially
+    API complete, but there are still some areas that need more work.
+
+---
+
+Let's get started...
+
+```python
+>>> import http3
+>>> r = http3.get('https://www.example.org/')
+>>> r.status_code
+<StatusCode.OK: 200>
+>>> r.protocol
+'HTTP/2'
+>>> r.headers['content-type']
+'text/html; charset=UTF-8'
+>>> r.text
+'<!doctype html>\n<html>\n<head>\n<title>Example Domain</title>...'
+```
+
+## Features
+
+HTTP3 builds on the well-established usability of `requests`, and gives you:
+
+* A requests-compatible API.
+* HTTP/2 and HTTP/1.1 support.
+* Support for issuing HTTP requests in parallel.
+* Standard synchronous interface, but with `async`/`await` support if you need it.
+* Strict timeouts everywhere.
+* Fully type annotated.
+* 100% test coverage.
+
+Plus all the standard features of `requests`...
+
+* International Domains and URLs
+* Keep-Alive & Connection Pooling
+* Sessions with Cookie Persistence
+* Browser-style SSL Verification
+* Basic/Digest Authentication *Digest is still TODO*
+* Elegant Key/Value Cookies
+* Automatic Decompression
+* Automatic Content Decoding
+* Unicode Response Bodies
+* Multipart File Uploads *TODO*
+* HTTP(S) Proxy Support *TODO*
+* Connection Timeouts
+* Streaming Downloads
+* .netrc Support *TODO*
+* Chunked Requests
+
+## Documentation
+
+For a run-through of all the basics, head over to the [QuickStart](quickstart.md).
+
+For more advanced topics, see the [Parallel Requests](parallel.md) or [Async Client](async.md) documentation.
+
+The [Developer Interface](api.md) provides a comprehensive API reference.
+
+## Dependencies
+
+The HTTP3 project relies on these excellent libraries:
+
+* `h2` - HTTP/2 support.
+* `h11` - HTTP/1.1 support.
+* `certifi` - SSL certificates.
+* `chardet` - Fallback auto-detection for response encoding.
+* `idna` - Internationalized domain name support.
+* `rfc3986` - URL parsing & normalization.
+* `brotlipy` - Decoding for "brotli" compressed responses. *(Optional)*
+
+A huge amount of credit is due to `requests` for the API layout that
+much of this work follows, as well as to `urllib3` for plenty of design
+inspiration around the lower level networking details.
diff --git a/docs/parallel.md b/docs/parallel.md
new file mode 100644 (file)
index 0000000..66d8490
--- /dev/null
@@ -0,0 +1,66 @@
+# Parallel Requests
+
+HTTP3 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.
+
+This has the huge benefit of allowing you to efficiently make parallel HTTP
+requests without having to switch out to using async all the way through.
+
+## Making Parallel Requests
+
+Let's make two outgoing HTTP requests in parallel:
+
+```python
+>>> with http3.parallel() as parallel:
+>>>     pending_one = parallel.get('https://example.com/1')
+>>>     pending_two = parallel.get('https://example.com/2')
+>>>     response_one = pending_one.get_response()
+>>>     response_two = pending_two.get_response()
+```
+
+If we're making lots of outgoing requests, we might not want to deal with the
+responses sequentially, but rather deal with each response that comes back
+as soon as it's available:
+
+```python
+>>> with http3.parallel() as parallel:
+>>>     for counter in range(1, 10):
+>>>         parallel.get(f'https://example.com/{counter}')
+>>>     while parallel.has_pending_responses:
+>>>         r = parallel.next_response()
+```
+
+## Exceptions and Cancellations
+
+The style of using `parallel` blocks ensures that you'll always have well
+defined exception and cancellation behaviours. Request exceptions are only ever
+raised when calling either `get_response` or `next_response`, and any pending
+requests are cancelled on exiting the block.
+
+## Parallel requests with a Client
+
+You can also call `parallel()` from a client instance, which allows you to
+control the authentication or dispatch behaviour for all requests within the
+block.
+
+```python
+>>> client = http3.Client()
+>>> with client.parallel() as parallel:
+>>>     ...
+```
+
+## Async parallel requests
+
+If you're working within an async framework, then you'll want to use a fully
+async API for making requests.
+
+```python
+>>> client = http3.AsyncClient()
+>>> async with client.parallel() as parallel:
+>>>     pending_one = await parallel.get('https://example.com/1')
+>>>     pending_two = await parallel.get('https://example.com/2')
+>>>     response_one = await pending_one.get_response()
+>>>     response_two = await pending_two.get_response()
+```
+
+See [the Async Client documentation](async.md) for more details.
diff --git a/docs/quickstart.md b/docs/quickstart.md
new file mode 100644 (file)
index 0000000..0758725
--- /dev/null
@@ -0,0 +1,270 @@
+# QuickStart
+
+!!! note
+    This page closely follows the layout of the `requests` QuickStart documentation.
+    The `http3` library is designed to be API compatible with `requests` wherever
+    possible.
+
+First start by importing HTTP3:
+
+```
+>>> import http3
+```
+
+Now, let’s try to get a webpage. For this example, let’s get GitHub’s public timeline:
+
+```python
+>>> r = http3.get('https://api.github.com/events')
+```
+
+Similarly, to make an HTTP POST request:
+
+```python
+>>> r = http3.post('https://httpbin.org/post', data={'key': 'value'})
+```
+
+The PUT, DELETE, HEAD, and OPTIONS requests all follow the same style:
+
+```python
+>>> r = http3.put('https://httpbin.org/put', data={'key': 'value'})
+>>> r = http3.delete('https://httpbin.org/delete')
+>>> r = http3.head('https://httpbin.org/get')
+>>> r = http3.options('https://httpbin.org/get')
+```
+
+## Passing Parameters in URLs
+
+To include URL query parameters in the request, use the `params` keyword:
+
+```python
+>>> params = {'key1': 'value1', 'key2': 'value2'}
+>>> r = http3.get('https://httpbin.org/get', params=params)
+```
+
+To see how the values get encoding into the URL string, we can inspect the
+resulting URL that was used to make the request:
+
+```python
+>>> r.url
+URL('https://httpbin.org/get?key2=value2&key1=value1')
+```
+
+You can also pass a list of items as a value:
+
+```python
+>>> params = {'key1': 'value1', 'key2': ['value2', 'value3']}
+>>> r = http3.get('https://httpbin.org/get', params=params)
+>>> r.url
+URL('https://httpbin.org/get?key1=value1&key2=value2&key2=value3')
+```
+
+## Response Content
+
+HTTP3 will automatically handle decoding the response content into unicode text.
+
+```python
+>>> r = http3.get('https://www.example.org/')
+>>> r.text
+'<!doctype html>\n<html>\n<head>\n<title>Example Domain</title>...'
+```
+
+You can inspect what encoding has been used to decode the response.
+
+```python
+>>> r.encoding
+'UTF-8'
+```
+
+If you need to override the standard behavior and explicitly set the encoding to
+use, then you can do that too.
+
+```python
+>>> r.encoding = 'ISO-8859-1'
+```
+
+## Binary Response Content
+
+The response content can also be accessed as bytes, for non-text responses:
+
+```python
+>>> r.content
+b'<!doctype html>\n<html>\n<head>\n<title>Example Domain</title>...'
+```
+
+Any `gzip` and `deflate` HTTP response encodings will automatically
+be decoded for you. If `brotlipy` is installed, then the `brotli` response
+encoding will also be supported.
+
+For example, to create an image from binary data returned by a request, you can use the following code:
+
+```python
+>>> from PIL import Image
+>>> from io import BytesIO
+>>> i = Image.open(BytesIO(r.content))
+```
+
+## JSON Response Content
+
+Often Web API responses will be encoded as JSON.
+
+```python
+>>> r = http3.get('https://api.github.com/events')
+>>> r.json()
+[{u'repository': {u'open_issues': 0, u'url': 'https://github.com/...' ...  }}]
+```
+
+## Custom Headers
+
+To include additional headers in the outgoing request, use the `headers` keyword argument:
+
+```python
+>>> url = 'http://httpbin.org/headers'
+>>> headers = {'user-agent': 'my-app/0.0.1'}
+>>> r = http3.get(url, headers=headers)
+```
+
+## Sending Form Encoded Data
+
+Some types of HTTP requests, such as `POST` and `PUT` requests, can include data
+in the request body. One common way of including that is as form encoded data,
+which is used for HTML forms.
+
+```python
+>>> data = {'key1': 'value1', 'key2': 'value2'}
+>>> r = http3.post("https://httpbin.org/post", data=data)
+>>> print(r.text)
+{
+  ...
+  "form": {
+    "key2": "value2",
+    "key1": "value1"
+  },
+  ...
+}
+```
+
+Form encoded data can also include multiple values form a given key.
+
+```python
+>>> data = {'key1': ['value1', 'value2']}
+>>> r = http3.post("https://httpbin.org/post", data=data)
+>>> print(r.text)
+{
+  ...
+  "form": {
+    "key1": [
+      "value1",
+      "value2"
+    ]
+  },
+  ...
+}
+```
+
+## Sending JSON Encoded Data
+
+Form encoded data is okay if all you need is simple key-value data structure.
+For more complicated data structures you'll often want to use JSON encoding instead.
+
+```python
+>>> data = {'integer': 123, 'boolean': True, 'list': ['a', 'b', 'c']}
+>>> r = http3.post("https://httpbin.org/post", json=data)
+>>> print(r.text)
+{
+  ...
+  "json": {
+    "boolean": true,
+    "integer": 123,
+    "list": [
+      "a",
+      "b",
+      "c"
+    ]
+  },
+  ...
+}
+```
+
+## Sending Binary Request Data
+
+For other encodings you should use either a `bytes` type, or a generator
+that yields `bytes`.
+
+You'll probably also want to set a custom `Content-Type` header when uploading
+binary data.
+
+## Response Status Codes
+
+We can inspect the HTTP status code of the response:
+
+```python
+>>> r = http3.get('https://httpbin.org/get')
+>>> r.status_code
+<StatusCode.OK: 200>
+```
+
+The status code is an integer enum, meaning that the Python representation gives
+use some descriptive information, but the value itself can be used as a regular integer.
+
+```python
+>>> r.status_code == 200
+True
+```
+
+HTTP3 also includes an easy shortcut for accessing status codes by their text phrase.
+
+```python
+>>> r.status_code == requests.codes.OK
+True
+```
+
+We can raise an exception for any Client or Server error responses (4xx or 5xx status codes):
+
+```python
+>>> not_found = http3.get('https://httpbin.org/status/404')
+>>> not_found.status_code
+<StatusCode.NOT_FOUND: 404>
+>>> not_found.raise_for_status()
+Traceback (most recent call last):
+  File "/Users/tomchristie/GitHub/encode/httpcore/http3/models.py", line 776, in raise_for_status
+    raise HttpError(message)
+http3.exceptions.HttpError: 404 Not Found
+```
+
+Any successful response codes will simply return `None` rather than raising an exception.
+
+``` python
+>>> r.raise_for_status()
+```
+
+## Response Headers
+
+The response headers are available as a dictionary-like interface.
+
+```python
+>>> r.headers
+Headers({
+    'content-encoding': 'gzip',
+    'transfer-encoding': 'chunked',
+    'connection': 'close',
+    'server': 'nginx/1.0.4',
+    'x-runtime': '148ms',
+    'etag': '"e1ca502697e5c9317743dc078f67693f"',
+    'content-type': 'application/json'
+})
+```
+
+The `Headers` data type is case-insensitive, so you can use any capitalization.
+
+```python
+>>> r.headers['Content-Type']
+'application/json'
+
+>>> r.headers.get('content-type')
+'application/json'
+```
+
+Multiple values for a single response header are represented as a single comma separated
+value, as per [RFC 7230](https://tools.ietf.org/html/rfc7230#section-3.2):
+
+> A recipient MAY combine multiple header fields with the same field name into one “field-name: field-value” pair, without changing the semantics of the message, by appending each subsequent field value to the combined field value in order, separated by a comma.
similarity index 97%
rename from httpcore/__init__.py
rename to http3/__init__.py
index 8f9cb07c03a13d0b0e568d701755ae0615d82707..79dab8b41adf1c3d1b13999f02162db8ce9e87d9 100644 (file)
@@ -49,4 +49,4 @@ from .models import (
 )
 from .status_codes import StatusCode, codes
 
-__version__ = "0.4.0"
+__version__ = "0.0.1"
similarity index 100%
rename from httpcore/api.py
rename to http3/api.py
similarity index 100%
rename from httpcore/auth.py
rename to http3/auth.py
similarity index 100%
rename from httpcore/client.py
rename to http3/client.py
similarity index 100%
rename from httpcore/concurrency.py
rename to http3/concurrency.py
similarity index 100%
rename from httpcore/config.py
rename to http3/config.py
similarity index 89%
rename from httpcore/decoders.py
rename to http3/decoders.py
index 7f3ef0db89a640c16a54e48b72573b080cfa70a6..b352de253fa712110f177d7e65fe3036f83e8f38 100644 (file)
@@ -6,7 +6,7 @@ See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
 import typing
 import zlib
 
-import httpcore.exceptions
+from .exceptions import DecodingError
 
 try:
     import brotli
@@ -48,13 +48,13 @@ class DeflateDecoder(Decoder):
         try:
             return self.decompressor.decompress(data)
         except zlib.error as exc:
-            raise httpcore.exceptions.DecodingError from exc
+            raise DecodingError from exc
 
     def flush(self) -> bytes:
         try:
             return self.decompressor.flush()
         except zlib.error as exc:  # pragma: nocover
-            raise httpcore.exceptions.DecodingError from exc
+            raise DecodingError from exc
 
 
 class GZipDecoder(Decoder):
@@ -71,13 +71,13 @@ class GZipDecoder(Decoder):
         try:
             return self.decompressor.decompress(data)
         except zlib.error as exc:
-            raise httpcore.exceptions.DecodingError from exc
+            raise DecodingError from exc
 
     def flush(self) -> bytes:
         try:
             return self.decompressor.flush()
         except zlib.error as exc:  # pragma: nocover
-            raise httpcore.exceptions.DecodingError from exc
+            raise DecodingError from exc
 
 
 class BrotliDecoder(Decoder):
@@ -97,14 +97,14 @@ class BrotliDecoder(Decoder):
         try:
             return self.decompressor.decompress(data)
         except brotli.Error as exc:
-            raise httpcore.exceptions.DecodingError from exc
+            raise DecodingError from exc
 
     def flush(self) -> bytes:
         try:
             self.decompressor.finish()
             return b""
         except brotli.Error as exc:  # pragma: nocover
-            raise httpcore.exceptions.DecodingError from exc
+            raise DecodingError from exc
 
 
 class MultiDecoder(Decoder):
similarity index 100%
rename from httpcore/exceptions.py
rename to http3/exceptions.py
similarity index 100%
rename from httpcore/interfaces.py
rename to http3/interfaces.py
similarity index 99%
rename from httpcore/models.py
rename to http3/models.py
index eb610801bc4f9a3da62cd8a91e189588a634bf0c..6b22674b19b2e8d6cca384ac26cb606e5af3abb4 100644 (file)
@@ -509,7 +509,7 @@ class BaseRequest:
         has_accept_encoding = "accept-encoding" in self.headers
 
         if not has_user_agent:
-            auto_headers.append((b"user-agent", b"httpcore"))
+            auto_headers.append((b"user-agent", b"http3"))
         if not has_accept:
             auto_headers.append((b"accept", b"*/*"))
         if not has_content_length:
similarity index 97%
rename from httpcore/status_codes.py
rename to http3/status_codes.py
index b839dcfe2d02c216255d3398de631bb9a9f87449..eb5e7cebc5d73d711bca79fe582eaa88a9aeeb60 100644 (file)
@@ -127,3 +127,7 @@ class StatusCode(IntEnum):
 
 
 codes = StatusCode
+
+# Include lower-case styles for `requests` compatability.
+for code in codes:
+    setattr(codes, code._name_.lower(), int(code))
similarity index 100%
rename from httpcore/utils.py
rename to http3/utils.py
diff --git a/mkdocs.yml b/mkdocs.yml
new file mode 100644 (file)
index 0000000..2e80f34
--- /dev/null
@@ -0,0 +1,21 @@
+site_name: HTTP3
+site_description: The next generation HTTP client.
+
+theme:
+    name: 'material'
+
+repo_name: encode/http3
+repo_url: https://github.com/encode/http3
+edit_uri: ""
+
+nav:
+    - Introduction: 'index.md'
+    - QuickStart: 'quickstart.md'
+    - Parallel Requests: 'parallel.md'
+    - Async Client: 'async.md'
+    - Requests Compatibility: 'compatibility.md'
+    - Developer Interface: 'api.md'
+
+markdown_extensions:
+  - admonition
+  - codehilite
index 3a639f5e01355e1aa474cca90e071a37bf23cd8a..bd133afe5c23c46af68f917ca15475b8da0049d3 100755 (executable)
@@ -9,6 +9,6 @@ fi
 if [ -d 'htmlcov' ] ; then
     rm -r htmlcov
 fi
-if [ -d 'httpcore.egg-info' ] ; then
-    rm -r httpcore.egg-info
+if [ -d 'http3.egg-info' ] ; then
+    rm -r http3.egg-info
 fi
index 3ce972391e3584a88ef6c4989a8eecefbc5c343d..89e1e93aad4196e8d415a469967e1844228c5e65 100755 (executable)
@@ -7,9 +7,9 @@ fi
 
 set -x
 
-${PREFIX}autoflake --in-place --recursive httpcore tests
-${PREFIX}black httpcore tests
-${PREFIX}isort --multi-line=3 --trailing-comma --force-grid-wrap=0 --combine-as --line-width 88 --recursive --apply httpcore tests
-${PREFIX}mypy httpcore --ignore-missing-imports --disallow-untyped-defs
+${PREFIX}autoflake --in-place --recursive http3 tests
+${PREFIX}black http3 tests
+${PREFIX}isort --multi-line=3 --trailing-comma --force-grid-wrap=0 --combine-as --line-width 88 --recursive --apply http3 tests
+${PREFIX}mypy http3 --ignore-missing-imports --disallow-untyped-defs
 
 scripts/clean
index 73ccae76baf9eeede08f8bc9462989db48cd3707..9ec45d54536b6b2e694aa0900e2603d0d57a0477 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh -e
 
-export PACKAGE="httpcore"
+export PACKAGE="http3"
 export VERSION=`cat ${PACKAGE}/__init__.py | grep __version__ | sed "s/__version__ = //" | sed "s/'//g"`
 export PREFIX=""
 if [ -d 'venv' ] ; then
index 63ad08a6a2e75aa6d0b0973cecbab0ab95163128..fe000e2f53c5c6b56c7e71a25b441dfcdf0d5d3b 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh -e
 
-export PACKAGE="httpcore"
+export PACKAGE="http3"
 export PREFIX=""
 if [ -d 'venv' ] ; then
     export PREFIX="venv/bin/"
index 77e581cba9cf5dcf874e04fbf71c738d1e9b4939..69fcde0a6ff71ba5801489ace87bbfc308cdd54b 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -35,17 +35,17 @@ def get_packages(package):
 
 
 setup(
-    name="httpcore",
+    name="http3",
     python_requires=">=3.6",
-    version=get_version("httpcore"),
-    url="https://github.com/encode/httpcore",
+    version=get_version("http3"),
+    url="https://github.com/encode/http3",
     license="BSD",
-    description="...",
+    description="The next generation HTTP client.",
     long_description=get_long_description(),
     long_description_content_type="text/markdown",
     author="Tom Christie",
     author_email="tom@tomchristie.com",
-    packages=get_packages("httpcore"),
+    packages=get_packages("http3"),
     data_files=[("", ["LICENSE.md"])],
     install_requires=[
         "certifi",
index 01f458532f0d7c39d949ea9a6e98096131725fcc..bf7fe5730148c4f513ea3cabfa879452f80a2c01 100644 (file)
@@ -1,12 +1,12 @@
 import pytest
 
-import httpcore
+import http3
 
 
 @pytest.mark.asyncio
 async def test_get(server):
     url = "http://127.0.0.1:8000/"
-    async with httpcore.AsyncClient() as client:
+    async with http3.AsyncClient() as client:
         response = await client.get(url)
     assert response.status_code == 200
     assert response.text == "Hello, world!"
@@ -18,7 +18,7 @@ async def test_get(server):
 @pytest.mark.asyncio
 async def test_post(server):
     url = "http://127.0.0.1:8000/"
-    async with httpcore.AsyncClient() as client:
+    async with http3.AsyncClient() as client:
         response = await client.post(url, data=b"Hello, world!")
     assert response.status_code == 200
 
@@ -26,14 +26,14 @@ async def test_post(server):
 @pytest.mark.asyncio
 async def test_post_json(server):
     url = "http://127.0.0.1:8000/"
-    async with httpcore.AsyncClient() as client:
+    async with http3.AsyncClient() as client:
         response = await client.post(url, json={"text": "Hello, world!"})
     assert response.status_code == 200
 
 
 @pytest.mark.asyncio
 async def test_stream_response(server):
-    async with httpcore.AsyncClient() as client:
+    async with http3.AsyncClient() as client:
         response = await client.request("GET", "http://127.0.0.1:8000/", stream=True)
     assert response.status_code == 200
     body = await response.read()
@@ -43,10 +43,10 @@ async def test_stream_response(server):
 
 @pytest.mark.asyncio
 async def test_access_content_stream_response(server):
-    async with httpcore.AsyncClient() as client:
+    async with http3.AsyncClient() as client:
         response = await client.request("GET", "http://127.0.0.1:8000/", stream=True)
     assert response.status_code == 200
-    with pytest.raises(httpcore.ResponseNotRead):
+    with pytest.raises(http3.ResponseNotRead):
         response.content
 
 
@@ -56,7 +56,7 @@ async def test_stream_request(server):
         yield b"Hello, "
         yield b"world!"
 
-    async with httpcore.AsyncClient() as client:
+    async with http3.AsyncClient() as client:
         response = await client.request(
             "POST", "http://127.0.0.1:8000/", data=hello_world()
         )
@@ -65,14 +65,14 @@ async def test_stream_request(server):
 
 @pytest.mark.asyncio
 async def test_raise_for_status(server):
-    async with httpcore.AsyncClient() as client:
+    async with http3.AsyncClient() as client:
         for status_code in (200, 400, 404, 500, 505):
             response = await client.request(
                 "GET", f"http://127.0.0.1:8000/status/{status_code}"
             )
 
             if 400 <= status_code < 600:
-                with pytest.raises(httpcore.exceptions.HttpError):
+                with pytest.raises(http3.exceptions.HttpError):
                     response.raise_for_status()
             else:
                 assert response.raise_for_status() is None
@@ -81,7 +81,7 @@ async def test_raise_for_status(server):
 @pytest.mark.asyncio
 async def test_options(server):
     url = "http://127.0.0.1:8000/"
-    async with httpcore.AsyncClient() as client:
+    async with http3.AsyncClient() as client:
         response = await client.options(url)
     assert response.status_code == 200
     assert response.text == "Hello, world!"
@@ -90,7 +90,7 @@ async def test_options(server):
 @pytest.mark.asyncio
 async def test_head(server):
     url = "http://127.0.0.1:8000/"
-    async with httpcore.AsyncClient() as client:
+    async with http3.AsyncClient() as client:
         response = await client.head(url)
     assert response.status_code == 200
     assert response.text == ""
@@ -99,7 +99,7 @@ async def test_head(server):
 @pytest.mark.asyncio
 async def test_put(server):
     url = "http://127.0.0.1:8000/"
-    async with httpcore.AsyncClient() as client:
+    async with http3.AsyncClient() as client:
         response = await client.put(url, data=b"Hello, world!")
     assert response.status_code == 200
 
@@ -107,7 +107,7 @@ async def test_put(server):
 @pytest.mark.asyncio
 async def test_patch(server):
     url = "http://127.0.0.1:8000/"
-    async with httpcore.AsyncClient() as client:
+    async with http3.AsyncClient() as client:
         response = await client.patch(url, data=b"Hello, world!")
     assert response.status_code == 200
 
@@ -115,7 +115,7 @@ async def test_patch(server):
 @pytest.mark.asyncio
 async def test_delete(server):
     url = "http://127.0.0.1:8000/"
-    async with httpcore.AsyncClient() as client:
+    async with http3.AsyncClient() as client:
         response = await client.delete(url)
     assert response.status_code == 200
     assert response.text == "Hello, world!"
@@ -127,7 +127,7 @@ async def test_100_continue(server):
     headers = {"Expect": "100-continue"}
     data = b"Echo request body"
 
-    async with httpcore.AsyncClient() as client:
+    async with http3.AsyncClient() as client:
         response = await client.post(url, headers=headers, data=data)
 
     assert response.status_code == 200
index 17993383a9f904012c1fe4e05ba408bc3476e0f6..597aae7771b6408a3300fa7fdc855f1417d2c4b6 100644 (file)
@@ -2,7 +2,7 @@ import json
 
 import pytest
 
-from httpcore import (
+from http3 import (
     URL,
     AsyncDispatcher,
     AsyncRequest,
index f3663f691685c0af44f39c8cc70f1c26034d45c9..d8e8f4a07cddd280f15deddd485b57e1ee7b76eb 100644 (file)
@@ -3,7 +3,7 @@ import functools
 
 import pytest
 
-import httpcore
+import http3
 
 
 def threadpool(func):
@@ -26,15 +26,15 @@ def threadpool(func):
 @threadpool
 def test_get(server):
     url = "http://127.0.0.1:8000/"
-    with httpcore.Client() as http:
+    with http3.Client() as http:
         response = http.get(url)
     assert response.status_code == 200
-    assert response.url == httpcore.URL(url)
+    assert response.url == http3.URL(url)
     assert response.content == b"Hello, world!"
     assert response.text == "Hello, world!"
     assert response.protocol == "HTTP/1.1"
     assert response.encoding == "iso-8859-1"
-    assert response.request.url == httpcore.URL(url)
+    assert response.request.url == http3.URL(url)
     assert response.headers
     assert response.is_redirect is False
     assert repr(response) == "<Response(200, 'OK')>"
@@ -42,7 +42,7 @@ def test_get(server):
 
 @threadpool
 def test_post(server):
-    with httpcore.Client() as http:
+    with http3.Client() as http:
         response = http.post("http://127.0.0.1:8000/", data=b"Hello, world!")
     assert response.status_code == 200
     assert response.reason_phrase == "OK"
@@ -50,7 +50,7 @@ def test_post(server):
 
 @threadpool
 def test_post_json(server):
-    with httpcore.Client() as http:
+    with http3.Client() as http:
         response = http.post("http://127.0.0.1:8000/", json={"text": "Hello, world!"})
     assert response.status_code == 200
     assert response.reason_phrase == "OK"
@@ -58,7 +58,7 @@ def test_post_json(server):
 
 @threadpool
 def test_stream_response(server):
-    with httpcore.Client() as http:
+    with http3.Client() as http:
         response = http.get("http://127.0.0.1:8000/", stream=True)
     assert response.status_code == 200
     content = response.read()
@@ -67,7 +67,7 @@ def test_stream_response(server):
 
 @threadpool
 def test_stream_iterator(server):
-    with httpcore.Client() as http:
+    with http3.Client() as http:
         response = http.get("http://127.0.0.1:8000/", stream=True)
     assert response.status_code == 200
     body = b""
@@ -78,7 +78,7 @@ def test_stream_iterator(server):
 
 @threadpool
 def test_raw_iterator(server):
-    with httpcore.Client() as http:
+    with http3.Client() as http:
         response = http.get("http://127.0.0.1:8000/", stream=True)
     assert response.status_code == 200
     body = b""
@@ -90,14 +90,14 @@ def test_raw_iterator(server):
 
 @threadpool
 def test_raise_for_status(server):
-    with httpcore.Client() as client:
+    with http3.Client() as client:
         for status_code in (200, 400, 404, 500, 505):
             response = client.request(
                 "GET", "http://127.0.0.1:8000/status/{}".format(status_code)
             )
 
             if 400 <= status_code < 600:
-                with pytest.raises(httpcore.exceptions.HttpError):
+                with pytest.raises(http3.exceptions.HttpError):
                     response.raise_for_status()
             else:
                 assert response.raise_for_status() is None
@@ -105,7 +105,7 @@ def test_raise_for_status(server):
 
 @threadpool
 def test_options(server):
-    with httpcore.Client() as http:
+    with http3.Client() as http:
         response = http.options("http://127.0.0.1:8000/")
     assert response.status_code == 200
     assert response.reason_phrase == "OK"
@@ -113,7 +113,7 @@ def test_options(server):
 
 @threadpool
 def test_head(server):
-    with httpcore.Client() as http:
+    with http3.Client() as http:
         response = http.head("http://127.0.0.1:8000/")
     assert response.status_code == 200
     assert response.reason_phrase == "OK"
@@ -121,7 +121,7 @@ def test_head(server):
 
 @threadpool
 def test_put(server):
-    with httpcore.Client() as http:
+    with http3.Client() as http:
         response = http.put("http://127.0.0.1:8000/", data=b"Hello, world!")
     assert response.status_code == 200
     assert response.reason_phrase == "OK"
@@ -129,7 +129,7 @@ def test_put(server):
 
 @threadpool
 def test_patch(server):
-    with httpcore.Client() as http:
+    with http3.Client() as http:
         response = http.patch("http://127.0.0.1:8000/", data=b"Hello, world!")
     assert response.status_code == 200
     assert response.reason_phrase == "OK"
@@ -137,7 +137,7 @@ def test_patch(server):
 
 @threadpool
 def test_delete(server):
-    with httpcore.Client() as http:
+    with http3.Client() as http:
         response = http.delete("http://127.0.0.1:8000/")
     assert response.status_code == 200
     assert response.reason_phrase == "OK"
index 5cbb380921d6dba42e2850a4a846c405516a67e3..f4f7ceb68ff44f6710a326afdd81848bd8b81837 100644 (file)
@@ -3,7 +3,7 @@ from http.cookiejar import Cookie, CookieJar
 
 import pytest
 
-from httpcore import (
+from http3 import (
     URL,
     AsyncDispatcher,
     AsyncRequest,
index 3f5168974a01d517026f9b2177b2f07a6d978d8f..01c0471c7094c3f6e839bf418e85e6b6c16bd3cf 100644 (file)
@@ -3,7 +3,7 @@ from urllib.parse import parse_qs
 
 import pytest
 
-from httpcore import (
+from http3 import (
     URL,
     AsyncClient,
     AsyncDispatcher,
index b8049c70b835bdf126625cd2ed5ebe737d4210da..00e0a7e4fcddd42e9051193e1c37ef42e1c89f7a 100644 (file)
@@ -1,6 +1,6 @@
 import pytest
 
-import httpcore
+import http3
 
 
 @pytest.mark.asyncio
@@ -8,7 +8,7 @@ async def test_keepalive_connections(server):
     """
     Connections should default to staying in a keep-alive state.
     """
-    async with httpcore.ConnectionPool() as http:
+    async with http3.ConnectionPool() as http:
         response = await http.request("GET", "http://127.0.0.1:8000/")
         await response.read()
         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.
     """
-    async with httpcore.ConnectionPool() as http:
+    async with http3.ConnectionPool() as http:
         response = await http.request("GET", "http://127.0.0.1:8000/")
         await response.read()
         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.
     """
-    pool_limits = httpcore.PoolLimits(soft_limit=1)
+    pool_limits = http3.PoolLimits(soft_limit=1)
 
-    async with httpcore.ConnectionPool(pool_limits=pool_limits) as http:
+    async with http3.ConnectionPool(pool_limits=pool_limits) as http:
         response = await http.request("GET", "http://127.0.0.1:8000/")
         await response.read()
         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.
     """
-    async with httpcore.ConnectionPool() as http:
+    async with http3.ConnectionPool() as http:
         response = await http.request("GET", "http://127.0.0.1:8000/")
         assert len(http.active_connections) == 1
         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.
     """
-    async with httpcore.ConnectionPool() as http:
+    async with http3.ConnectionPool() as http:
         response_a = await http.request("GET", "http://127.0.0.1:8000/")
         assert len(http.active_connections) == 1
         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.
     """
     headers = [(b"connection", b"close")]
-    async with httpcore.ConnectionPool() as http:
+    async with http3.ConnectionPool() as http:
         response = await http.request("GET", "http://127.0.0.1:8000/", headers=headers)
         await response.read()
         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.
     """
-    async with httpcore.ConnectionPool() as http:
+    async with http3.ConnectionPool() as http:
         response = await http.request("GET", "http://127.0.0.1:8000/")
         await response.read()
         await response.close()
@@ -126,7 +126,7 @@ async def test_premature_response_close(server):
     """
     A premature close should close the connection.
     """
-    async with httpcore.ConnectionPool() as http:
+    async with http3.ConnectionPool() as http:
         response = await http.request("GET", "http://127.0.0.1:8000/")
         await response.close()
         assert len(http.active_connections) == 0
index 4b267f4fd97557988c49bdee11febde09be5a026..639ed91723782d06bfc901bd76507fa91b405954 100644 (file)
@@ -1,6 +1,6 @@
 import pytest
 
-from httpcore import HTTPConnection, Request, SSLConfig
+from http3 import HTTPConnection, Request, SSLConfig
 
 
 @pytest.mark.asyncio
index e19bb1cf811cb146844568a4b2032b067ce34359..b87e528a3a5a370d6415341d3037d25c3823b2d3 100644 (file)
@@ -2,7 +2,7 @@ import json
 
 import pytest
 
-from httpcore import Client, Response
+from http3 import Client, Response
 
 from .utils import MockHTTP2Backend
 
index d177dbba96a99b24a88a45bccb21f1a38d9ac8ea..04a9a2e66005996c5dad532e9f7f8ca0714875c9 100644 (file)
@@ -2,7 +2,7 @@ import json
 
 import pytest
 
-from httpcore import (
+from http3 import (
     CertTypes,
     Client,
     Dispatcher,
index 651fddf8c1d7426603a3c71f66fb5573c401c9b0..5a0203e135b58104d1a7ab0e6aa1f65ebdcd2c67 100644 (file)
@@ -5,7 +5,7 @@ import h2.config
 import h2.connection
 import h2.events
 
-from httpcore import (
+from http3 import (
     AsyncioBackend,
     BaseReader,
     BaseWriter,
index 705245d6962deba7bf43e0da93ca4429ed3a18b2..57b1412ccf38a3146dca75ad0329d96fd5680fd5 100644 (file)
@@ -1,6 +1,6 @@
 import pytest
 
-from httpcore import CookieConflict, Cookies
+from http3 import CookieConflict, Cookies
 
 
 def test_cookies():
index ffcde8e1b8e1d47794699dae1fd9def0b94b5396..c6b755d1d1344af5ddc3db8ffc7aacf0698b54b7 100644 (file)
@@ -1,8 +1,8 @@
-import httpcore
+import http3
 
 
 def test_headers():
-    h = httpcore.Headers([("a", "123"), ("a", "456"), ("b", "789")])
+    h = http3.Headers([("a", "123"), ("a", "456"), ("b", "789")])
     assert "a" in h
     assert "A" in h
     assert "b" in h
@@ -18,10 +18,10 @@ def test_headers():
     assert list(h) == ["a", "a", "b"]
     assert dict(h) == {"a": "123, 456", "b": "789"}
     assert repr(h) == "Headers([('a', '123'), ('a', '456'), ('b', '789')])"
-    assert h == httpcore.Headers([("a", "123"), ("b", "789"), ("a", "456")])
+    assert h == http3.Headers([("a", "123"), ("b", "789"), ("a", "456")])
     assert h != [("a", "123"), ("A", "456"), ("b", "789")]
 
-    h = httpcore.Headers({"a": "123", "b": "789"})
+    h = http3.Headers({"a": "123", "b": "789"})
     assert h["A"] == "123"
     assert h["B"] == "789"
     assert h.raw == [(b"a", b"123"), (b"b", b"789")]
@@ -29,7 +29,7 @@ def test_headers():
 
 
 def test_header_mutations():
-    h = httpcore.Headers()
+    h = http3.Headers()
     assert dict(h) == {}
     h["a"] = "1"
     assert dict(h) == {"a": "1"}
@@ -45,31 +45,31 @@ def test_header_mutations():
 
 
 def test_copy_headers():
-    headers = httpcore.Headers({"custom": "example"})
-    headers_copy = httpcore.Headers(headers)
+    headers = http3.Headers({"custom": "example"})
+    headers_copy = http3.Headers(headers)
     assert headers == headers_copy
 
 
 def test_headers_insert_retains_ordering():
-    headers = httpcore.Headers({"a": "a", "b": "b", "c": "c"})
+    headers = http3.Headers({"a": "a", "b": "b", "c": "c"})
     headers["b"] = "123"
     assert list(headers.values()) == ["a", "123", "c"]
 
 
 def test_headers_insert_appends_if_new():
-    headers = httpcore.Headers({"a": "a", "b": "b", "c": "c"})
+    headers = http3.Headers({"a": "a", "b": "b", "c": "c"})
     headers["d"] = "123"
     assert list(headers.values()) == ["a", "b", "c", "123"]
 
 
 def test_headers_insert_removes_all_existing():
-    headers = httpcore.Headers([("a", "123"), ("a", "456")])
+    headers = http3.Headers([("a", "123"), ("a", "456")])
     headers["a"] = "789"
     assert dict(headers) == {"a": "789"}
 
 
 def test_headers_delete_removes_all_existing():
-    headers = httpcore.Headers([("a", "123"), ("a", "456")])
+    headers = http3.Headers([("a", "123"), ("a", "456")])
     del headers["a"]
     assert dict(headers) == {}
 
@@ -78,7 +78,7 @@ def test_headers_dict_repr():
     """
     Headers should display with a dict repr by default.
     """
-    headers = httpcore.Headers({"custom": "example"})
+    headers = http3.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 = httpcore.Headers({b"custom": "example ☃".encode("utf-8")})
+    headers = http3.Headers({b"custom": "example ☃".encode("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 = httpcore.Headers([("custom", "example 1"), ("custom", "example 2")])
+    headers = http3.Headers([("custom", "example 1"), ("custom", "example 2")])
     assert (
         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.
     """
     raw_headers = [(b"Custom", b"Example")]
-    headers = httpcore.Headers(raw_headers)
+    headers = http3.Headers(raw_headers)
     assert dict(headers) == {"custom": "Example"}
     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.
     """
     raw_headers = [(b"Custom", "Code point: ☃".encode("utf-8"))]
-    headers = httpcore.Headers(raw_headers)
+    headers = http3.Headers(raw_headers)
     assert dict(headers) == {"custom": "Code point: ☃"}
     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.
     """
     raw_headers = [(b"Custom", "Code point: ÿ".encode("iso-8859-1"))]
-    headers = httpcore.Headers(raw_headers)
+    headers = http3.Headers(raw_headers)
     assert dict(headers) == {"custom": "Code point: ÿ"}
     assert headers.encoding == "iso-8859-1"
 
@@ -136,7 +136,7 @@ def test_headers_decode_explicit_encoding():
     particular decoding.
     """
     raw_headers = [(b"Custom", "Code point: ☃".encode("utf-8"))]
-    headers = httpcore.Headers(raw_headers)
+    headers = http3.Headers(raw_headers)
     headers.encoding = "iso-8859-1"
     assert dict(headers) == {"custom": "Code point: â\x98\x83"}
     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'.
     """
-    h = httpcore.Headers([("set-cookie", "a, b"), ("set-cookie", "c")])
+    h = http3.Headers([("set-cookie", "a, b"), ("set-cookie", "c")])
     h.getlist("Set-Cookie") == ["a, b", "b"]
 
-    h = httpcore.Headers([("vary", "a, b"), ("vary", "c")])
+    h = http3.Headers([("vary", "a, b"), ("vary", "c")])
     h.getlist("Vary") == ["a", "b", "c"]
index 90e4a4b7faa8d47f13f456dc5c64437ae45b0247..369d43ce62fb7572eb65f39a659ef64d63174be5 100644 (file)
@@ -1,4 +1,4 @@
-from httpcore import QueryParams
+from http3 import QueryParams
 
 
 def test_queryparams():
index 79cbba36e802b806c42e059146582cff362e301e..b5126bc70042782b2a730087b479a9cb18912e9b 100644 (file)
@@ -1,32 +1,32 @@
 import pytest
 
-import httpcore
+import http3
 
 
 def test_request_repr():
-    request = httpcore.Request("GET", "http://example.org")
+    request = http3.Request("GET", "http://example.org")
     assert repr(request) == "<Request('GET', 'http://example.org')>"
 
 
 def test_no_content():
-    request = httpcore.Request("GET", "http://example.org")
+    request = http3.Request("GET", "http://example.org")
     assert "Content-Length" not in request.headers
 
 
 def test_content_length_header():
-    request = httpcore.Request("POST", "http://example.org", data=b"test 123")
+    request = http3.Request("POST", "http://example.org", data=b"test 123")
     assert request.headers["Content-Length"] == "8"
 
 
 def test_url_encoded_data():
-    for RequestClass in (httpcore.Request, httpcore.AsyncRequest):
+    for RequestClass in (http3.Request, http3.AsyncRequest):
         request = RequestClass("POST", "http://example.org", data={"test": "123"})
         assert request.headers["Content-Type"] == "application/x-www-form-urlencoded"
         assert request.content == b"test=123"
 
 
 def test_json_encoded_data():
-    for RequestClass in (httpcore.Request, httpcore.AsyncRequest):
+    for RequestClass in (http3.Request, http3.AsyncRequest):
         request = RequestClass("POST", "http://example.org", json={"test": 123})
         assert request.headers["Content-Type"] == "application/json"
         assert request.content == b'{"test": 123}'
@@ -38,7 +38,7 @@ def test_transfer_encoding_header():
 
     data = streaming_body(b"test 123")
 
-    request = httpcore.Request("POST", "http://example.org", data=data)
+    request = http3.Request("POST", "http://example.org", data=data)
     assert "Content-Length" not in request.headers
     assert request.headers["Transfer-Encoding"] == "chunked"
 
@@ -46,14 +46,14 @@ def test_transfer_encoding_header():
 def test_override_host_header():
     headers = {"host": "1.2.3.4:80"}
 
-    request = httpcore.Request("GET", "http://example.org", headers=headers)
+    request = http3.Request("GET", "http://example.org", headers=headers)
     assert request.headers["Host"] == "1.2.3.4:80"
 
 
 def test_override_accept_encoding_header():
     headers = {"Accept-Encoding": "identity"}
 
-    request = httpcore.Request("GET", "http://example.org", headers=headers)
+    request = http3.Request("GET", "http://example.org", headers=headers)
     assert request.headers["Accept-Encoding"] == "identity"
 
 
@@ -64,30 +64,30 @@ def test_override_content_length_header():
     data = streaming_body(b"test 123")
     headers = {"Content-Length": "8"}
 
-    request = httpcore.Request("POST", "http://example.org", data=data, headers=headers)
+    request = http3.Request("POST", "http://example.org", data=data, headers=headers)
     assert request.headers["Content-Length"] == "8"
 
 
 def test_url():
     url = "http://example.org"
-    request = httpcore.Request("GET", url)
+    request = http3.Request("GET", url)
     assert request.url.scheme == "http"
     assert request.url.port == 80
     assert request.url.full_path == "/"
 
     url = "https://example.org/abc?foo=bar"
-    request = httpcore.Request("GET", url)
+    request = http3.Request("GET", url)
     assert request.url.scheme == "https"
     assert request.url.port == 443
     assert request.url.full_path == "/abc?foo=bar"
 
 
 def test_invalid_urls():
-    with pytest.raises(httpcore.InvalidURL):
-        httpcore.Request("GET", "example.org")
+    with pytest.raises(http3.InvalidURL):
+        http3.Request("GET", "example.org")
 
-    with pytest.raises(httpcore.InvalidURL):
-        httpcore.Request("GET", "invalid://example.org")
+    with pytest.raises(http3.InvalidURL):
+        http3.Request("GET", "invalid://example.org")
 
-    with pytest.raises(httpcore.InvalidURL):
-        httpcore.Request("GET", "http:///foo")
+    with pytest.raises(http3.InvalidURL):
+        http3.Request("GET", "http:///foo")
index f2d080ffc81cf82a4b0c679d7b78a1639e4028df..140d7f341879bff6e38c381fea4b9575b4e116b7 100644 (file)
@@ -1,6 +1,6 @@
 import pytest
 
-import httpcore
+import http3
 
 
 def streaming_body():
@@ -14,14 +14,14 @@ async def async_streaming_body():
 
 
 def test_response():
-    response = httpcore.Response(200, content=b"Hello, world!")
+    response = http3.Response(200, content=b"Hello, world!")
     assert response.status_code == 200
     assert response.reason_phrase == "OK"
     assert response.text == "Hello, world!"
 
 
 def test_response_repr():
-    response = httpcore.Response(200, content=b"Hello, world!")
+    response = http3.Response(200, content=b"Hello, world!")
     assert repr(response) == "<Response(200, 'OK')>"
 
 
@@ -31,7 +31,7 @@ def test_response_content_type_encoding():
     """
     headers = {"Content-Type": "text-plain; charset=latin-1"}
     content = "Latin 1: ÿ".encode("latin-1")
-    response = httpcore.Response(200, content=content, headers=headers)
+    response = http3.Response(200, content=content, headers=headers)
     assert response.text == "Latin 1: ÿ"
     assert response.encoding == "latin-1"
 
@@ -41,7 +41,7 @@ def test_response_autodetect_encoding():
     Autodetect encoding if there is no charset info in a Content-Type header.
     """
     content = "おはようございます。".encode("EUC-JP")
-    response = httpcore.Response(200, content=content)
+    response = http3.Response(200, content=content)
     assert response.text == "おはようございます。"
     assert response.encoding == "EUC-JP"
 
@@ -52,7 +52,7 @@ def test_response_fallback_to_autodetect():
     """
     headers = {"Content-Type": "text-plain; charset=invalid-codec-name"}
     content = "おはようございます。".encode("EUC-JP")
-    response = httpcore.Response(200, content=content, headers=headers)
+    response = http3.Response(200, content=content, headers=headers)
     assert response.text == "おはようございます。"
     assert response.encoding == "EUC-JP"
 
@@ -64,7 +64,7 @@ def test_response_default_text_encoding():
     """
     content = b"Hello, world!"
     headers = {"Content-Type": "text/plain"}
-    response = httpcore.Response(200, content=content, headers=headers)
+    response = http3.Response(200, content=content, headers=headers)
     assert response.status_code == 200
     assert response.encoding == "iso-8859-1"
     assert response.text == "Hello, world!"
@@ -74,7 +74,7 @@ def test_response_default_encoding():
     """
     Default to utf-8 if all else fails.
     """
-    response = httpcore.Response(200, content=b"")
+    response = http3.Response(200, content=b"")
     assert response.text == ""
     assert response.encoding == "utf-8"
 
@@ -84,7 +84,7 @@ def test_response_non_text_encoding():
     Default to apparent encoding for non-text content-type headers.
     """
     headers = {"Content-Type": "image/png"}
-    response = httpcore.Response(200, content=b"xyz", headers=headers)
+    response = http3.Response(200, content=b"xyz", headers=headers)
     assert response.text == "xyz"
     assert response.encoding == "ascii"
 
@@ -93,7 +93,7 @@ def test_response_set_explicit_encoding():
     headers = {
         "Content-Type": "text-plain; charset=utf-8"
     }  # Deliberately incorrect charset
-    response = httpcore.Response(
+    response = http3.Response(
         200, content="Latin 1: ÿ".encode("latin-1"), headers=headers
     )
     response.encoding = "latin-1"
@@ -102,7 +102,7 @@ def test_response_set_explicit_encoding():
 
 
 def test_response_force_encoding():
-    response = httpcore.Response(200, content="Snowman: ☃".encode("utf-8"))
+    response = http3.Response(200, content="Snowman: ☃".encode("utf-8"))
     response.encoding = "iso-8859-1"
     assert response.status_code == 200
     assert response.reason_phrase == "OK"
@@ -111,7 +111,7 @@ def test_response_force_encoding():
 
 
 def test_read_response():
-    response = httpcore.Response(200, content=b"Hello, world!")
+    response = http3.Response(200, content=b"Hello, world!")
 
     assert response.status_code == 200
     assert response.text == "Hello, world!"
@@ -126,7 +126,7 @@ def test_read_response():
 
 
 def test_raw_interface():
-    response = httpcore.Response(200, content=b"Hello, world!")
+    response = http3.Response(200, content=b"Hello, world!")
 
     raw = b""
     for part in response.raw():
@@ -135,7 +135,7 @@ def test_raw_interface():
 
 
 def test_stream_interface():
-    response = httpcore.Response(200, content=b"Hello, world!")
+    response = http3.Response(200, content=b"Hello, world!")
 
     content = b""
     for part in response.stream():
@@ -145,7 +145,7 @@ def test_stream_interface():
 
 @pytest.mark.asyncio
 async def test_async_stream_interface():
-    response = httpcore.AsyncResponse(200, content=b"Hello, world!")
+    response = http3.AsyncResponse(200, content=b"Hello, world!")
 
     content = b""
     async for part in response.stream():
@@ -154,7 +154,7 @@ async def test_async_stream_interface():
 
 
 def test_stream_interface_after_read():
-    response = httpcore.Response(200, content=b"Hello, world!")
+    response = http3.Response(200, content=b"Hello, world!")
 
     response.read()
 
@@ -166,7 +166,7 @@ def test_stream_interface_after_read():
 
 @pytest.mark.asyncio
 async def test_async_stream_interface_after_read():
-    response = httpcore.AsyncResponse(200, content=b"Hello, world!")
+    response = http3.AsyncResponse(200, content=b"Hello, world!")
 
     await response.read()
 
@@ -177,7 +177,7 @@ async def test_async_stream_interface_after_read():
 
 
 def test_streaming_response():
-    response = httpcore.Response(200, content=streaming_body())
+    response = http3.Response(200, content=streaming_body())
 
     assert response.status_code == 200
     assert not response.is_closed
@@ -191,7 +191,7 @@ def test_streaming_response():
 
 @pytest.mark.asyncio
 async def test_async_streaming_response():
-    response = httpcore.AsyncResponse(200, content=async_streaming_body())
+    response = http3.AsyncResponse(200, content=async_streaming_body())
 
     assert response.status_code == 200
     assert not response.is_closed
@@ -204,49 +204,49 @@ async def test_async_streaming_response():
 
 
 def test_cannot_read_after_stream_consumed():
-    response = httpcore.Response(200, content=streaming_body())
+    response = http3.Response(200, content=streaming_body())
 
     content = b""
     for part in response.stream():
         content += part
 
-    with pytest.raises(httpcore.StreamConsumed):
+    with pytest.raises(http3.StreamConsumed):
         response.read()
 
 
 @pytest.mark.asyncio
 async def test_async_cannot_read_after_stream_consumed():
-    response = httpcore.AsyncResponse(200, content=async_streaming_body())
+    response = http3.AsyncResponse(200, content=async_streaming_body())
 
     content = b""
     async for part in response.stream():
         content += part
 
-    with pytest.raises(httpcore.StreamConsumed):
+    with pytest.raises(http3.StreamConsumed):
         await response.read()
 
 
 def test_cannot_read_after_response_closed():
-    response = httpcore.Response(200, content=streaming_body())
+    response = http3.Response(200, content=streaming_body())
 
     response.close()
 
-    with pytest.raises(httpcore.ResponseClosed):
+    with pytest.raises(http3.ResponseClosed):
         response.read()
 
 
 @pytest.mark.asyncio
 async def test_async_cannot_read_after_response_closed():
-    response = httpcore.AsyncResponse(200, content=async_streaming_body())
+    response = http3.AsyncResponse(200, content=async_streaming_body())
 
     await response.close()
 
-    with pytest.raises(httpcore.ResponseClosed):
+    with pytest.raises(http3.ResponseClosed):
         await response.read()
 
 
 def test_unknown_status_code():
-    response = httpcore.Response(600)
+    response = http3.Response(600)
     assert response.status_code == 600
     assert response.reason_phrase == ""
     assert response.text == ""
index 2a45cb3b6371fb6e9c3f5b13b3b8bdb976f9b67f..365809bdc4fc7b3a31b044174206cd6178466a7e 100644 (file)
@@ -1,4 +1,4 @@
-from httpcore import URL
+from http3 import URL
 
 
 def test_idna_url():
index 1247a41602a658815805e5e5234034499fdfdd99..b417a817ec9d5c485af50c591b79d9e38ffddcca 100644 (file)
@@ -3,7 +3,7 @@ import functools
 
 import pytest
 
-import httpcore
+import http3
 
 
 def threadpool(func):
@@ -25,7 +25,7 @@ def threadpool(func):
 
 @threadpool
 def test_get(server):
-    response = httpcore.get("http://127.0.0.1:8000/")
+    response = http3.get("http://127.0.0.1:8000/")
     assert response.status_code == 200
     assert response.reason_phrase == "OK"
     assert response.text == "Hello, world!"
@@ -33,7 +33,7 @@ def test_get(server):
 
 @threadpool
 def test_post(server):
-    response = httpcore.post("http://127.0.0.1:8000/", data=b"Hello, world!")
+    response = http3.post("http://127.0.0.1:8000/", data=b"Hello, world!")
     assert response.status_code == 200
     assert response.reason_phrase == "OK"
 
@@ -45,41 +45,41 @@ def test_post_byte_iterator(server):
         yield b", "
         yield b"world!"
 
-    response = httpcore.post("http://127.0.0.1:8000/", data=data())
+    response = http3.post("http://127.0.0.1:8000/", data=data())
     assert response.status_code == 200
     assert response.reason_phrase == "OK"
 
 
 @threadpool
 def test_options(server):
-    response = httpcore.options("http://127.0.0.1:8000/")
+    response = http3.options("http://127.0.0.1:8000/")
     assert response.status_code == 200
     assert response.reason_phrase == "OK"
 
 
 @threadpool
 def test_head(server):
-    response = httpcore.head("http://127.0.0.1:8000/")
+    response = http3.head("http://127.0.0.1:8000/")
     assert response.status_code == 200
     assert response.reason_phrase == "OK"
 
 
 @threadpool
 def test_put(server):
-    response = httpcore.put("http://127.0.0.1:8000/", data=b"Hello, world!")
+    response = http3.put("http://127.0.0.1:8000/", data=b"Hello, world!")
     assert response.status_code == 200
     assert response.reason_phrase == "OK"
 
 
 @threadpool
 def test_patch(server):
-    response = httpcore.patch("http://127.0.0.1:8000/", data=b"Hello, world!")
+    response = http3.patch("http://127.0.0.1:8000/", data=b"Hello, world!")
     assert response.status_code == 200
     assert response.reason_phrase == "OK"
 
 
 @threadpool
 def test_delete(server):
-    response = httpcore.delete("http://127.0.0.1:8000/")
+    response = http3.delete("http://127.0.0.1:8000/")
     assert response.status_code == 200
     assert response.reason_phrase == "OK"
index 4ee6d6e78eed6b1f1d5f7d74bfd78257a9527389..a77f2189d09ca1ca9ed9ba45216e8e7088b6ba1a 100644 (file)
@@ -3,34 +3,34 @@ import ssl
 
 import pytest
 
-import httpcore
+import http3
 
 
 @pytest.mark.asyncio
 async def test_load_ssl_config():
-    ssl_config = httpcore.SSLConfig()
+    ssl_config = http3.SSLConfig()
     context = await ssl_config.load_ssl_context()
     assert context.verify_mode == ssl.VerifyMode.CERT_REQUIRED
 
 
 @pytest.mark.asyncio
 async def test_load_ssl_config_verify_non_existing_path():
-    ssl_config = httpcore.SSLConfig(verify="/path/to/nowhere")
+    ssl_config = http3.SSLConfig(verify="/path/to/nowhere")
     with pytest.raises(IOError):
         await ssl_config.load_ssl_context()
 
 
 @pytest.mark.asyncio
 async def test_load_ssl_config_verify_existing_file():
-    ssl_config = httpcore.SSLConfig(verify=httpcore.config.DEFAULT_CA_BUNDLE_PATH)
+    ssl_config = http3.SSLConfig(verify=http3.config.DEFAULT_CA_BUNDLE_PATH)
     context = await ssl_config.load_ssl_context()
     assert context.verify_mode == ssl.VerifyMode.CERT_REQUIRED
 
 
 @pytest.mark.asyncio
 async def test_load_ssl_config_verify_directory():
-    path = os.path.dirname(httpcore.config.DEFAULT_CA_BUNDLE_PATH)
-    ssl_config = httpcore.SSLConfig(verify=path)
+    path = os.path.dirname(http3.config.DEFAULT_CA_BUNDLE_PATH)
+    ssl_config = http3.SSLConfig(verify=path)
     context = await ssl_config.load_ssl_context()
     assert context.verify_mode == ssl.VerifyMode.CERT_REQUIRED
 
@@ -38,7 +38,7 @@ async def test_load_ssl_config_verify_directory():
 @pytest.mark.asyncio
 async def test_load_ssl_config_cert_and_key(cert_and_key_paths):
     cert_path, key_path = cert_and_key_paths
-    ssl_config = httpcore.SSLConfig(cert=(cert_path, key_path))
+    ssl_config = http3.SSLConfig(cert=(cert_path, key_path))
     context = await ssl_config.load_ssl_context()
     assert context.verify_mode == ssl.VerifyMode.CERT_REQUIRED
 
@@ -46,28 +46,28 @@ async def test_load_ssl_config_cert_and_key(cert_and_key_paths):
 @pytest.mark.asyncio
 async def test_load_ssl_config_cert_without_key_raises(cert_and_key_paths):
     cert_path, _ = cert_and_key_paths
-    ssl_config = httpcore.SSLConfig(cert=cert_path)
+    ssl_config = http3.SSLConfig(cert=cert_path)
     with pytest.raises(ssl.SSLError):
         await ssl_config.load_ssl_context()
 
 
 @pytest.mark.asyncio
 async def test_load_ssl_config_no_verify(verify=False):
-    ssl_config = httpcore.SSLConfig(verify=False)
+    ssl_config = http3.SSLConfig(verify=False)
     context = await ssl_config.load_ssl_context()
     assert context.verify_mode == ssl.VerifyMode.CERT_NONE
 
 
 def test_ssl_repr():
-    ssl = httpcore.SSLConfig(verify=False)
+    ssl = http3.SSLConfig(verify=False)
     assert repr(ssl) == "SSLConfig(cert=None, verify=False)"
 
 
 def test_timeout_repr():
-    timeout = httpcore.TimeoutConfig(timeout=5.0)
+    timeout = http3.TimeoutConfig(timeout=5.0)
     assert repr(timeout) == "TimeoutConfig(timeout=5.0)"
 
-    timeout = httpcore.TimeoutConfig(read_timeout=5.0)
+    timeout = http3.TimeoutConfig(read_timeout=5.0)
     assert (
         repr(timeout)
         == "TimeoutConfig(connect_timeout=None, read_timeout=5.0, write_timeout=None)"
@@ -75,32 +75,32 @@ def test_timeout_repr():
 
 
 def test_limits_repr():
-    limits = httpcore.PoolLimits(hard_limit=100)
+    limits = http3.PoolLimits(hard_limit=100)
     assert (
         repr(limits) == "PoolLimits(soft_limit=None, hard_limit=100, pool_timeout=None)"
     )
 
 
 def test_ssl_eq():
-    ssl = httpcore.SSLConfig(verify=False)
-    assert ssl == httpcore.SSLConfig(verify=False)
+    ssl = http3.SSLConfig(verify=False)
+    assert ssl == http3.SSLConfig(verify=False)
 
 
 def test_timeout_eq():
-    timeout = httpcore.TimeoutConfig(timeout=5.0)
-    assert timeout == httpcore.TimeoutConfig(timeout=5.0)
+    timeout = http3.TimeoutConfig(timeout=5.0)
+    assert timeout == http3.TimeoutConfig(timeout=5.0)
 
 
 def test_limits_eq():
-    limits = httpcore.PoolLimits(hard_limit=100)
-    assert limits == httpcore.PoolLimits(hard_limit=100)
+    limits = http3.PoolLimits(hard_limit=100)
+    assert limits == http3.PoolLimits(hard_limit=100)
 
 
 def test_timeout_from_tuple():
-    timeout = httpcore.TimeoutConfig(timeout=(5.0, 5.0, 5.0))
-    assert timeout == httpcore.TimeoutConfig(timeout=5.0)
+    timeout = http3.TimeoutConfig(timeout=(5.0, 5.0, 5.0))
+    assert timeout == http3.TimeoutConfig(timeout=5.0)
 
 
 def test_timeout_from_config_instance():
-    timeout = httpcore.TimeoutConfig(timeout=(5.0))
-    assert httpcore.TimeoutConfig(timeout) == httpcore.TimeoutConfig(timeout=5.0)
+    timeout = http3.TimeoutConfig(timeout=(5.0))
+    assert http3.TimeoutConfig(timeout) == http3.TimeoutConfig(timeout=5.0)
index ac795ca91e1ad5c9465a84171e6d0fc1d6d44a1d..2e21790989d8ac0cba4c9ec2bc33c67757b526c8 100644 (file)
@@ -3,7 +3,7 @@ import zlib
 import brotli
 import pytest
 
-import httpcore
+import http3
 
 
 def test_deflate():
@@ -12,7 +12,7 @@ def test_deflate():
     compressed_body = compressor.compress(body) + compressor.flush()
 
     headers = [(b"Content-Encoding", b"deflate")]
-    response = httpcore.Response(200, headers=headers, content=compressed_body)
+    response = http3.Response(200, headers=headers, content=compressed_body)
     assert response.content == body
 
 
@@ -22,7 +22,7 @@ def test_gzip():
     compressed_body = compressor.compress(body) + compressor.flush()
 
     headers = [(b"Content-Encoding", b"gzip")]
-    response = httpcore.Response(200, headers=headers, content=compressed_body)
+    response = http3.Response(200, headers=headers, content=compressed_body)
     assert response.content == body
 
 
@@ -31,7 +31,7 @@ def test_brotli():
     compressed_body = brotli.compress(body)
 
     headers = [(b"Content-Encoding", b"br")]
-    response = httpcore.Response(200, headers=headers, content=compressed_body)
+    response = http3.Response(200, headers=headers, content=compressed_body)
     assert response.content == body
 
 
@@ -47,7 +47,7 @@ def test_multi():
     )
 
     headers = [(b"Content-Encoding", b"deflate, gzip")]
-    response = httpcore.Response(200, headers=headers, content=compressed_body)
+    response = http3.Response(200, headers=headers, content=compressed_body)
     assert response.content == body
 
 
@@ -56,11 +56,11 @@ def test_multi_with_identity():
     compressed_body = brotli.compress(body)
 
     headers = [(b"Content-Encoding", b"br, identity")]
-    response = httpcore.Response(200, headers=headers, content=compressed_body)
+    response = http3.Response(200, headers=headers, content=compressed_body)
     assert response.content == body
 
     headers = [(b"Content-Encoding", b"identity, br")]
-    response = httpcore.Response(200, headers=headers, content=compressed_body)
+    response = http3.Response(200, headers=headers, content=compressed_body)
     assert response.content == body
 
 
@@ -73,7 +73,7 @@ def test_streaming():
         yield compressor.flush()
 
     headers = [(b"Content-Encoding", b"gzip")]
-    response = httpcore.Response(200, headers=headers, content=compress(body))
+    response = http3.Response(200, headers=headers, content=compress(body))
     assert not hasattr(response, "body")
     assert response.read() == body
 
@@ -83,6 +83,6 @@ def test_decoding_errors(header_value):
     headers = [(b"Content-Encoding", header_value)]
     body = b"test 123"
     compressed_body = brotli.compress(body)[3:]
-    with pytest.raises(httpcore.exceptions.DecodingError):
-        response = httpcore.Response(200, headers=headers, content=compressed_body)
+    with pytest.raises(http3.exceptions.DecodingError):
+        response = http3.Response(200, headers=headers, content=compressed_body)
         response.content
index f1206fa87cab1d6da78a387be6d5c16a432d2013..bfced702eb6ee112ffa1fbe3d7c4042d20c241fe 100644 (file)
@@ -1,6 +1,6 @@
 import pytest
 
-from httpcore import (
+from http3 import (
     AsyncClient,
     ConnectTimeout,
     PoolLimits,