fix(small-fixes): close 4 audit findings (0.8.5)#36
Merged
Conversation
Bundles chain.py TYPE_CHECKING fix, pydantic.py TypeAdapter NameError window fix, LoggingMiddleware docs print() replacement, and symmetric test_expected_exports assertion. All small, all unrelated, batched to avoid release churn. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Each fix is TDD where applicable. T1 (chain.py) has two failing tests pinning typing.get_type_hints resolution. T2 (pydantic.py) is a contract narrowing verified by existing tests. T3 (LoggingMiddleware docs) is docs-only. T4 (public-api test) is a test-quality change. T5 = release notes + PR opening. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…KING compose_async and compose used string annotations referencing AsyncMiddleware / Middleware imported only under `if typing.TYPE_CHECKING:`. Calling typing.get_type_hints(compose_async) at runtime raised `NameError: name 'AsyncMiddleware' is not defined`. The TYPE_CHECKING guard also violates the project's typing-import-style memory rule. Drop the guard, import the protocols unconditionally at module top, and unquote the string annotations. httpware.middleware.__init__ does not import chain.py back, so no circular import. Tests pin typing.get_type_hints(compose_async) and typing.get_type_hints( compose) resolve without NameError. Closes audit Low finding (chain.py:9-10) from planning/audit/2026-06-07-deep-audit.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… window _get_adapter and the TypeError fallback inside PydanticDecoder.decode both referenced TypeAdapter as a bare name. The name was bound only under `if import_checker.is_pydantic_installed:`. If a test reloaded the module with the flag patched to False, TypeAdapter was undefined and subsequent calls raised NameError instead of the documented ImportError. Hoist `from pydantic import TypeAdapter` unconditionally. The module is gated upstream by client.py:_default_pydantic_decoder(), which raises ImportError before this module is loaded when pydantic is absent — there is no real-world path that loads pydantic.py without pydantic available. Update the module docstring to reflect the new contract. Closes audit Low finding (pydantic.py:15-16, 27, 43) from planning/audit/2026-06-07-deep-audit.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The example previously used `print(...)` to demonstrate a middleware that
records inbound/outbound traffic. CLAUDE.md lists "No print()" as a
non-negotiable architecture invariant, so the doc example would fail CI
in a user's own project if they followed the project's conventions.
Rewrite with a module-level `_LOGGER = logging.getLogger("myapp.logging_middleware")`
and `_LOGGER.info(...)` calls, matching the existing RequestIdMiddleware
example's style further down the same file.
Closes audit Nit finding (docs/middleware.md:156-161) from
planning/audit/2026-06-07-deep-audit.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
test_expected_exports used `missing = expected - set(__all__)` so it caught symbols missing from __all__ but not the reverse — symbols added to __all__ that aren't in the expected set slipped through (the companion test_all_exports_resolve catches symbols in __all__ that don't exist at all; the gap was real symbols accidentally added to __all__). Switch to `assert expected == set(__all__)` with a multi-line message that names both directions, so future test failures pinpoint which side drifted. Closes audit Nit finding (test_public_api.py:69-71) from planning/audit/2026-06-07-deep-audit.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Four small unrelated fixes in one patch. chain.py get_type_hints resolves; pydantic.py NameError window eliminated; LoggingMiddleware docs example uses logging; public-API test catches bogus __all__ entries. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes 4 of the remaining audit findings — two Lows in production code, two Nits in docs/tests. See
planning/specs/2026-06-08-small-fixes-mop-up-design.mdfor the design andplanning/releases/0.8.5.mdfor the user-facing release notes.What changes
chain.pyTYPE_CHECKING block dropped.typing.get_type_hints(compose_async)andtyping.get_type_hints(compose)now resolve cleanly.pydantic.pyTypeAdapter import is unconditional. Eliminates the NameError window on module-reload with the install flag patched off.LoggingMiddlewaredocs example useslogginginstead ofprint(). Matches CLAUDE.md's "no print()" invariant.__all__. Catches bogus entries the old subtraction missed.Audit findings closed
middleware/chain.py:9-10decoders/pydantic.py:15-16, 27, 43docs/middleware.md:156-161tests/test_public_api.py:69-71expected == set(__all__)Test plan
typing.get_type_hintsresolution for bothcompose_asyncandcompose.import httpwaredoes not load pydantic.Release
Tag
0.8.5from the merge SHA after this PR lands.🤖 Generated with Claude Code