Skip to content

Repository files navigation

Action0-Req

CI PyPI

Typed Python representations of HTTP requests and responses with convenient creation, duplication and manipulation. The companion of action0-url, which provides the URL representation.

Requires Python 3.11 or newer.

Full documentation including the API reference: https://laughinjar.github.io/action0-req/

Status: the core API is complete — the header name, status code and method constants, the Headers mapping, Request and Response, and sync/async body streaming via BodyProducer (BytesBody, FileBody, IterableBody, AsyncIterableBody).

Installation

pip install action0-req  # or uv add action0-req

Usage

Header, Status and Method are StrEnum/IntEnum constants for the IANA-registered header field names, status codes and request methods — every member is its string or integer value:

from action0.req import Header, Method, Status

print(Header.CONTENT_TYPE)  # Content-Type
print(Method.POST)  # POST
print(Status.NOT_FOUND)  # 404
print(Status.NOT_FOUND.phrase)  # Not Found
print(Status.NOT_FOUND.is_client_error)  # True

Headers is an ordered, case-insensitive, multi-value aware mapping of header fields that preserves the representation (order and casing) exactly:

from action0.req import Headers

headers = Headers({"Content-Type": "text/html"})
headers.add("Set-Cookie", "a=1")
headers.add("set-cookie", "b=2")
print(headers["CONTENT-TYPE"])  # text/html
print(headers.get_all("Set-Cookie"))  # ['a=1', 'b=2']
print(headers.as_str(separator="\n"))  # "\r\n" by default
# Content-Type: text/html
# Set-Cookie: a=1
# set-cookie: b=2

# repr()/str() redact secrets, only as_str() renders them
print(Headers({"Authorization": "Bearer tok"}))  # Headers(Authorization: ***)

Request combines a method, a Url (from action0-url), Headers, a meta dict for application metadata (never on the wire) and a body (bytes, str or a streaming BodyProducer — retrievable in any of the three forms):

from action0.req import Request

req = Request("https://api.example.com/items", query={"page": 2})
req.headers["Accept"] = "application/json"
print(req.as_str(separator="\n"))  # "\r\n" by default
# GET /items?page=2 HTTP/1.1
# Host: api.example.com
# Accept: application/json

post = req.copy(method="POST", body='{"a": 1}')
print(post.body_bytes())  # b'{"a": 1}'
print(post)  # Request(POST https://api.example.com/items?page=2)

Response mirrors it for the server side — status (with reason phrase fallback and category properties), headers, body:

from action0.req import Response, Status

resp = Response(Status.NOT_FOUND, headers={"Content-Type": "text/plain"}, body="not here")
print(resp.phrase, resp.is_client_error)  # Not Found True
print(resp.as_str(separator="\n"))  # "\r\n" by default
# HTTP/1.1 404 Not Found
# Content-Type: text/plain

Development

The project is managed with uv; uv run creates and syncs the virtual environment automatically:

uv run pytest        # run the tests (incl. the docstring examples as doctests)
uv run ruff check    # lint
uv run ruff format   # format
uv run mypy          # type-check (also: uv run pyright, uv run ty check)

# build the docs (Sphinx; deployed to GitHub Pages on push to main)
uv run --group docs sphinx-build -W docs docs/_build/html

Releasing

The version lives only in src/action0/req/__init__.py (__version__). To release: bump it, merge to main, then tag the release commit and push the tag — the release workflow re-runs all checks, verifies the tag matches __version__, builds sdist + wheel and publishes to PyPI via trusted publishing:

git tag v0.1.0
git push origin v0.1.0

AI-assisted development

In the spirit of transparency: most of this project's code, tests and documentation are written by Claude Code, Anthropic's coding agent — under human direction and review. The designs are specified, discussed and iterated by a human, and every change is reviewed before it lands in main or in a release. AI-authored commits carry a Co-Authored-By: Claude ... trailer.

About action0

This is just the namespace I like to use for my personal projects. I quite like namespaces.

About

Typed Python representations of HTTP requests and responses with convenient creation, duplication and manipulation

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages