HomeArchitecture x-rays

Python

The architecture of HTTPX, x-rayed

HTTPX enforces its public API with a naming convention you can see straight in the x-ray: every single module is underscore-prefixed (_client.py, _models.py, _transports/). The entire supported surface is whatever __init__.py chooses to re-export — 23 private components behind one public door.

Auto-generated by archsteer xray v0.4.1 against encode/httpx@b5addb6 (httpx/) on 2026-07-05. Read-only static analysis — no code executed, no architecture rules declared. Structure, not judgment.
23
components
18
modules
88
internal edges
4
runtime deps

Module dependency graph

Top 14 modules by connectivity; an arrow means "imports from".

graph LR
    m0["__init__"]
    m1["_api"]
    m2["_auth"]
    m3["_client"]
    m4["_config"]
    m5["_content"]
    m6["_exceptions"]
    m7["_main"]
    m8["_models"]
    m9["_multipart"]
    m10["_transports"]
    m11["_types"]
    m12["_urls"]
    m13["_utils"]
    m0 --> m1
    m0 --> m2
    m0 --> m3
    m0 --> m4
    m0 --> m5
    m0 --> m6
    m0 --> m7
    m0 --> m8
    m0 --> m10
    m0 --> m11
    m0 --> m12
    m1 --> m3
    m1 --> m4
    m1 --> m8
    m1 --> m11
    m1 --> m12
    m2 --> m6
    m2 --> m8
    m2 --> m13
    m3 --> m2
    m3 --> m4
    m3 --> m6
    m3 --> m8
    m3 --> m10
    m3 --> m11
    m3 --> m12
    m3 --> m13
    m4 --> m8
    m4 --> m11
    m4 --> m12
    m5 --> m6
    m5 --> m9
    m5 --> m11
    m5 --> m13
    m6 --> m8
    m7 --> m3
    m7 --> m6
    m7 --> m8
    m8 --> m5
    m8 --> m6
    m8 --> m9
    m8 --> m11
    m8 --> m12
    m8 --> m13
    m9 --> m11
    m9 --> m13
    m10 --> m0
    m10 --> m4
    m10 --> m6
    m10 --> m8
    m10 --> m11
    m10 --> m12
    m11 --> m2
    m11 --> m4
    m11 --> m8
    m11 --> m12
    m12 --> m11
    m12 --> m13
    m13 --> m11
    m13 --> m12

Components by module

_transports · 6__init__ · 1__version__ · 1_api · 1_auth · 1_client · 1_config · 1_content · 1_decoders · 1_exceptions · 1_main · 1_models · 1_multipart · 1_status_codes · 1_types · 1_urlparse · 1

Most connected components

Top 20 of 23 by exported API surface and dependency count.

ComponentModuleKey exports
_client.py_client_is_https_redirect, _port_or_default, _same_origin, UseClientDefault
_exceptions.py_exceptionsHTTPError, RequestError, TransportError, TimeoutException
_main.py_mainprint_help, get_lexer_for_response, format_request_headers, format_response_headers
_models.py_models_is_known_encoding, _normalize_header_key, _normalize_header_value, _parse_content_type_charset
_transports/default.py_transports_load_httpcore_exceptions, map_httpcore_exceptions, ResponseStream, HTTPTransport
_content.py_contentByteStream, IteratorByteStream, AsyncIteratorByteStream, UnattachedStream
_decoders.py_decodersContentDecoder, IdentityDecoder, DeflateDecoder, GZipDecoder
_auth.py_authAuth, FunctionAuth, BasicAuth, NetRCAuth
_utils.py_utilsprimitive_value_to_str, get_environment_proxies, to_bytes, to_str
_api.py_apirequest, stream, get, options
_urlparse.py_urlparseParseResult, urlparse, encode_host, normalize_port
_multipart.py_multipart_format_form_param, _guess_content_type, get_multipart_boundary_from_content_type, DataField
_config.py_configUnsetType, create_ssl_context, Timeout, Limits
_transports/asgi.py_transportsis_running_trio, create_event, ASGIResponseStream, ASGITransport
__init__.py__init__
_transports/wsgi.py_transports_skip_leading_empty_chunks, WSGIByteStream, WSGITransport
_urls.py_urlsURL, QueryParams
_types.py_typesSyncByteStream, AsyncByteStream
_transports/base.py_transportsBaseTransport, AsyncBaseTransport
_transports/mock.py_transportsMockTransport

Declared runtime dependencies

anyiocertifihttpcoreidna

What the structure teaches

One public door, 22 private rooms

Every module except __init__.py is underscore-private. That's not decoration — it gives the maintainers license to refactor anything internal without a deprecation cycle, because the only supported import path is the top-level package.

The transport layer is the extension point

_transports/ separates "what request to make" from "how bytes move": the default transport wraps httpcore, but the same interface admits mock transports for testing, WSGI/ASGI transports for calling your own app in-process, and custom ones. It's the most architecturally deliberate subpackage in the library.

Sync and async share one brain

_client.py holds both Client and AsyncClient, sharing request building, redirect logic, and cookie handling, diverging only where I/O actually happens. The x-ray shows it as the largest, most-connected component — the cost of not maintaining two parallel client codebases.

X-ray your own repo

This page is unedited archsteer xray output plus commentary. The same map of your codebase takes one command, runs locally, and never sends code anywhere: pip install archsteer && archsteer xray

FAQ

How is HTTPX structured internally?

As 23 underscore-private modules re-exported through a single __init__.py: _client.py (sync and async clients sharing one implementation), _models.py (Request/Response), _transports/ (the pluggable layer that actually moves bytes, wrapping httpcore by default), plus focused modules for auth, config, content, and URLs.

What is the HTTPX transport API?

A small interface (handle_request / handle_async_request) that separates the client's HTTP semantics from byte transport. Swapping it lets you test against a MockTransport, call an ASGI/WSGI app in-process without a socket, or add custom behavior — all without touching client code.

How was this architecture map generated?

By running `archsteer xray` (an open-source, MIT-licensed CLI) against the httpx/ package directory of the public GitHub repo — read-only static analysis, no code executed. Reproduce it with `pip install archsteer && archsteer xray`.

More x-rays