Skip to main content

lothc logo

lothc

PyPI CI codecov Python versions License

Lord Of The Http Clients — a typed HTTP client for Python, built on pyreqwest (an awesome Rust-backed HTTP client), with first-class optional support for pydantic and msgspec as both decode and encode targets.

Installing

uv add 'lothc[pydantic,msgspec]'

(Any subset of the extras works — the base package alone gets you bytes/dict support.)

Quickstart

from lothc import HTTPClient
from pydantic import BaseModel


class Pokemon(BaseModel):
    id: int
    name: str


async with HTTPClient.build(base_url="https://pokeapi.co/api/v2/") as client:
    pikachu = await client.get("pokemon/pikachu", response_data_type=Pokemon)
    print(pikachu)  # id=25 name='pikachu'

Why?

Why was lothc built, and why should you use it?

pyreqwest is a genuinely excellent HTTP client for Python, fast because the heavy lifting happens in Rust, not pure Python. But its API is a builder pattern (client.get(path).build() before you can even .send() it), unfamiliar to anyone coming from requests/httpx/niquests, where a call is just client.get(url, params=..., headers=...). lothc wraps pyreqwest with exactly that familiar shape, so you get pyreqwest's speed without giving up the ergonomics Python HTTP users already expect.

The other reason: Python's most popular third-party HTTP clients (httpx, aiohttp, niquests) all have first-class JSON support: call .json() and get back a dict. But in order for a Python project to be end-to-end type-safe, data crossing I/O boundaries must be validated, and if invalid, handled accordingly (raise an error) — a plain dict does neither. Closing that gap is exactly what lothc is designed for.

The original idea was to make lothc backend-agnostic: httpx, aiohttp, niquests, and pyreqwest all interchangeable underneath the same typed lothc interface, so switching backends never meant switching your call sites. However, in the author's opinion there's currently no compelling reason not to just use pyreqwest, so pyreqwest is the only backend implemented today, but, if there's demand for an httpx/aiohttp/niquests backend, the author is happy to consider adding one.

Fast

HTTP client throughput race — lothc and pyreqwest finish in well under a fifth of a second, other libraries take much longer

Benchmarked with perf.py against a tiny Rust-based static JSON server, 10,000 requests at concurrency 100 — including lothc's fully-typed decode targets (response_data_type= a msgspec Struct or a pydantic BaseModel), not just raw bytes or an untyped dict. The object handed back from those runs isn't just parsed JSON — it's a real, constructed, field-validated instance of your own type, and that validation cost is included in the numbers, not benchmarked around. Decoding into a real msgspec Struct even edged out the unvalidated dict path in this run. Full numbers: docs/benchmarks.md.

Highlights

Pass response_data_type to any lothc call and get back a real, constructed, field-validated pydantic BaseModel or msgspec Struct, instead of the plain dict .json() leaves you to validate yourself. See Benchmarks for what that costs (usually nothing).

Two clients, one API HTTPClient (async) and SyncHTTPClient (sync) — identical surface, both backed by pyreqwest.
Every verb get/get_result, post, put, patch, delete, head, download — see Verbs.
Typed params, headers & forms A BaseModel/Struct for query params or headers (with None-field omission), or a real multipart body via form=.
Precise static types Every verb is paired @overloads, not a cast-laden generic — your editor knows the exact return type.
SSE & streaming Spec-compliant SSE — automatic reconnect with Last-Event-ID, server retry: honored, typed decode (discriminated unions included) — plus raw or NDJSON-typed stream_get/stream_post — see SSE / Streaming.
Retries with real backoff max_retries/retry_methods, a genuine pyreqwest middleware hook, Retry-After-aware — see Retries.
Authentication Static bearer_token, a per-request-refreshed bearer_auth, basic_auth, or default_headers for anything else — plus a ready-made OAuth 2 client-credentials provider (OAuthProvider: mint, leeway-based renewal, refresh-then-mint fallback, optional on-disk token cache) — see Authentication.
Cookies, redirects, proxy cookie_store, follow_redirects/max_redirects, proxy= — see Networking.
A real error hierarchy HTTPTransportError/HTTPTimeoutError/HTTPConnectionError for no response, HTTPResponseError for 4xx/5xx — see Error handling.
Everything optional pydantic, msgspec — works with neither, either, or both installed.

Development

See CLAUDE.md and style-guide.md for architecture notes and the (non-obvious in places) design conventions this codebase relies on.

task deps-sync    # install
task test         # run tests
task check        # lint + format-check + typecheck (what CI runs)

Release files for lothc 0.0.14

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lothc 0.0.14
File Size Uploaded
lothc-0.0.14.tar.gz 43.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for lothc 0.0.14
File Interpreter ABI Platform
lothc-0.0.14-py3-none-any.whl Python 3 none any Details

Total release size: 85.7 kB

Release files / lothc-0.0.14.tar.gz

Download URL lothc-0.0.14.tar.gz
Size 43.8 kB
Tags Source
SHA-256 checksum
How to use checksums
0b4f10f93b935679989e65b2975ef2714134a76d74f6be8f444c94b344a0ce23
BLAKE2b-256 checksum
How to use checksums
ffd0ecf1313da1dd570670dd5ac34c23cd3f119373e29ee0ed4e76a161192017
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / lothc-0.0.14-py3-none-any.whl

Download URL lothc-0.0.14-py3-none-any.whl
Size 41.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
34d507bda9e1af2ac0a7cf1b68d63570db74f4db0b2c4b20e98af430becbf072
BLAKE2b-256 checksum
How to use checksums
af87951c0fb595dcd947dbc4afd1ab5567217090dd93be2384373b60421f674d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

0.0.19

2 release files

0.0.18

2 release files

0.0.17

2 release files

0.0.16

2 release files

0.0.15

2 release files

This release

0.0.14 This release

2 release files

0.0.11

2 release files

0.0.10

2 release files

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page