Skip to content

Latest commit

 

History

History
22 lines (16 loc) · 2.53 KB

File metadata and controls

22 lines (16 loc) · 2.53 KB

Changelog

All notable changes to httpware will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

Added

  • Initial project scaffold: src/httpware/ package, py.typed marker, pyproject.toml with uv_build backend.
  • Org conventions ported from modern-python/modern-di: Justfile, .github/workflows/ci.yml, [tool.ruff] config, [tool.pytest.ini_options], dev and lint dep groups.
  • Declared dependencies: httpx2>=2.0.0,<3.0, pydantic>=2.0,<3.0.
  • Declared install extras: [msgspec], [otel], [niquests], [all].
  • SECURITY.md with 90-day private-disclosure window.
  • CONTRIBUTING.md with development workflow.
  • CLAUDE.md with AI-agent guidance.
  • Core data types: Request, Response, Limits, Timeout, ClientConfig — frozen+slotted dataclasses with with_* immutability helpers on Request and computed text/json() accessors on Response (Story 1.2).
  • Status-keyed exception hierarchy with plain typed fields: ClientError, TransportError, TimeoutError, StatusError, ClientStatusError/ServerStatusError bases, 9 leaf classes (BadRequestErrorServiceUnavailableError), STATUS_TO_EXCEPTION lookup dict (Story 1.3). StatusError is picklable and deep-copyable via custom __reduce__; __repr__ and the summary message strip user:pass@ userinfo from the request URL; headers is stored as a read-only MappingProxyType so caller mutations after raise do not bleed into the exception. TimeoutError multi-inherits from builtins.TimeoutError (revisits architecture Decision 3) so except builtins.TimeoutError (the form asyncio.wait_for raises) also catches httpware-raised timeouts.
  • Transport protocol (@runtime_checkable) and default Httpx2Transport adapter; StreamResponse placeholder for Story 4.1 protocol typing; the wire method is uppercased at the seam and httpx2 exceptions (TimeoutException, HTTPError, InvalidURL, CookieConflict, and the closed-client RuntimeError) are mapped to httpware.TimeoutError / httpware.TransportError (with the original exception's message preserved on the mapped instance) so no httpx2 exception escapes the library; lazy httpx2.AsyncClient construction is guarded by an asyncio.Lock so concurrent first-calls share one client; httpx2 is confined to src/httpware/transports/httpx2.py (Story 1.4).