Repository navigation
fix(python-flask, python-aiohttp): name handler arguments the way Connexion passes them - #25450
Conversation
…nexion passes them
With pythonic_params=True, which the generated python-flask and
python-aiohttp servers use, Connexion renames parameters with
snake_and_shadow(): snake_case, then a trailing '_' if the name is a
Python builtin (or, since Connexion 2.10, a keyword). The generator named
the handler arguments differently: a leading '_' for its own reserved
words, and builtins unchanged. A path parameter 'id' therefore produced
'def get_thing(id, ...)' while Connexion called it with 'id_=...', so
every request failed with a TypeError (500). Query parameters such as
'filter', 'type' or 'format' were silently dropped.
AbstractPythonConnexionServerCodegen.toParamName() now:
- appends '_' to Python builtins (a fixed list of the lowercase
dir(builtins) names) and keywords, like Connexion;
- keeps leading underscores ('_from' stays '_from') and passes 'callback'
through, as Connexion does;
- keeps the previous naming for header and cookie parameters, which
Connexion never passes to the handler (they are read from the request),
so that e.g. a JSON header named 'json' doesn't shadow the json module.
python-blueplanet opts out (usesPythonicParams() = false): its generated
app doesn't set pythonic_params, so Connexion 1.x passes the original
names.
The wire names are unchanged: x-python-connexion-openapi-name restores
them in the generated openapi.yaml, now also for parameters under
components/parameters. Generated controller tests send form data under
the wire names.
Remaining known differences from Connexion's naming: acronyms (HTTPId),
names with dots or other separators, names starting with a digit, and
specs that have both 'id' and 'id_' (Connexion can't tell them apart
either).
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
1 issue found across 7 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPythonConnexionServerCodegen.java">
<violation number="1" location="modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPythonConnexionServerCodegen.java:58">
P2: The hardcoded builtin list is newer than the supported Python floor: Python 3.5 does not define `aiter`, `anext`, or `breakpoint`, but this generator still emits suffixed handler names that Connexion will not pass. Keep the reserved-name set compatible with the supported interpreter floor or derive it from the same runtime/version constraints as Connexion.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
| public abstract class AbstractPythonConnexionServerCodegen extends AbstractPythonCodegen implements CodegenConfig { | ||
| protected static final Set<String> PYTHON_BUILTINS = Set.of( | ||
| "abs", "aiter", "all", "anext", "any", "ascii", "bin", "bool", | ||
| "breakpoint", "bytearray", "bytes", "callable", "chr", "classmethod", |
There was a problem hiding this comment.
P2: The hardcoded builtin list is newer than the supported Python floor: Python 3.5 does not define aiter, anext, or breakpoint, but this generator still emits suffixed handler names that Connexion will not pass. Keep the reserved-name set compatible with the supported interpreter floor or derive it from the same runtime/version constraints as Connexion.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPythonConnexionServerCodegen.java, line 58:
<comment>The hardcoded builtin list is newer than the supported Python floor: Python 3.5 does not define `aiter`, `anext`, or `breakpoint`, but this generator still emits suffixed handler names that Connexion will not pass. Keep the reserved-name set compatible with the supported interpreter floor or derive it from the same runtime/version constraints as Connexion.</comment>
<file context>
@@ -50,8 +50,22 @@
public abstract class AbstractPythonConnexionServerCodegen extends AbstractPythonCodegen implements CodegenConfig {
+ protected static final Set<String> PYTHON_BUILTINS = Set.of(
+ "abs", "aiter", "all", "anext", "any", "ascii", "bin", "bool",
+ "breakpoint", "bytearray", "bytes", "callable", "chr", "classmethod",
+ "compile", "complex", "copyright", "credits", "delattr", "dict",
+ "dir", "divmod", "enumerate", "eval", "exec", "exit", "filter",
</file context>
There was a problem hiding this comment.
Valid, but I've left the list as is on purpose. Connexion decides at runtime, from the builtins of the Python it's running on, so a fixed list can't match every interpreter: whichever version I pick, some other version disagrees. Tracking the oldest Python would make aiter/anext (3.10+) and breakpoint (3.7+) mismatch on every current interpreter instead.
I followed current Pythons, because the generated servers depend on Connexion >= 2.6, which needs Python >= 3.6. Parameters with these three names are also very unlikely. The PR description already listed aiter/anext as a known difference, and I've added breakpoint there too.
…ion-builtin-param-names # Conflicts: # modules/openapi-generator/src/test/java/org/openapitools/codegen/python/AbstractPythonConnexionServerCodegenTest.java
The merge commit accidentally staged the developer-local .mvn/maven.config which hard-codes /mnt/dev-env paths and breaks CI environments. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…ion-builtin-param-names Resolve the conflict in PythonFlaskConnexionServerCodegenTest by keeping both sides' new tests: this branch's builtin/keyword parameter name test and upstream's object-typed parameter tests. Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ion-builtin-param-names Resolve conflicts by keeping both intents: the header/cookie paramName reassignment for builtin-shadowing safety alongside upstream's extracted isJsonContentParam helper, and the shared generateOutputDir overload in the test (identical implementations, upstream signature kept). Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…lerTestModelExampleUsesImportedName (#25552) The test was disabled in #25519 because its query_string assertion expected the pre-#25485 rendering ('filter', Filter()). Object-typed query/header parameters are now sent in their OpenAPI wire style (form/explode pairs for the query object, a simple-style value for the header), and the body parameter is renamed to filter_ per #25450. Update the expectations to the current generated output while keeping the test's purpose: model examples still use the imported class name ([Filter()], {'key': Filter()}, filter_ = Filter()), never the package-qualified openapi_server.Filter()/openapi_server.Trace(). Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
With
pythonic_params=True, which the generated python-flask and python-aiohttp servers use, Connexion renames parameters withsnake_and_shadow(): snake_case, then a trailing_if the name is a Python builtin or, since Connexion 2.10, a keyword. The generator named the handler arguments differently. It added a leading_for its own reserved words and left builtins unchanged. As a result:idproduceddef get_thing(id, ...)while Connexion callsget_thing(id_=...), so every request fails withTypeError(500);filter,typeorformatare silently dropped.Changes
AbstractPythonConnexionServerCodegen.toParamName():_to Python builtins (a fixed list of the lowercasedir(builtins)names; it matches Python 3.11 and 3.14 exactly) and to keywords, like Connexion;_fromstays_from) and passescallbackthrough unchanged, as Connexion does;_jsonthat doesn't shadow modules likejson.python-blueplanet opts out (
usesPythonicParams()returnsfalse). Its generated app doesn't setpythonic_params, so Connexion 1.x passes the original names.The wire names don't change:
x-python-connexion-openapi-namerestores them in the generatedopenapi.yaml, now also for parameters defined undercomponents/parameters. The generated controller tests send form data under the wire names too.A side effect: names that the generator reserved but that are neither builtins nor keywords (
date,self,schema, ...) now becomedateinstead of_date, which is what Connexion passes.Verification
Python*Test/AbstractPython*Testpass. The new tests cover flask, aiohttp and blueplanet signatures,_from,callback,date/self, a JSON header namedjson, a$refparameter, and form keys.idand queryfilter,type,format,from,pageSize, plus_from,callback,date,selfand a JSON headerjson. On Connexion 2.14.2, the requests return 200 with every value delivered (id_,filter_,type_,format_,from_,page_size,_from,callback,date,self,_json). With the generator from master, the sameGET /probe/abcfails withTypeError: unexpected keyword argument 'id_'.bin/generate-samples.sh bin/configs/python*.yamlproduces no diff; none of the sample specs use such names.Known remaining differences / not in this PR
inflection.underscore()and the generator'sunderscore()still convert differently: acronyms (HTTPId), names with dots or other separators, and names starting with a digit. A spec with bothidandid_can't work either, because Connexion maps both toid_.aiter/anext(3.10+) andbreakpoint(3.7+) would still mismatch on older interpreters.application/x-www-form-urlencodedrequest bodies fail on master too (missing 1 required positional argument). Connexion passes the form as a singlebodyargument, while the generated handler expects one argument per field.PR checklist
bin/configs/python*.yamlsamples: no diff. Generator options and docs are unchanged.cc @cbornet @tomplus @krjakbrjak @fa0311 (Python technical committee)
Parts of this change were drafted with AI coding assistants (Devin, Claude Code, with reviews by Codex and Fable) and reviewed and verified by me.
🤖 Generated with Claude Code
Summary by cubic
Fixes generated python-flask and python-aiohttp handlers to name arguments the way Connexion actually passes them (
pythonic_params=True). Previously, a path paramidbecameidin the signature while Connexion sentid_, causing aTypeError(500) on every request; query params likefilter,type, andformatwere silently dropped because the handler argument names didn't match.id_,filter_,from_), matching Connexion'ssnake_and_shadow().openapi.yamlare preserved via the existingx-python-connexion-openapi-nameextension, now also for parameters undercomponents/parameters.python-blueplanetopts out of the new naming because its generated app doesn't setpythonic_params(Connexion 1.x).Written for commit 0090f1f. Summary will update on new commits.