pyreqwest - Powerful and fast Rust based HTTP client. Built on top of and inspired by reqwest.
Why
- No reinvention of the wheel - built on top of widely used reqwest and other Rust HTTP crates
- Secure and fast - no C-extension code, no Python code/dependencies, no
unsafecode - Ergonomic and easy to use - similar API as in reqwest, fully type-annotated
- Testing ergonomics - mocking included, can also connect into ASGI apps
Using this is a good choice when:
- You care about throughput and latency, especially in high concurrency scenarios
- You want a single solution to serve all your HTTP client needs
This is not a good choice when:
- You want a pure Python solution allowing debugging of the HTTP client internals
- You use alternative Python implementations or Python version older than 3.11
Features
- High performance, see notes and benchmarks
- Asynchronous and synchronous HTTP clients
- Customizable via middlewares and custom JSON serializers
- Ergonomic as
reqwest - HTTP/1.1 and HTTP/2 support (also HTTP/3 when it stabilizes)
- Mocking and testing utilities (can also connect to ASGI apps)
- Fully type-safe with Python type hints
- Full test coverage
- Free threading, see notes
Standard HTTP features you would expect
- HTTPS support (using rustls)
- Request and response body streaming
- Connection pooling
- JSON, URLs, Headers, Cookies etc. (all serializers in Rust)
- Automatic decompression (zstd, gzip, brotli, deflate)
- Automatic response decoding (charset detection)
- Multipart form support
- Proxy support (also SOCKS)
- Redirects
- Timeouts
- Authentication (Basic, Bearer)
- Cookie management
Quickstart
# uv add pyreqwest from pyreqwest.client import ClientBuilder, SyncClientBuilder async def example_async(): async with ClientBuilder().error_for_status(True).build() as client: response = await client.get("https://httpbun.com/get").query({"q": "val"}).build().send() print(await response.json()) def example_sync(): with SyncClientBuilder().error_for_status(True).build() as client: print(client.get("https://httpbun.com/get").query({"q": "val"}).build().send().json())
Context manager usage is optional, but recommended. Also close() methods are available.
Mocking in pytest
from pyreqwest.client import ClientBuilder from pyreqwest.pytest_plugin import ClientMocker async def test_client(client_mocker: ClientMocker) -> None: client_mocker.get(path="/api").with_body_text("Hello Mock") async with ClientBuilder().build() as client: response = await client.get("http://example.invalid/api").build().send() assert response.status == 200 and await response.text() == "Hello Mock" assert client_mocker.get_call_count() == 1
Manual mocking is available via ClientMocker.create_mocker(MonkeyPatch).
Simple request interface
This is only recommended for simple use-cases such as scripts. Usually, the full client API should be used which reuses connections and has other optimizations.
# Sync example from pyreqwest.simple.sync_request import pyreqwest_get response = pyreqwest_get("https://httpbun.com/get").query({"q": "val"}).send() print(response.json())
# Async example from pyreqwest.simple.request import pyreqwest_get response = await pyreqwest_get("https://httpbun.com/get").query({"q": "val"}).send() print(await response.json())
Documentation
See docs
See examples
