0.8.0 — Sync Client + httpx2-aligned naming
httpware 0.8.0 — Sync Client + httpx2-aligned naming
Breaking release. Renames the async middleware surface to use the Async*/async_* prefix (matching httpx2's convention), drops Retry(attempt_timeout=...), and adds a fully-featured sync Client.
If you have existing async code, migration is one mechanical pass through your imports — see "Breaking changes" below.
What's new
- Sync
Client. Full parity withAsyncClient: typed response decoding, middleware chain,Retry+Bulkhead,stream()context manager, lifecycle (with+close()), andhttpx2.Clientinjection. Designed for CLI tools, scripts, Django sync views, Jupyter, and threaded service workers. - Sync
Middleware+Next+ decorators.from httpware import Middleware, Next, before_request, after_response, on_error. Same protocol shape as async; bodies are sync. - Sync
RetryandBulkhead. Same resilience semantics as their async siblings, withtime.sleepandthreading.Semaphore. SyncRetrysharesRetryBudgetwith async — one instance is safe across both worlds. RetryBudgetis now thread-safe via an internalthreading.Lock. Async users see no behavioral difference; the overhead is invisible (~50–100 ns per op).- Shared helpers in
_internal/.map_httpx2_exception,_raise_on_status_error, the streaming-body marker, and the body predicates moved to_internal/exception_mapping.pyand_internal/status.py. No public-API change other than the exports listed below.
Breaking changes
Renames
| Old name | New name |
|---|---|
httpware.Middleware |
httpware.AsyncMiddleware |
httpware.Next |
httpware.AsyncNext |
httpware.Retry |
httpware.AsyncRetry |
httpware.Bulkhead |
httpware.AsyncBulkhead |
httpware.before_request |
httpware.async_before_request |
httpware.after_response |
httpware.async_after_response |
httpware.on_error |
httpware.async_on_error |
httpware.middleware.chain.compose |
httpware.middleware.chain.compose_async |
Removals
Retry(attempt_timeout=...)/AsyncRetry(attempt_timeout=...)is removed. It usedasyncio.timeoutto bound the whole attempt as a structured cancellation; this had no clean sync equivalent and is mostly covered byhttpx2.Timeout(per-phase I/O bounds) for typical use cases. Users who genuinely need whole-attempt wall-clock bounds can compose their own timeout middleware.
New names that previously meant something else
The unprefixed Middleware, Next, Retry, Bulkhead, before_request, after_response, on_error now refer to sync types. Code that imports them and expects async behavior will break at type-check time (or at the first await site).
Migration
A one-pass sed/regex covers most of the work:
# in your project root:
git ls-files '*.py' | xargs sed -i.bak \
-e 's/from httpware import \(.*\)\bMiddleware\b/from httpware import \1AsyncMiddleware/g' \
-e 's/from httpware import \(.*\)\bNext\b/from httpware import \1AsyncNext/g' \
-e 's/from httpware import \(.*\)\bRetry\b/from httpware import \1AsyncRetry/g' \
-e 's/from httpware import \(.*\)\bBulkhead\b/from httpware import \1AsyncBulkhead/g' \
-e 's/from httpware import \(.*\)\bbefore_request\b/from httpware import \1async_before_request/g' \
-e 's/from httpware import \(.*\)\bafter_response\b/from httpware import \1async_after_response/g' \
-e 's/from httpware import \(.*\)\bon_error\b/from httpware import \1async_on_error/g'Then update the symbol references in the file bodies (your type checker will guide you). If you were using Retry(attempt_timeout=...), remove the kwarg and rely on httpx2.Timeout or write a minimal timeout middleware.
References
- Design spec:
planning/specs/2026-06-07-sync-client-design.md - Implementation plan:
planning/plans/2026-06-07-sync-client-plan.md - Engineering notes:
planning/engineering.md§3 Seam A, §5 module layout - Source spec parent (httpx convention):
planning/archive/specs/2026-06-03-thin-httpx2-wrapper-design.md