Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ wheels/
.venv
uv.lock
plan.md
site/
13 changes: 13 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: 2

build:
os: "ubuntu-22.04"
tools:
python: "3.12"

python:
install:
- requirements: docs/requirements.txt

mkdocs:
configuration: mkdocs.yml
11 changes: 5 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@ Guidance for AI agents (Claude Code, etc.) working in this repository.

**Where to find what:**

- [`docs/engineering.md`](docs/engineering.md) — the distilled design reference: invariants and *why*, the five protocol seams, exception contract, module layout, testing patterns, optional-extras pattern, remaining roadmap. Read this before adding any new module or extension point.
- [`docs/deferred-work.md`](docs/deferred-work.md) — review-surfaced items that are real but not actionable now.
- [`docs/superpowers/specs/`](docs/superpowers/specs/) and [`docs/superpowers/plans/`](docs/superpowers/plans/) — per-feature design specs and implementation plans (active work).
- [`docs/archive/`](docs/archive/) — historical bmad-era planning bundle (PRD, architecture, epics, product briefs, per-story specs for 1-1 through 1-5). Consult only for original rationale or specific FR/NFR citations.
- [`docs/dev/engineering.md`](docs/dev/engineering.md) — the distilled design reference: invariants and *why*, the five protocol seams, exception contract, module layout, testing patterns, optional-extras pattern, remaining roadmap. Read this before adding any new module or extension point.
- [`planning/deferred-work.md`](planning/deferred-work.md) — review-surfaced items that are real but not actionable now.
- [`planning/specs/`](planning/specs/) and [`planning/plans/`](planning/plans/) — per-feature design specs and implementation plans (active work).

**Per-feature workflow:** brainstorming → spec in `docs/superpowers/specs/` → writing-plans → plan in `docs/superpowers/plans/` → executing-plans (or subagent-driven-development) → requesting-code-review → finishing-a-development-branch. Topic slugs are kebab-case descriptions (`msgspec-decoder-adapter`), not story IDs.
**Per-feature workflow:** brainstorming → spec in `planning/specs/` → writing-plans → plan in `planning/plans/` → executing-plans (or subagent-driven-development) → requesting-code-review → finishing-a-development-branch. Topic slugs are kebab-case descriptions (`msgspec-decoder-adapter`), not story IDs.

## Commands

Expand Down Expand Up @@ -99,5 +98,5 @@ Five documented internal boundaries. AI agents must respect them — never cross

## When in doubt

- Check [`docs/engineering.md`](docs/engineering.md) before adding a new module or extension point; `docs/archive/architecture.md` has the deeper historical rationale if needed.
- Check [`docs/dev/engineering.md`](docs/dev/engineering.md) before adding a new module or extension point.
- Surface ambiguity as a documentation gap rather than improvising.
50 changes: 4 additions & 46 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,48 +1,6 @@
# Contributing to httpware
# Contributing

Thank you for your interest in contributing. `httpware` is an open-source resilience-first async HTTP client framework for Python, maintained under the [`modern-python`](https://github.com/modern-python) org.
The contributing guide is published as part of the project documentation:
**https://httpware.readthedocs.io/en/latest/dev/contributing/**

## Quick start

```bash
git clone https://github.com/modern-python/httpware.git
cd httpware
just install # uv lock --upgrade && uv sync --all-extras --frozen --group lint
just lint # ruff format + ruff check + ty check
just test # pytest with coverage
```

## Development workflow

1. **Open an issue first** for non-trivial changes — design discussion catches issues earlier than code review.
2. **Branch from `main`**, use a descriptive name (`feat/retry-budget-jitter`, `fix/transport-cancel-leak`).
3. **Run `just lint` and `just test`** locally before pushing. CI will reject changes that fail either.
4. **Add tests** for any code change. Property-based tests (via Hypothesis) are required for concurrency-sensitive code (retry budget, bulkhead, retry interleaving).
5. **Open a pull request** against `main`. PR titles use conventional-commits style (`feat:`, `fix:`, `docs:`, `refactor:`, `test:`, `chore:`).

## Code style

- `ruff format` enforces formatting; do not hand-format.
- Type-check with `ty` (Astral). Use `# ty: ignore[<rule>]` for suppressions, not `# type: ignore`.
- Do NOT use `from __future__ import annotations`. Python 3.11+ is the floor.
- Module docstrings are required; per-method docstrings only when types alone are insufficient.

See `docs/concepts/middleware.md` and `docs/recipes/custom-middleware.md` (once published) for architecture conventions.

## Architecture invariants

These are enforced by CI grep gates. Do not break them in pull requests:

- No `import httpx2` outside `src/httpware/transports/httpx2.py`.
- No `httpx2._*` (private API) usage anywhere in the library.
- No `from __future__ import annotations`.
- No `print()` calls.
- No `logging.basicConfig()` or bare `logging.getLogger()`.

## Code of Conduct

By participating in this project, you agree to abide by its Code of Conduct. Be excellent to one another.

## License

By contributing, you agree that your contributions will be licensed under the project's MIT license.
Source: [`docs/dev/contributing.md`](docs/dev/contributing.md).
22 changes: 7 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

**Async HTTP client framework for Python.**

`httpware` is a typed, async HTTP client library built on `httpx2` with a protocol-based seam so the transport is swappable. Middleware composes via an onion model. Pydantic and msgspec response decoding ship out of the box. `RecordedTransport` replaces respx for transport-level tests.
`httpware` is a typed, async HTTP client library with a protocol-based seam so the transport is swappable (`httpx2` ships as the default). Middleware composes via an onion model. Pydantic and msgspec response decoding ship out of the box. `RecordedTransport` replaces `respx` for transport-level tests.

> **Status:** Pre-1.0 (0.1.0 alpha). Public API is subject to change between minor releases until v1.0. Resilience middleware (retry / timeout / bulkhead), streaming, and observability are not yet shipped — track progress on GitHub.
> **Status:** Pre-1.0 (0.1.0 alpha). Public API is subject to change between minor releases until v1.0. Resilience middleware (retry / timeout / bulkhead), streaming, and observability are not yet shipped.

## Install

Expand All @@ -23,7 +23,7 @@ Optional extras:
pip install httpware[msgspec] # MsgspecDecoder
```

(`otel`, `niquests`, and `all` extras are declared but their integrations have not shipped yet.)
(`otel`, `niquests`, and `all` extras are declared; integrations have not shipped yet.)

## Quickstart

Expand All @@ -43,20 +43,12 @@ async def main() -> None:
print(user.name)
```

## What ships in 0.1.0
## 📚 [Documentation](https://httpware.readthedocs.io)

- **`AsyncClient`** — eight HTTP method shortcuts (`get`, `post`, `put`, `patch`, `delete`, `head`, `options`, `request`) with typed `response_model` overloads; per-call overrides for `headers`, `params`, `cookies`, `timeout`, `json`, `content`; httpx-style `base_url` join; `with_options(...)` returns a view sharing the same transport.
- **Transport-agnostic seam.** `httpx2` is confined to `httpware.transports.httpx2.Httpx2Transport`. Implement the `Transport` protocol to swap backends.
- **Middleware foundation.** `Middleware` protocol, `Next` type alias, and phase decorators (`@before_request`, `@after_response`, `@on_error`). The chain is composed at `AsyncClient` construction; consumers don't compose chains themselves.
- **Pluggable response decoding.** `PydanticDecoder` (default) with cached `TypeAdapter`; `MsgspecDecoder` via `httpware[msgspec]`.
- **`RecordedTransport`** — built-in test double with a route table, observed-request list, and `aclose_calls` counter.
- **Status-keyed exception hierarchy** — `StatusError`, 4xx / 5xx subclasses, plain typed fields (`status: int`, `body: bytes`, `headers`, `json`, `request_method`, `request_url`). Pickleable; userinfo redacted in `__repr__`.
- **No `httpx2` exception types** leak through `httpware`. The transport seam maps them to `httpware` exceptions.
## 📦 [PyPI](https://pypi.org/project/httpware)

## 📝 [License](./LICENSE)

## Part of `modern-python`

Browse the full list of templates and libraries in [`modern-python`](https://github.com/modern-python) — see the org profile for the categorized index.

## License

MIT — see [LICENSE](./LICENSE).
17 changes: 0 additions & 17 deletions docs/archive/README.md

This file was deleted.

Loading
Loading