Skip to content

Tags: modern-python/httpware

Tags

0.15.0

Toggle 0.15.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat!: status-agnostic response-body cap (max_response_body_bytes) (#78)

* feat: add reason discriminator to ResponseTooLargeError

Status-agnostic semantics + explicit declared/streamed trip mode, ahead of
the max_response_body_bytes cap rework. Existing stream() Content-Length
checks pass reason="declared"; restructured in a later task.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: add pure _accumulate_capped core with property test

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: add shared _read_capped streaming accumulator

_read_capped / _read_capped_async wrap the pure core with the Content-Length
early-reject and the buffered Response rebuild; _safe_extensions drops the
stale network_stream. Caller owns the stream lifecycle.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat!: replace max_error_body_bytes with max_response_body_bytes

Status-agnostic, decoded-byte cap enforced at the non-streaming terminal via a
streaming capped-accumulator (send(stream=True) + _read_capped). Branches on
cap is None so the default path keeps plain send() and .elapsed. Construction
validates >= 1. The old error-only param is removed (pre-1.0, no shim).

BREAKING CHANGE: max_error_body_bytes is replaced by max_response_body_bytes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: bound stream() error pre-read via _read_capped

Both stream() error branches route the 4xx/5xx pre-read through the shared
accumulator when a cap is set, so chunked/compression-bombed error bodies are
caught instead of read unbounded; exc.response.content stays populated.
User-driven success streaming is never capped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: lock ResponseTooLargeError resilience semantics

Cap trips are not retried, do not trip the circuit breaker, and an over-cap
retryable 5xx surfaces as ResponseTooLargeError (cap-wins). No prod change —
these assert the behavior that falls out of the ClientError hierarchy.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: promote response-body cap into architecture; retire deferred item

Rewrite architecture/client.md 'Bounded response bodies' and the errors.md
ResponseTooLargeError entry for the status-agnostic decoded-byte cap; remove the
actioned deferred item; add the 0.15.0 release note; check in the change bundle
(design.md + plan.md).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(planning): mark response-body-cap bundle shipped (#78)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: correct capped-rebuild header handling + skip bodiless responses

Two bugs in the capped read path found in review of #78:

- The rebuilt Response kept content-encoding while holding already-decoded
  content, so httpx2 re-decompressed and crashed on every compressed body under
  the cap. Strip content-encoding / transfer-encoding / (compressed)
  content-length via _buffered_headers; httpx2 recomputes content-length.
- A bodiless response (HEAD / 204 / 304) with a large declared Content-Length
  was falsely rejected. _response_has_body short-circuits these: read the empty
  body and return the original response unchanged, preserving its headers (HEAD
  legitimately echoes the entity length).

Adds within-cap compressed-body and bodiless regression tests at the
_read_capped, send(), and stream() levels.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

0.14.0

Toggle 0.14.0's commit message

Verified

This commit was signed with the committer’s verified signature.
lesnik512 Artur Shiriev
chore(planning): archive circuit-breaker-state bundle, ship 0.14.0 (#70)

Post-merge bookkeeping for PR #70: fill the 0.14.0 release-notes PR number,
mark the bundle shipped (pr: 70), move it active -> archive, flip its Index
line to Archived, and trim the deferred CircuitBreaker entry to just manual
control now that read-only state has shipped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

0.13.0

Toggle 0.13.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat(circuit-breaker): time-based failure-rate trip mode (0.13.0) (#69)

* feat(circuit-breaker): add time-bucketed _RollingWindow recorder

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(circuit-breaker): thread rate-mode config + validation

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(circuit-breaker): rate-over-window trip mode

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(circuit-breaker): assert rate-mode circuit.opened attributes

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(circuit-breaker): document rate mode; 0.13.0 release notes

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(planning): add the circuit-breaker-rate-mode change bundle

Design + plan for the opt-in time-based failure-rate trip mode, and the
Active Index entry. Bundle stays active/draft until merge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(circuit-breaker): document rate mode in the module docstring

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(planning): archive the circuit-breaker-rate-mode bundle (#69)

Ship bookkeeping for PR #69: fill the 0.13.0 release-notes PR number, mark
the bundle shipped (pr: 69), move it from changes/active/ to changes/archive/,
flip its Index line to Archived, and trim the deferred "CircuitBreaker v2" item
to the still-open axes (count-based window, manual control + state).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(circuit-breaker): clarify mode-switch precedence and cross-mode validation

Address PR #69 review: note that failure_rate_threshold is the sole mode
switch (both-set → rate wins, not an error), and that window_seconds /
minimum_calls are validated in both modes even when inert in classic.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

0.12.0

Toggle 0.12.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat(client): per-verb *_with_response siblings (0.12.0) (#68)

* refactor(client): extract _prepare_request from _request_with_body

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(client): add async per-verb *_with_response siblings

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(client): add sync per-verb *_with_response siblings

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(client): document per-verb *_with_response siblings

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(release): 0.12.0 — per-verb *_with_response siblings

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(planning): add the per-verb-with-response change bundle

Design + plan for the get_with_response … request_with_response siblings,
and the Active Index entry. Bundle stays active/draft until merge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(release): cite PR #68 in 0.12.0 shipped-via

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(planning): archive the per-verb-with-response bundle (#68)

Ship bookkeeping: mark design.md + plan.md shipped (pr: 68, outcome filled),
move the bundle from changes/active/ to changes/archive/, and flip its Index
line from Active to Archived.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

0.11.0

Toggle 0.11.0's commit message

Verified

This commit was signed with the committer’s verified signature.
lesnik512 Artur Shiriev
chore(release): 0.11.0 — deep-audit hardening

Add 0.11.0 release notes (security redaction, bounded error bodies +
ResponseTooLargeError, correctness fixes, middleware __all__, test/doc
quality — the full 2026-06-14 deep-audit remediation, #62#66).

Reset the static pyproject version to the placeholder "0": releases are
tag-driven (publish.yml runs `uv version $GITHUB_REF_NAME` from the tag),
so the field was stale at 0.3.0 against the 0.10.1 release history.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

0.10.1

Toggle 0.10.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Merge pull request #52 from modern-python/fix/0.10.1-delta-audit

0.10.1 — delta-audit closure (fixes + hardening)

0.10.0

Toggle 0.10.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Merge pull request #51 from modern-python/feat/circuit-breaker-timeout

Add CircuitBreaker + AsyncTimeout (0.10.0)

0.9.1

Toggle 0.9.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Merge pull request #49 from modern-python/docs/can-decode-no-raise-ob…

…ligation

docs(decoders): document the can_decode no-raise obligation

0.9.0

Toggle 0.9.0's commit message

Verified

This commit was signed with the committer’s verified signature.
lesnik512 Artur Shiriev
docs(release): 0.9.0 release notes

0.8.6

Toggle 0.8.6's commit message
0.8.6 — test mop-up