fix(python-flask, python-aiohttp): name handler arguments the way Connexion passes them

KH
1d ago
+281-5

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. It added a leading _ for its own reserved words and left builtins unchanged. As a result:

  • a path parameter id produced def get_thing(id, ...) while Connexion calls get_thing(id_=...), so every request fails with TypeError (500);
  • query parameters such as filter, type or format are silently dropped.

Changes

AbstractPythonConnexionServerCodegen.toParamName():

  • appends _ to Python builtins (a fixed list of the lowercase dir(builtins) names; it matches Python 3.11 and 3.14 exactly) and to keywords, like Connexion;
  • keeps leading underscores (_from stays _from) and passes callback through unchanged, as Connexion does;
  • keeps the previous naming for header and cookie parameters. Connexion never passes these to the handler (they are read from the request), so they keep a name such as _json that doesn't shadow modules like json.

python-blueplanet opts out (usesPythonicParams() returns false). Its generated app doesn't set pythonic_params, so Connexion 1.x passes the original names.

The wire names don't change: x-python-connexion-openapi-name restores them in the generated openapi.yaml, now also for parameters defined under components/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 become date instead of _date, which is what Connexion passes.

Verification

  • Python*Test / AbstractPython*Test pass. The new tests cover flask, aiohttp and blueplanet signatures, _from, callback, date/self, a JSON header named json, a $ref parameter, and form keys.
  • Generated python-flask and python-aiohttp servers from a spec with path id and query filter, type, format, from, pageSize, plus _from, callback, date, self and a JSON header json. 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 same GET /probe/abc fails with TypeError: unexpected keyword argument 'id_'.
  • bin/generate-samples.sh bin/configs/python*.yaml produces no diff; none of the sample specs use such names.

Known remaining differences / not in this PR

  • Names that Connexion's inflection.underscore() and the generator's underscore() still convert differently: acronyms (HTTPId), names with dots or other separators, and names starting with a digit. A spec with both id and id_ can't work either, because Connexion maps both to id_.
  • The builtins list follows current Pythons: aiter/anext (3.10+) and breakpoint (3.7+) would still mismatch on older interpreters.
  • Pre-existing and unchanged: application/x-www-form-urlencoded request bodies fail on master too (missing 1 required positional argument). Connexion passes the form as a single body argument, while the generated handler expects one argument per field.

PR checklist

  • Read the contribution guidelines.
  • Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
    Regenerated all bin/configs/python*.yaml samples: no diff. Generator options and docs are unchanged.
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

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 param id became id in the signature while Connexion sent id_, causing a TypeError (500) on every request; query params like filter, type, and format were silently dropped because the handler argument names didn't match.

  • Builtins and keywords now get a trailing underscore (id_, filter_, from_), matching Connexion's snake_and_shadow().
  • Header and cookie params keep the previous naming, since Connexion reads them from the request and never passes them to the handler.
  • Wire names in the generated openapi.yaml are preserved via the existing x-python-connexion-openapi-name extension, now also for parameters under components/parameters.
  • python-blueplanet opts out of the new naming because its generated app doesn't set pythonic_params (Connexion 1.x).