Merge branch 'master' into feature/allow-multipart-without-files

This commit is contained in:
-LAN- 2025-06-11 16:49:46 +08:00 committed by GitHub
commit 4bb86a4e60
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 108 additions and 75 deletions

View File

@ -14,7 +14,7 @@ jobs:
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
steps:
- uses: "actions/checkout@v4"

View File

@ -4,13 +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/).
## Dev
## 0.28.1 (6th December, 2024)
* Fix SSL case where `verify=False` together with client side certificates.
## 0.28.0 (28th November, 2024)
The 0.28 release includes a limited set of deprecations.
Be aware that the default *JSON request bodies now use a more compact representation*. This is generally considered a prefered style, tho may require updates to test suites.
The 0.28 release includes a limited set of deprecations...
**Deprecations**:

View File

@ -270,8 +270,9 @@ multipart file encoding is available by passing a dictionary with the
name of the payloads as keys and either tuple of elements or a file-like object or a string as values.
```pycon
>>> files = {'upload-file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel')}
>>> r = httpx.post("https://httpbin.org/post", files=files)
>>> with open('report.xls', 'rb') as report_file:
... files = {'upload-file': ('report.xls', report_file, 'application/vnd.ms-excel')}
... r = httpx.post("https://httpbin.org/post", files=files)
>>> print(r.text)
{
...
@ -318,7 +319,10 @@ To do that, pass a list of `(field, <file>)` items instead of a dictionary, allo
For instance this request sends 2 files, `foo.png` and `bar.png` in one request on the `images` form field:
```pycon
>>> files = [('images', ('foo.png', open('foo.png', 'rb'), 'image/png')),
('images', ('bar.png', open('bar.png', 'rb'), 'image/png'))]
>>> r = httpx.post("https://httpbin.org/post", files=files)
>>> with open('foo.png', 'rb') as foo_file, open('bar.png', 'rb') as bar_file:
... files = [
... ('images', ('foo.png', foo_file, 'image/png')),
... ('images', ('bar.png', bar_file, 'image/png')),
... ]
... r = httpx.post("https://httpbin.org/post", files=files)
```

View File

@ -159,3 +159,18 @@ what gets sent over the wire.*
* `def delete(name, [domain], [path])`
* `def clear([domain], [path])`
* *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**

View File

@ -174,8 +174,9 @@ Form encoded data can also include multiple values from a given key.
You can also upload files, using HTTP multipart encoding:
```pycon
>>> files = {'upload-file': open('report.xls', 'rb')}
>>> r = httpx.post("https://httpbin.org/post", files=files)
>>> with open('report.xls', 'rb') as report_file:
... files = {'upload-file': report_file}
... r = httpx.post("https://httpbin.org/post", files=files)
>>> print(r.text)
{
...
@ -190,8 +191,9 @@ You can also explicitly set the filename and content type, by using a tuple
of items for the file value:
```pycon
>>> files = {'upload-file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel')}
>>> r = httpx.post("https://httpbin.org/post", files=files)
>>> with open('report.xls', 'rb') report_file:
... files = {'upload-file': ('report.xls', report_file, 'application/vnd.ms-excel')}
... r = httpx.post("https://httpbin.org/post", files=files)
>>> print(r.text)
{
...
@ -206,8 +208,9 @@ If you need to include non-file data fields in the multipart form, use the `data
```pycon
>>> data = {'message': 'Hello, world!'}
>>> files = {'file': open('report.xls', 'rb')}
>>> r = httpx.post("https://httpbin.org/post", data=data, files=files)
>>> with open('report.xls', 'rb') as report_file:
... files = {'file': report_file}
... r = httpx.post("https://httpbin.org/post", data=data, files=files)
>>> print(r.text)
{
...

View File

@ -2,67 +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.
<!-- NOTE: Entries are alphabetised. -->
## 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.
### Hishel
[GitHub](https://github.com/karpetrosyan/hishel) - [Documentation](https://hishel.com/)
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
[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).
### 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.
Provides authentication classes to be used with HTTPX's [authentication parameter](advanced/authentication.md#customizing-authentication).
### httpx-caching
@ -70,22 +24,76 @@ A utility for record and repeat an http request.
This package adds caching functionality to HTTPX
### httpx-socks
[GitHub](https://github.com/romis2012/httpx-socks)
Proxy (HTTP, SOCKS) transports for httpx.
### httpx-sse
[GitHub](https://github.com/florimondmanca/httpx-sse)
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
<!-- NOTE: this list is in alphabetical order. -->
### urllib3-transport
[GitHub](https://gist.github.com/florimondmanca/d56764d78d748eb9f73165da388e546e)

View File

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

View File

@ -1723,7 +1723,7 @@ class AsyncClient(BaseClient):
if not isinstance(request.stream, AsyncByteStream):
raise RuntimeError(
"Attempted to send an sync request with an AsyncClient instance."
"Attempted to send a sync request with an AsyncClient instance."
)
with request_context(request=request):

View File

@ -964,7 +964,7 @@ class Response:
Automatically called if the response body is read to completion.
"""
if not isinstance(self.stream, SyncByteStream):
raise RuntimeError("Attempted to call an sync close on an async stream.")
raise RuntimeError("Attempted to call a sync close on an async stream.")
if not self.is_closed:
self.is_closed = True
@ -1045,7 +1045,7 @@ class Response:
if self.is_closed:
raise StreamClosed()
if not isinstance(self.stream, AsyncByteStream):
raise RuntimeError("Attempted to call an async iterator on an sync stream.")
raise RuntimeError("Attempted to call an async iterator on a sync stream.")
self.is_stream_consumed = True
self._num_bytes_downloaded = 0
@ -1068,7 +1068,7 @@ class Response:
Automatically called if the response body is read to completion.
"""
if not isinstance(self.stream, AsyncByteStream):
raise RuntimeError("Attempted to call an async close on an sync stream.")
raise RuntimeError("Attempted to call an async close on a sync stream.")
if not self.is_closed:
self.is_closed = True

View File

@ -355,7 +355,7 @@ class AsyncHTTPTransport(AsyncBaseTransport):
else: # pragma: no cover
raise ValueError(
"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.

View File

@ -25,6 +25,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Internet :: WWW/HTTP",
]
dependencies = [

View File

@ -19,7 +19,7 @@ twine==6.0.1
# Tests & Linting
coverage[toml]==7.6.1
cryptography==44.0.0
cryptography==44.0.1
mypy==1.13.0
pytest==8.3.4
ruff==0.8.1