fix(python-fastapi): rebase #24098 onto master (relax path/query/header strict typing, #21905) - #24793
Conversation
…OpenAPITools#21905) Pydantic strict types (StrictInt/StrictStr/StrictFloat) and Field(strict=True) disable automatic string coercion. Since path/query/header values always arrive on the wire as strings, FastAPI rejected otherwise-valid requests with a 422 (int_type: Input should be a valid integer). Add a relaxStrict flag to PydanticType that emits coercible types (int/str/float) and omits strict=True, gated behind a shouldRelaxStrictParameterTyping() hook that defaults to false. PythonFastAPIServerCodegen overrides it for path/query/header params. Body params and the Python client generator are unchanged (strict typing is correct for JSON bodies). Regenerated the python-fastapi petstore sample. Claude-Session: https://claude.ai/code/session_019g7iwAyg7ErX1WrhqHyTn6
Replace the relaxStrict boolean + shouldRelaxStrictParameterTyping hook with
an explicit PydanticCoercibleType subclass of PydanticType that never emits
Pydantic strict types for the scalar kinds where strictness blocks coercion.
Selection moves into a getPydanticParameterType() factory: PythonFastAPIServer
returns PydanticCoercibleType for path/query/header params and the strict base
type for everything else. The rule ("wire-string params are never strict") is
now a code structure rather than a flag callers must remember to set, and the
explanatory comment lives in one place on the class it describes.
Behaviour-preserving: the regenerated python-fastapi sample is byte-identical
to the previous commit. Python codegen tests (fastapi, client) pass.
Claude-Session: https://claude.ai/code/session_019g7iwAyg7ErX1WrhqHyTn6
… for FastAPI path/query/header params) Resolve conflicts in AbstractPythonCodegen.java: upstream moved constraint handling into a static ConstraintApplier / ConstraintType, replacing the per-type constants and the instance applyConstraints method. Reapply the PR's PydanticCoercibleType subclass on top of that refactor so path/query/ header parameters emit coercible (non-strict) Pydantic types, using the new ConstraintApplier API.
…OpenAPITools#21905) Pydantic strict types (StrictInt/StrictStr/StrictFloat) and Field(strict=True) disable automatic string coercion. Since path/query/header values always arrive on the wire as strings, FastAPI rejected otherwise-valid requests with a 422 (int_type: Input should be a valid integer). Add a relaxStrict flag to PydanticType that emits coercible types (int/str/float) and omits strict=True, gated behind a shouldRelaxStrictParameterTyping() hook that defaults to false. PythonFastAPIServerCodegen overrides it for path/query/header params. Body params and the Python client generator are unchanged (strict typing is correct for JSON bodies). Regenerated the python-fastapi petstore sample. Claude-Session: https://claude.ai/code/session_019g7iwAyg7ErX1WrhqHyTn6 Conflicts: modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPythonCodegen.java samples/server/petstore/python-fastapi/src/openapi_server/apis/fake_api.py samples/server/petstore/python-fastapi/src/openapi_server/apis/pet_api.py samples/server/petstore/python-fastapi/src/openapi_server/apis/store_api.py samples/server/petstore/python-fastapi/src/openapi_server/apis/user_api.py
Replace the relaxStrict boolean + shouldRelaxStrictParameterTyping hook with
an explicit PydanticCoercibleType subclass of PydanticType that never emits
Pydantic strict types for the scalar kinds where strictness blocks coercion.
Selection moves into a getPydanticParameterType() factory: PythonFastAPIServer
returns PydanticCoercibleType for path/query/header params and the strict base
type for everything else. The rule ("wire-string params are never strict") is
now a code structure rather than a flag callers must remember to set, and the
explanatory comment lives in one place on the class it describes.
Behaviour-preserving: the regenerated python-fastapi sample is byte-identical
to the previous commit. Python codegen tests (fastapi, client) pass.
Claude-Session: https://claude.ai/code/session_019g7iwAyg7ErX1WrhqHyTn6
Conflicts:
modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPythonCodegen.java
…s://github.com/goopher/openapi-generator into goopher/fix_python-fastapi-query-param-strict-coercion
There was a problem hiding this comment.
All reported issues were addressed across 10 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
|
thanks for filing a new PR based on the latest master cc @cbornet (2017/09) @tomplus (2018/10) @krjakbrjak (2023/02) @fa0311 (2023/10) |
…ITools#21905) Cookie values arrive as strings in the Cookie header, just like path/query/header params, so strict types (StrictInt/StrictBool/ StrictStr, strict=True) disabled Pydantic's string coercion and made FastAPI reject valid requests with a 422. Route cookie params through PydanticCoercibleType as well, and add a regression test covering path/query/header/cookie params while verifying JSON body model properties keep strict typing.
The trailing newline added to endpoint_argument_definition.mustache in OpenAPITools#23398 leaks into the rendered output: api.mustache includes the partial inline, immediately followed by a comma, so the newline wraps the comma onto a line of its own: pet: Annotated[Pet, Field(description="...")] = Body(..., description="...") , Remove the trailing newline so parameters render as `...),` again. Add a regression test asserting the comma stays at end of line (raw content checks, since assertFileContains linearizes away newlines), and regenerate the python-fastapi petstore sample.
|
Added ae92480 — a small formatting fix spotted while regenerating samples: fix(python-fastapi): keep endpoint argument comma on the parameter line #23398 added a trailing newline to |
|
is it correct to say that you've been using this fix in the production environment and it works as expected? |
This PR rebases @goopher's #24098 onto current
master. It does not change the original fix; it only resolves merge conflicts and keeps the behavior working against upstream refactors that landed after #24098.Original problem (#21905): Pydantic strict types (
StrictInt/StrictStr/StrictFloat) andField(strict=True)disable string coercion. Path/query/header values always arrive as strings, so FastAPI rejected valid requests with 422 (int_type: Input should be a valid integer).Original approach (from #24098):
int/str/float) and omitstrict=True.PydanticCoercibleType), selected bygetPydanticParameterType(), not a boolean flag.What this rebase had to reconcile with
master:ConstraintApplier(do not restore inlined min/max/length constraints).PydanticCoercibleTypeand FastAPIgetPydanticParameterType()for path/query/header.python-fastapipetstore samples with HEAD's current signature shape (Query(...)/alias=/ trailing commas) and the relaxed types.Fixes #21905
Supersedes / continues #24098 (credit: @goopher)
PR checklist
Commit all changed files.
This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
These must match the expectations made by your contribution.
You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example
./bin/generate-samples.sh bin/configs/java*.IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
Summary by cubic
Fixes #21905 by relaxing strict Pydantic typing for
python-fastapipath/query/header/cookie params, which previously rejected valid requests with 422 because wire-string values couldn't be coerced toStrictInt/StrictStr/StrictFloat.Bug Fixes
int/str/floattypes withoutstrict=Truevia a newPydanticCoercibleType; body params and the Python client keep strict types.endpoint_argument_definition.mustachepartial was making them wrap onto their own line.ConstraintApplierfrom [python] centralize the Python constraint rules #24141, with regenerated petstore samples and regression tests.Written for commit ae92480. Summary will update on new commits.