Compare commits
18 Commits
version-0.
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5addb64f0 | ||
|
|
ae1b9f6623 | ||
|
|
ca097c96f9 | ||
|
|
def4778d62 | ||
|
|
435e1dac89 | ||
|
|
4b23574cf8 | ||
|
|
652f051fea | ||
|
|
3fee27838e | ||
|
|
bc00d2bd9f | ||
|
|
767cf6baa6 | ||
|
|
b55d463570 | ||
|
|
15e9759e65 | ||
|
|
364697efca | ||
|
|
89102021fc | ||
|
|
4fb9528c2f | ||
|
|
336204f012 | ||
|
|
6c7af96773 | ||
|
|
9e8ab40369 |
4
.github/workflows/publish.yml
vendored
4
.github/workflows/publish.yml
vendored
@ -15,9 +15,9 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: "actions/checkout@v4"
|
- uses: "actions/checkout@v4"
|
||||||
- uses: "actions/setup-python@v5"
|
- uses: "actions/setup-python@v6"
|
||||||
with:
|
with:
|
||||||
python-version: 3.8
|
python-version: 3.9
|
||||||
- name: "Install dependencies"
|
- name: "Install dependencies"
|
||||||
run: "scripts/install"
|
run: "scripts/install"
|
||||||
- name: "Build package & docs"
|
- name: "Build package & docs"
|
||||||
|
|||||||
4
.github/workflows/test-suite.yml
vendored
4
.github/workflows/test-suite.yml
vendored
@ -14,11 +14,11 @@ jobs:
|
|||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
|
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: "actions/checkout@v4"
|
- uses: "actions/checkout@v4"
|
||||||
- uses: "actions/setup-python@v5"
|
- uses: "actions/setup-python@v6"
|
||||||
with:
|
with:
|
||||||
python-version: "${{ matrix.python-version }}"
|
python-version: "${{ matrix.python-version }}"
|
||||||
allow-prereleases: true
|
allow-prereleases: true
|
||||||
|
|||||||
10
CHANGELOG.md
10
CHANGELOG.md
@ -4,9 +4,15 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
## 0.28.2 (...)
|
## [UNRELEASED]
|
||||||
|
|
||||||
* Update package classifiers. (#3460)
|
### Removed
|
||||||
|
|
||||||
|
* Drop support for Python 3.8
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* Expose `FunctionAuth` from the public API. (#3699)
|
||||||
|
|
||||||
## 0.28.1 (6th December, 2024)
|
## 0.28.1 (6th December, 2024)
|
||||||
|
|
||||||
|
|||||||
@ -101,7 +101,7 @@ Or, to include the optional HTTP/2 support, use:
|
|||||||
$ pip install httpx[http2]
|
$ pip install httpx[http2]
|
||||||
```
|
```
|
||||||
|
|
||||||
HTTPX requires Python 3.8+.
|
HTTPX requires Python 3.9+.
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
|
|||||||
@ -29,7 +29,7 @@ import certifi
|
|||||||
import httpx
|
import httpx
|
||||||
import ssl
|
import ssl
|
||||||
|
|
||||||
# This SSL context is equivelent to the default `verify=True`.
|
# This SSL context is equivalent to the default `verify=True`.
|
||||||
ctx = ssl.create_default_context(cafile=certifi.where())
|
ctx = ssl.create_default_context(cafile=certifi.where())
|
||||||
client = httpx.Client(verify=ctx)
|
client = httpx.Client(verify=ctx)
|
||||||
```
|
```
|
||||||
@ -71,19 +71,7 @@ client = httpx.Client(verify=ctx)
|
|||||||
|
|
||||||
### Working with `SSL_CERT_FILE` and `SSL_CERT_DIR`
|
### Working with `SSL_CERT_FILE` and `SSL_CERT_DIR`
|
||||||
|
|
||||||
Unlike `requests`, the `httpx` package does not automatically pull in [the environment variables `SSL_CERT_FILE` or `SSL_CERT_DIR`](https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_default_verify_paths.html). If you want to use these they need to be enabled explicitly.
|
`httpx` does respect the `SSL_CERT_FILE` and `SSL_CERT_DIR` environment variables by default. For details, refer to [the section on the environment variables page](../environment_variables.md#ssl_cert_file).
|
||||||
|
|
||||||
For example...
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Use `SSL_CERT_FILE` or `SSL_CERT_DIR` if configured.
|
|
||||||
# Otherwise default to certifi.
|
|
||||||
ctx = ssl.create_default_context(
|
|
||||||
cafile=os.environ.get("SSL_CERT_FILE", certifi.where()),
|
|
||||||
capath=os.environ.get("SSL_CERT_DIR"),
|
|
||||||
)
|
|
||||||
client = httpx.Client(verify=ctx)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Making HTTPS requests to a local server
|
### Making HTTPS requests to a local server
|
||||||
|
|
||||||
|
|||||||
15
docs/api.md
15
docs/api.md
@ -159,3 +159,18 @@ what gets sent over the wire.*
|
|||||||
* `def delete(name, [domain], [path])`
|
* `def delete(name, [domain], [path])`
|
||||||
* `def clear([domain], [path])`
|
* `def clear([domain], [path])`
|
||||||
* *Standard mutable mapping interface*
|
* *Standard mutable mapping interface*
|
||||||
|
|
||||||
|
## `Proxy`
|
||||||
|
|
||||||
|
*A configuration of the proxy server.*
|
||||||
|
|
||||||
|
```pycon
|
||||||
|
>>> proxy = Proxy("http://proxy.example.com:8030")
|
||||||
|
>>> client = Client(proxy=proxy)
|
||||||
|
```
|
||||||
|
|
||||||
|
* `def __init__(url, [ssl_context], [auth], [headers])`
|
||||||
|
* `.url` - **URL**
|
||||||
|
* `.auth` - **tuple[str, str]**
|
||||||
|
* `.headers` - **Headers**
|
||||||
|
* `.ssl_context` - **SSLContext**
|
||||||
|
|||||||
@ -23,7 +23,7 @@ To make asynchronous requests, you'll need an `AsyncClient`.
|
|||||||
```
|
```
|
||||||
|
|
||||||
!!! tip
|
!!! tip
|
||||||
Use [IPython](https://ipython.readthedocs.io/en/stable/) or Python 3.8+ with `python -m asyncio` to try this code interactively, as they support executing `async`/`await` expressions in the console.
|
Use [IPython](https://ipython.readthedocs.io/en/stable/) or Python 3.9+ with `python -m asyncio` to try this code interactively, as they support executing `async`/`await` expressions in the console.
|
||||||
|
|
||||||
## API Differences
|
## API Differences
|
||||||
|
|
||||||
|
|||||||
@ -226,3 +226,7 @@ For both query params (`params=`) and form data (`data=`), `requests` supports s
|
|||||||
In HTTPX, event hooks may access properties of requests and responses, but event hook callbacks cannot mutate the original request/response.
|
In HTTPX, event hooks may access properties of requests and responses, but event hook callbacks cannot mutate the original request/response.
|
||||||
|
|
||||||
If you are looking for more control, consider checking out [Custom Transports](advanced/transports.md#custom-transports).
|
If you are looking for more control, consider checking out [Custom Transports](advanced/transports.md#custom-transports).
|
||||||
|
|
||||||
|
## Exceptions and Errors
|
||||||
|
|
||||||
|
`requests` exception hierarchy is slightly different to the `httpx` exception hierarchy. `requests` exposes a top level `RequestException`, where as `httpx` exposes a top level `HTTPError`. see the exceptions exposes in requests [here](https://requests.readthedocs.io/en/latest/_modules/requests/exceptions/). See the `httpx` error hierarchy [here](https://www.python-httpx.org/exceptions/).
|
||||||
|
|||||||
@ -51,3 +51,29 @@ python -c "import httpx; httpx.get('http://example.com')"
|
|||||||
python -c "import httpx; httpx.get('http://127.0.0.1:5000/my-api')"
|
python -c "import httpx; httpx.get('http://127.0.0.1:5000/my-api')"
|
||||||
python -c "import httpx; httpx.get('https://www.python-httpx.org')"
|
python -c "import httpx; httpx.get('https://www.python-httpx.org')"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## `SSL_CERT_FILE`
|
||||||
|
|
||||||
|
Valid values: a filename
|
||||||
|
|
||||||
|
If this environment variable is set then HTTPX will load
|
||||||
|
CA certificate from the specified file instead of the default
|
||||||
|
location.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```console
|
||||||
|
SSL_CERT_FILE=/path/to/ca-certs/ca-bundle.crt python -c "import httpx; httpx.get('https://example.com')"
|
||||||
|
```
|
||||||
|
|
||||||
|
## `SSL_CERT_DIR`
|
||||||
|
|
||||||
|
Valid values: a directory following an [OpenSSL specific layout](https://www.openssl.org/docs/manmaster/man3/SSL_CTX_load_verify_locations.html).
|
||||||
|
|
||||||
|
If this environment variable is set and the directory follows an [OpenSSL specific layout](https://www.openssl.org/docs/manmaster/man3/SSL_CTX_load_verify_locations.html) (ie. you ran `c_rehash`) then HTTPX will load CA certificates from this directory instead of the default location.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```console
|
||||||
|
SSL_CERT_DIR=/path/to/ca-certs/ python -c "import httpx; httpx.get('https://example.com')"
|
||||||
|
```
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 113 KiB |
@ -145,6 +145,6 @@ To include the optional brotli and zstandard decoders support, use:
|
|||||||
$ pip install httpx[brotli,zstd]
|
$ pip install httpx[brotli,zstd]
|
||||||
```
|
```
|
||||||
|
|
||||||
HTTPX requires Python 3.8+
|
HTTPX requires Python 3.9+
|
||||||
|
|
||||||
[sync-support]: https://github.com/encode/httpx/issues/572
|
[sync-support]: https://github.com/encode/httpx/issues/572
|
||||||
|
|||||||
@ -20,8 +20,6 @@ httpx.get("https://www.example.com")
|
|||||||
Will send debug level output to the console, or wherever `stdout` is directed too...
|
Will send debug level output to the console, or wherever `stdout` is directed too...
|
||||||
|
|
||||||
```
|
```
|
||||||
DEBUG [2024-09-28 17:27:40] httpx - load_ssl_context verify=True cert=None
|
|
||||||
DEBUG [2024-09-28 17:27:40] httpx - load_verify_locations cafile='/Users/karenpetrosyan/oss/karhttpx/.venv/lib/python3.9/site-packages/certifi/cacert.pem'
|
|
||||||
DEBUG [2024-09-28 17:27:40] httpcore.connection - connect_tcp.started host='www.example.com' port=443 local_address=None timeout=5.0 socket_options=None
|
DEBUG [2024-09-28 17:27:40] httpcore.connection - connect_tcp.started host='www.example.com' port=443 local_address=None timeout=5.0 socket_options=None
|
||||||
DEBUG [2024-09-28 17:27:41] httpcore.connection - connect_tcp.complete return_value=<httpcore._backends.sync.SyncStream object at 0x101f1e8e0>
|
DEBUG [2024-09-28 17:27:41] httpcore.connection - connect_tcp.complete return_value=<httpcore._backends.sync.SyncStream object at 0x101f1e8e0>
|
||||||
DEBUG [2024-09-28 17:27:41] httpcore.connection - start_tls.started ssl_context=SSLContext(verify=True) server_hostname='www.example.com' timeout=5.0
|
DEBUG [2024-09-28 17:27:41] httpcore.connection - start_tls.started ssl_context=SSLContext(verify=True) server_hostname='www.example.com' timeout=5.0
|
||||||
|
|||||||
@ -191,7 +191,7 @@ You can also explicitly set the filename and content type, by using a tuple
|
|||||||
of items for the file value:
|
of items for the file value:
|
||||||
|
|
||||||
```pycon
|
```pycon
|
||||||
>>> with open('report.xls', 'rb') report_file:
|
>>> with open('report.xls', 'rb') as report_file:
|
||||||
... files = {'upload-file': ('report.xls', report_file, 'application/vnd.ms-excel')}
|
... files = {'upload-file': ('report.xls', report_file, 'application/vnd.ms-excel')}
|
||||||
... r = httpx.post("https://httpbin.org/post", files=files)
|
... r = httpx.post("https://httpbin.org/post", files=files)
|
||||||
>>> print(r.text)
|
>>> print(r.text)
|
||||||
|
|||||||
@ -2,73 +2,21 @@
|
|||||||
|
|
||||||
As HTTPX usage grows, there is an expanding community of developers building tools and libraries that integrate with HTTPX, or depend on HTTPX. Here are some of them.
|
As HTTPX usage grows, there is an expanding community of developers building tools and libraries that integrate with HTTPX, or depend on HTTPX. Here are some of them.
|
||||||
|
|
||||||
|
<!-- NOTE: Entries are alphabetised. -->
|
||||||
|
|
||||||
## Plugins
|
## Plugins
|
||||||
|
|
||||||
### httpx-ws
|
|
||||||
|
|
||||||
[GitHub](https://github.com/frankie567/httpx-ws) - [Documentation](https://frankie567.github.io/httpx-ws/)
|
|
||||||
|
|
||||||
WebSocket support for HTTPX.
|
|
||||||
|
|
||||||
### httpx-socks
|
|
||||||
|
|
||||||
[GitHub](https://github.com/romis2012/httpx-socks)
|
|
||||||
|
|
||||||
Proxy (HTTP, SOCKS) transports for httpx.
|
|
||||||
|
|
||||||
### httpdbg
|
|
||||||
|
|
||||||
[GitHub](https://github.com/cle-b/httpdbg) - [Documentation](https://httpdbg.readthedocs.io/)
|
|
||||||
|
|
||||||
A tool for Python developers to easily debug the HTTP(S) client requests in a Python program.
|
|
||||||
|
|
||||||
### Hishel
|
### Hishel
|
||||||
|
|
||||||
[GitHub](https://github.com/karpetrosyan/hishel) - [Documentation](https://hishel.com/)
|
[GitHub](https://github.com/karpetrosyan/hishel) - [Documentation](https://hishel.com/)
|
||||||
|
|
||||||
An elegant HTTP Cache implementation for HTTPX and HTTP Core.
|
An elegant HTTP Cache implementation for HTTPX and HTTP Core.
|
||||||
|
|
||||||
### Authlib
|
|
||||||
|
|
||||||
[GitHub](https://github.com/lepture/authlib) - [Documentation](https://docs.authlib.org/en/latest/)
|
|
||||||
|
|
||||||
The ultimate Python library in building OAuth and OpenID Connect clients and servers. Includes an [OAuth HTTPX client](https://docs.authlib.org/en/latest/client/httpx.html).
|
|
||||||
|
|
||||||
### Gidgethub
|
|
||||||
|
|
||||||
[GitHub](https://github.com/brettcannon/gidgethub) - [Documentation](https://gidgethub.readthedocs.io/en/latest/index.html)
|
|
||||||
|
|
||||||
An asynchronous GitHub API library. Includes [HTTPX support](https://gidgethub.readthedocs.io/en/latest/httpx.html).
|
|
||||||
|
|
||||||
### HTTPX-Auth
|
### HTTPX-Auth
|
||||||
|
|
||||||
[GitHub](https://github.com/Colin-b/httpx_auth) - [Documentation](https://colin-b.github.io/httpx_auth/)
|
[GitHub](https://github.com/Colin-b/httpx_auth) - [Documentation](https://colin-b.github.io/httpx_auth/)
|
||||||
|
|
||||||
Provides authentication classes to be used with HTTPX [authentication parameter](advanced/authentication.md#customizing-authentication).
|
Provides authentication classes to be used with HTTPX's [authentication parameter](advanced/authentication.md#customizing-authentication).
|
||||||
|
|
||||||
### pytest-HTTPX
|
|
||||||
|
|
||||||
[GitHub](https://github.com/Colin-b/pytest_httpx) - [Documentation](https://colin-b.github.io/pytest_httpx/)
|
|
||||||
|
|
||||||
Provides `httpx_mock` [pytest](https://docs.pytest.org/en/latest/) fixture to mock HTTPX within test cases.
|
|
||||||
|
|
||||||
### RESPX
|
|
||||||
|
|
||||||
[GitHub](https://github.com/lundberg/respx) - [Documentation](https://lundberg.github.io/respx/)
|
|
||||||
|
|
||||||
A utility for mocking out the Python HTTPX library.
|
|
||||||
|
|
||||||
### rpc.py
|
|
||||||
|
|
||||||
[Github](https://github.com/abersheeran/rpc.py) - [Documentation](https://github.com/abersheeran/rpc.py#rpcpy)
|
|
||||||
|
|
||||||
An fast and powerful RPC framework based on ASGI/WSGI. Use HTTPX as the client of the RPC service.
|
|
||||||
|
|
||||||
### VCR.py
|
|
||||||
|
|
||||||
[GitHub](https://github.com/kevin1024/vcrpy) - [Documentation](https://vcrpy.readthedocs.io/)
|
|
||||||
|
|
||||||
A utility for record and repeat an http request.
|
|
||||||
|
|
||||||
### httpx-caching
|
### httpx-caching
|
||||||
|
|
||||||
@ -76,22 +24,82 @@ A utility for record and repeat an http request.
|
|||||||
|
|
||||||
This package adds caching functionality to HTTPX
|
This package adds caching functionality to HTTPX
|
||||||
|
|
||||||
|
### httpx-secure
|
||||||
|
|
||||||
|
[GitHub](https://github.com/Zaczero/httpx-secure)
|
||||||
|
|
||||||
|
Drop-in SSRF protection for httpx with DNS caching and custom validation support.
|
||||||
|
|
||||||
|
### httpx-socks
|
||||||
|
|
||||||
|
[GitHub](https://github.com/romis2012/httpx-socks)
|
||||||
|
|
||||||
|
Proxy (HTTP, SOCKS) transports for httpx.
|
||||||
|
|
||||||
### httpx-sse
|
### httpx-sse
|
||||||
|
|
||||||
[GitHub](https://github.com/florimondmanca/httpx-sse)
|
[GitHub](https://github.com/florimondmanca/httpx-sse)
|
||||||
|
|
||||||
Allows consuming Server-Sent Events (SSE) with HTTPX.
|
Allows consuming Server-Sent Events (SSE) with HTTPX.
|
||||||
|
|
||||||
### robox
|
### httpx-retries
|
||||||
|
|
||||||
[Github](https://github.com/danclaudiupop/robox)
|
[GitHub](https://github.com/will-ockmore/httpx-retries) - [Documentation](https://will-ockmore.github.io/httpx-retries/)
|
||||||
|
|
||||||
A library for scraping the web built on top of HTTPX.
|
A retry layer for HTTPX.
|
||||||
|
|
||||||
|
### httpx-ws
|
||||||
|
|
||||||
|
[GitHub](https://github.com/frankie567/httpx-ws) - [Documentation](https://frankie567.github.io/httpx-ws/)
|
||||||
|
|
||||||
|
WebSocket support for HTTPX.
|
||||||
|
|
||||||
|
### pytest-HTTPX
|
||||||
|
|
||||||
|
[GitHub](https://github.com/Colin-b/pytest_httpx) - [Documentation](https://colin-b.github.io/pytest_httpx/)
|
||||||
|
|
||||||
|
Provides a [pytest](https://docs.pytest.org/en/latest/) fixture to mock HTTPX within test cases.
|
||||||
|
|
||||||
|
### RESPX
|
||||||
|
|
||||||
|
[GitHub](https://github.com/lundberg/respx) - [Documentation](https://lundberg.github.io/respx/)
|
||||||
|
|
||||||
|
A utility for mocking out HTTPX.
|
||||||
|
|
||||||
|
### rpc.py
|
||||||
|
|
||||||
|
[Github](https://github.com/abersheeran/rpc.py) - [Documentation](https://github.com/abersheeran/rpc.py#rpcpy)
|
||||||
|
|
||||||
|
A fast and powerful RPC framework based on ASGI/WSGI. Use HTTPX as the client of the RPC service.
|
||||||
|
|
||||||
|
## Libraries with HTTPX support
|
||||||
|
|
||||||
|
### Authlib
|
||||||
|
|
||||||
|
[GitHub](https://github.com/lepture/authlib) - [Documentation](https://docs.authlib.org/en/latest/)
|
||||||
|
|
||||||
|
A python library for building OAuth and OpenID Connect clients and servers. Includes an [OAuth HTTPX client](https://docs.authlib.org/en/latest/client/httpx.html).
|
||||||
|
|
||||||
|
### Gidgethub
|
||||||
|
|
||||||
|
[GitHub](https://github.com/brettcannon/gidgethub) - [Documentation](https://gidgethub.readthedocs.io/en/latest/index.html)
|
||||||
|
|
||||||
|
An asynchronous GitHub API library. Includes [HTTPX support](https://gidgethub.readthedocs.io/en/latest/httpx.html).
|
||||||
|
|
||||||
|
### httpdbg
|
||||||
|
|
||||||
|
[GitHub](https://github.com/cle-b/httpdbg) - [Documentation](https://httpdbg.readthedocs.io/)
|
||||||
|
|
||||||
|
A tool for python developers to easily debug the HTTP(S) client requests in a python program.
|
||||||
|
|
||||||
|
### VCR.py
|
||||||
|
|
||||||
|
[GitHub](https://github.com/kevin1024/vcrpy) - [Documentation](https://vcrpy.readthedocs.io/)
|
||||||
|
|
||||||
|
Record and repeat requests.
|
||||||
|
|
||||||
## Gists
|
## Gists
|
||||||
|
|
||||||
<!-- NOTE: this list is in alphabetical order. -->
|
|
||||||
|
|
||||||
### urllib3-transport
|
### urllib3-transport
|
||||||
|
|
||||||
[GitHub](https://gist.github.com/florimondmanca/d56764d78d748eb9f73165da388e546e)
|
[GitHub](https://gist.github.com/florimondmanca/d56764d78d748eb9f73165da388e546e)
|
||||||
|
|||||||
@ -50,6 +50,7 @@ __all__ = [
|
|||||||
"DecodingError",
|
"DecodingError",
|
||||||
"delete",
|
"delete",
|
||||||
"DigestAuth",
|
"DigestAuth",
|
||||||
|
"FunctionAuth",
|
||||||
"get",
|
"get",
|
||||||
"head",
|
"head",
|
||||||
"Headers",
|
"Headers",
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
__title__ = "httpx"
|
__title__ = "httpx"
|
||||||
__description__ = "A next generation HTTP client, for Python 3."
|
__description__ = "A next generation HTTP client, for Python 3."
|
||||||
__version__ = "0.28.2"
|
__version__ = "0.28.1"
|
||||||
|
|||||||
@ -16,7 +16,7 @@ if typing.TYPE_CHECKING: # pragma: no cover
|
|||||||
from hashlib import _Hash
|
from hashlib import _Hash
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["Auth", "BasicAuth", "DigestAuth", "NetRCAuth"]
|
__all__ = ["Auth", "BasicAuth", "DigestAuth", "FunctionAuth", "NetRCAuth"]
|
||||||
|
|
||||||
|
|
||||||
class Auth:
|
class Auth:
|
||||||
|
|||||||
@ -331,9 +331,7 @@ class StreamClosed(StreamError):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
message = (
|
message = "Attempted to read or stream content, but the stream has been closed."
|
||||||
"Attempted to read or stream content, but the stream has " "been closed."
|
|
||||||
)
|
|
||||||
super().__init__(message)
|
super().__init__(message)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -355,7 +355,7 @@ class AsyncHTTPTransport(AsyncBaseTransport):
|
|||||||
else: # pragma: no cover
|
else: # pragma: no cover
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Proxy protocol must be either 'http', 'https', 'socks5', or 'socks5h',"
|
"Proxy protocol must be either 'http', 'https', 'socks5', or 'socks5h',"
|
||||||
" but got {proxy.url.scheme!r}."
|
f" but got {proxy.url.scheme!r}."
|
||||||
)
|
)
|
||||||
|
|
||||||
async def __aenter__(self: A) -> A: # Use generics for subclass support.
|
async def __aenter__(self: A) -> A: # Use generics for subclass support.
|
||||||
|
|||||||
@ -379,7 +379,7 @@ class URL:
|
|||||||
|
|
||||||
if ":" in userinfo:
|
if ":" in userinfo:
|
||||||
# Mask any password component.
|
# Mask any password component.
|
||||||
userinfo = f'{userinfo.split(":")[0]}:[secure]'
|
userinfo = f"{userinfo.split(':')[0]}:[secure]"
|
||||||
|
|
||||||
authority = "".join(
|
authority = "".join(
|
||||||
[
|
[
|
||||||
|
|||||||
@ -6,7 +6,7 @@ build-backend = "hatchling.build"
|
|||||||
name = "httpx"
|
name = "httpx"
|
||||||
description = "The next generation HTTP client."
|
description = "The next generation HTTP client."
|
||||||
license = "BSD-3-Clause"
|
license = "BSD-3-Clause"
|
||||||
requires-python = ">=3.8"
|
requires-python = ">=3.9"
|
||||||
authors = [
|
authors = [
|
||||||
{ name = "Tom Christie", email = "tom@tomchristie.com" },
|
{ name = "Tom Christie", email = "tom@tomchristie.com" },
|
||||||
]
|
]
|
||||||
@ -20,7 +20,6 @@ classifiers = [
|
|||||||
"Operating System :: OS Independent",
|
"Operating System :: OS Independent",
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: 3 :: Only",
|
"Programming Language :: Python :: 3 :: Only",
|
||||||
"Programming Language :: Python :: 3.8",
|
|
||||||
"Programming Language :: Python :: 3.9",
|
"Programming Language :: Python :: 3.9",
|
||||||
"Programming Language :: Python :: 3.10",
|
"Programming Language :: Python :: 3.10",
|
||||||
"Programming Language :: Python :: 3.11",
|
"Programming Language :: Python :: 3.11",
|
||||||
@ -44,7 +43,7 @@ brotli = [
|
|||||||
cli = [
|
cli = [
|
||||||
"click==8.*",
|
"click==8.*",
|
||||||
"pygments==2.*",
|
"pygments==2.*",
|
||||||
"rich>=10,<14",
|
"rich>=10,<15",
|
||||||
]
|
]
|
||||||
http2 = [
|
http2 = [
|
||||||
"h2>=3,<5",
|
"h2>=3,<5",
|
||||||
|
|||||||
@ -11,20 +11,19 @@ chardet==5.2.0
|
|||||||
# Documentation
|
# Documentation
|
||||||
mkdocs==1.6.1
|
mkdocs==1.6.1
|
||||||
mkautodoc==0.2.0
|
mkautodoc==0.2.0
|
||||||
mkdocs-material==9.5.47
|
mkdocs-material==9.6.18
|
||||||
|
|
||||||
# Packaging
|
# Packaging
|
||||||
build==1.2.2.post1
|
build==1.3.0
|
||||||
twine==6.0.1
|
twine==6.1.0
|
||||||
|
|
||||||
# Tests & Linting
|
# Tests & Linting
|
||||||
coverage[toml]==7.6.1
|
coverage[toml]==7.10.6
|
||||||
cryptography==44.0.1
|
cryptography==45.0.7
|
||||||
mypy==1.13.0
|
mypy==1.17.1
|
||||||
pytest==8.3.4
|
pytest==8.4.1
|
||||||
ruff==0.8.1
|
ruff==0.12.11
|
||||||
trio==0.27.0
|
trio==0.31.0
|
||||||
trio-typing==0.10.0
|
trio-typing==0.10.0
|
||||||
trustme==1.1.0; python_version < '3.9'
|
trustme==1.2.1
|
||||||
trustme==1.2.0; python_version >= '3.9'
|
uvicorn==0.35.0
|
||||||
uvicorn==0.32.1
|
|
||||||
|
|||||||
@ -326,7 +326,7 @@ async def test_auth_property() -> None:
|
|||||||
async with httpx.AsyncClient(transport=httpx.MockTransport(app)) as client:
|
async with httpx.AsyncClient(transport=httpx.MockTransport(app)) as client:
|
||||||
assert client.auth is None
|
assert client.auth is None
|
||||||
|
|
||||||
client.auth = ("user", "password123") # type: ignore
|
client.auth = ("user", "password123")
|
||||||
assert isinstance(client.auth, httpx.BasicAuth)
|
assert isinstance(client.auth, httpx.BasicAuth)
|
||||||
|
|
||||||
url = "https://example.org/"
|
url = "https://example.org/"
|
||||||
|
|||||||
@ -3,35 +3,35 @@ import httpx
|
|||||||
|
|
||||||
def test_client_base_url():
|
def test_client_base_url():
|
||||||
client = httpx.Client()
|
client = httpx.Client()
|
||||||
client.base_url = "https://www.example.org/" # type: ignore
|
client.base_url = "https://www.example.org/"
|
||||||
assert isinstance(client.base_url, httpx.URL)
|
assert isinstance(client.base_url, httpx.URL)
|
||||||
assert client.base_url == "https://www.example.org/"
|
assert client.base_url == "https://www.example.org/"
|
||||||
|
|
||||||
|
|
||||||
def test_client_base_url_without_trailing_slash():
|
def test_client_base_url_without_trailing_slash():
|
||||||
client = httpx.Client()
|
client = httpx.Client()
|
||||||
client.base_url = "https://www.example.org/path" # type: ignore
|
client.base_url = "https://www.example.org/path"
|
||||||
assert isinstance(client.base_url, httpx.URL)
|
assert isinstance(client.base_url, httpx.URL)
|
||||||
assert client.base_url == "https://www.example.org/path/"
|
assert client.base_url == "https://www.example.org/path/"
|
||||||
|
|
||||||
|
|
||||||
def test_client_base_url_with_trailing_slash():
|
def test_client_base_url_with_trailing_slash():
|
||||||
client = httpx.Client()
|
client = httpx.Client()
|
||||||
client.base_url = "https://www.example.org/path/" # type: ignore
|
client.base_url = "https://www.example.org/path/"
|
||||||
assert isinstance(client.base_url, httpx.URL)
|
assert isinstance(client.base_url, httpx.URL)
|
||||||
assert client.base_url == "https://www.example.org/path/"
|
assert client.base_url == "https://www.example.org/path/"
|
||||||
|
|
||||||
|
|
||||||
def test_client_headers():
|
def test_client_headers():
|
||||||
client = httpx.Client()
|
client = httpx.Client()
|
||||||
client.headers = {"a": "b"} # type: ignore
|
client.headers = {"a": "b"}
|
||||||
assert isinstance(client.headers, httpx.Headers)
|
assert isinstance(client.headers, httpx.Headers)
|
||||||
assert client.headers["A"] == "b"
|
assert client.headers["A"] == "b"
|
||||||
|
|
||||||
|
|
||||||
def test_client_cookies():
|
def test_client_cookies():
|
||||||
client = httpx.Client()
|
client = httpx.Client()
|
||||||
client.cookies = {"a": "b"} # type: ignore
|
client.cookies = {"a": "b"}
|
||||||
assert isinstance(client.cookies, httpx.Cookies)
|
assert isinstance(client.cookies, httpx.Cookies)
|
||||||
mycookies = list(client.cookies.jar)
|
mycookies = list(client.cookies.jar)
|
||||||
assert len(mycookies) == 1
|
assert len(mycookies) == 1
|
||||||
@ -42,7 +42,7 @@ def test_client_timeout():
|
|||||||
expected_timeout = 12.0
|
expected_timeout = 12.0
|
||||||
client = httpx.Client()
|
client = httpx.Client()
|
||||||
|
|
||||||
client.timeout = expected_timeout # type: ignore
|
client.timeout = expected_timeout
|
||||||
|
|
||||||
assert isinstance(client.timeout, httpx.Timeout)
|
assert isinstance(client.timeout, httpx.Timeout)
|
||||||
assert client.timeout.connect == expected_timeout
|
assert client.timeout.connect == expected_timeout
|
||||||
|
|||||||
@ -17,7 +17,7 @@ def test_client_queryparams_string():
|
|||||||
assert client.params["a"] == "b"
|
assert client.params["a"] == "b"
|
||||||
|
|
||||||
client = httpx.Client()
|
client = httpx.Client()
|
||||||
client.params = "a=b" # type: ignore
|
client.params = "a=b"
|
||||||
assert isinstance(client.params, httpx.QueryParams)
|
assert isinstance(client.params, httpx.QueryParams)
|
||||||
assert client.params["a"] == "b"
|
assert client.params["a"] == "b"
|
||||||
|
|
||||||
|
|||||||
@ -1011,7 +1011,10 @@ def test_response_decode_text_using_autodetect():
|
|||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.reason_phrase == "OK"
|
assert response.reason_phrase == "OK"
|
||||||
assert response.encoding == "ISO-8859-1"
|
# The encoded byte string is consistent with either ISO-8859-1 or
|
||||||
|
# WINDOWS-1252. Versions <6.0 of chardet claim the former, while chardet
|
||||||
|
# 6.0 detects the latter.
|
||||||
|
assert response.encoding in ("ISO-8859-1", "WINDOWS-1252")
|
||||||
assert response.text == text
|
assert response.text == text
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -489,18 +489,18 @@ def test_response_invalid_argument():
|
|||||||
def test_ensure_ascii_false_with_french_characters():
|
def test_ensure_ascii_false_with_french_characters():
|
||||||
data = {"greeting": "Bonjour, ça va ?"}
|
data = {"greeting": "Bonjour, ça va ?"}
|
||||||
response = httpx.Response(200, json=data)
|
response = httpx.Response(200, json=data)
|
||||||
assert (
|
assert "ça va" in response.text, (
|
||||||
"ça va" in response.text
|
"ensure_ascii=False should preserve French accented characters"
|
||||||
), "ensure_ascii=False should preserve French accented characters"
|
)
|
||||||
assert response.headers["Content-Type"] == "application/json"
|
assert response.headers["Content-Type"] == "application/json"
|
||||||
|
|
||||||
|
|
||||||
def test_separators_for_compact_json():
|
def test_separators_for_compact_json():
|
||||||
data = {"clé": "valeur", "liste": [1, 2, 3]}
|
data = {"clé": "valeur", "liste": [1, 2, 3]}
|
||||||
response = httpx.Response(200, json=data)
|
response = httpx.Response(200, json=data)
|
||||||
assert (
|
assert response.text == '{"clé":"valeur","liste":[1,2,3]}', (
|
||||||
response.text == '{"clé":"valeur","liste":[1,2,3]}'
|
"separators=(',', ':') should produce a compact representation"
|
||||||
), "separators=(',', ':') should produce a compact representation"
|
)
|
||||||
assert response.headers["Content-Type"] == "application/json"
|
assert response.headers["Content-Type"] == "application/json"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user