diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml index ce3df5db..ae70a6b3 100644 --- a/.github/workflows/test-suite.yml +++ b/.github/workflows/test-suite.yml @@ -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" diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f1233ef..ee0f81f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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**: diff --git a/docs/advanced/clients.md b/docs/advanced/clients.md index a55fc596..90969cef 100644 --- a/docs/advanced/clients.md +++ b/docs/advanced/clients.md @@ -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, )` 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) ``` diff --git a/docs/api.md b/docs/api.md index d01cc649..f1bd50c9 100644 --- a/docs/api.md +++ b/docs/api.md @@ -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** diff --git a/docs/quickstart.md b/docs/quickstart.md index aa203a83..38da2fec 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -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) { ... diff --git a/docs/third_party_packages.md b/docs/third_party_packages.md index 78ecc5a7..546607f7 100644 --- a/docs/third_party_packages.md +++ b/docs/third_party_packages.md @@ -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. + + ## 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 - - ### urllib3-transport [GitHub](https://gist.github.com/florimondmanca/d56764d78d748eb9f73165da388e546e) diff --git a/httpx/__version__.py b/httpx/__version__.py index 0a684ac3..801bfacf 100644 --- a/httpx/__version__.py +++ b/httpx/__version__.py @@ -1,3 +1,3 @@ __title__ = "httpx" __description__ = "A next generation HTTP client, for Python 3." -__version__ = "0.28.0" +__version__ = "0.28.1" diff --git a/httpx/_client.py b/httpx/_client.py index 2249231f..13cd9336 100644 --- a/httpx/_client.py +++ b/httpx/_client.py @@ -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): diff --git a/httpx/_models.py b/httpx/_models.py index 67d74bf8..2cc86321 100644 --- a/httpx/_models.py +++ b/httpx/_models.py @@ -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 diff --git a/httpx/_transports/default.py b/httpx/_transports/default.py index d5aa05ff..fc8c7097 100644 --- a/httpx/_transports/default.py +++ b/httpx/_transports/default.py @@ -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. diff --git a/pyproject.toml b/pyproject.toml index 9e671911..675d2ad4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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 = [ diff --git a/requirements.txt b/requirements.txt index 0d8ba2ef..caa094f3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -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