Skip to content

fix(web): type-checker-transparent request-binding markers (v26.06.07)#33

Merged
ancongui merged 1 commit into
mainfrom
fix/web-param-markers-mypy-transparent
Jun 5, 2026
Merged

fix(web): type-checker-transparent request-binding markers (v26.06.07)#33
ancongui merged 1 commit into
mainfrom
fix/web-param-markers-mypy-transparent

Conversation

@ancongui
Copy link
Copy Markdown
Contributor

@ancongui ancongui commented Jun 5, 2026

Summary

The web request-binding markers in pyfly.web.params (PathVar, QueryParam, Body, Header, Cookie, File, Valid) were plain Generic[T] classes. mypy --strict therefore saw a handler parameter order_id: PathVar[str] as a PathVar[str] object rather than str, so user controllers written exactly as the docs/skills show could not pass strict type-checking without # type: ignore / cast. (The framework's own idp/web.py and transactional/rest/controllers.py had accumulated those workarounds; the order_service sample exhibits the errors but isn't type-checked.)

Fix

Redefine the markers as Annotated[T, <sentinel>] aliases:

  • A type checker sees PathVar[str] as str and Valid[Body[Order]] as Order — handler bodies pass mypy --strict with no escape hatches.
  • At runtime the binder recovers the source from the annotation metadata via the new pyfly.web.params.inspect_binding(hint) -> (binding, inner_type, validate), used by both the Starlette ParameterResolver (shared with the FastAPI adapter) and the OpenAPI metadata extractor.
  • Runtime binding semantics are unchanged: path/query/body/header/cookie/file resolution, Valid[...] validation with structured 422s, the flattened Valid[Body[T]] form, and the Valid[Model] → validated-body shorthand all behave identically.

Removed the now-redundant cast(...)/# type: ignore workarounds in idp/web.py and transactional/rest/controllers.py — these now serve as in-tree regression guards (reverting the markers would re-break mypy src/pyfly).

Tests

  • Rewrote tests/web/test_params.py to lock in the new contract via inspect_binding (all binding kinds + Valid wrapping/standalone + nested flattening + the mypy-transparent underlying type).
  • Updated tests/web/test_file_upload_types.py to the new representation.
  • Existing resolver/valid/controller/full-stack HTTP tests (binding_type is PathVar, TestClient round-trips) unchanged and passing.

Gates

mypy --strict (607 files) ✓ · ruff ✓ · full suite 3623 passed, 1 skipped.

Bumps v26.06.06 → v26.06.07 (pyproject / __init__ / README), CHANGELOG entry, uv.lock synced.

…p v26.06.07

PathVar/QueryParam/Body/Header/Cookie/File/Valid were Generic[T] classes, so
mypy --strict saw `order_id: PathVar[str]` as a PathVar[str] object, not str —
user controllers written as documented could not pass strict typing without
cast/# type: ignore. They are now Annotated[T, sentinel] aliases (mypy sees
PathVar[str] as str, Valid[Body[Order]] as Order); the binder recovers the
source from annotation metadata via the new pyfly.web.params.inspect_binding.

Runtime binding semantics unchanged. Removed the now-redundant cast()/ignore
workarounds in idp/web.py and transactional/rest/controllers.py. Updated
tests/web/test_params.py + test_file_upload_types.py to the new contract.

Gates: mypy --strict (607 files) clean, ruff clean, full suite 3623 passed.
@ancongui ancongui merged commit 33bdcea into main Jun 5, 2026
5 checks passed
@ancongui ancongui deleted the fix/web-param-markers-mypy-transparent branch June 5, 2026 13:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant