[python] support legacy model dictionaries

Merged
TA
3mo ago
+5220-12

The removed python-legacy generator exposed to_dict() as a
public dictionary API: every declared field, normalized Python names
by default, and wire names with serialize=True. The current Python
generator instead uses to_dict() for its transport projection, so
replacing that behavior directly would also change JSON and request
payloads.

The design discussion accepted a default-off compatibility boundary and
requested the broader option name:
https://github.com/OpenAPITools/openapi-generator/issues/24125

Add compatibleWithPythonLegacy as that default-off switch. Ordinary
fields keep the normalized Python constructor names used by
python-legacy while still accepting wire names. Explicit
nameMappings keep their requested public names. to_dict() uses
public names by default and wire names with serialize=True, while
to_json() and ApiClient retain the current transport projection.

Preserve custom and inherited to_dict() methods, composed-model
wrappers, and model-only generation. Match python-legacy one-level
conversion of list elements and dictionary values rather than
recursively converting nested containers.

Render the compatibility helpers in each model because model-only
generation does not emit a shared support module. Add a dedicated
generated sample for generic, inherited, oneOf, anyOf, nullable,
defaulted, read-only, nested-container, and additional-property
behavior.

Closes #24125.


Summary by cubic

Adds an opt-in compatibleWithPythonLegacy option to restore the python-legacy public to_dict() behavior without changing JSON or request serialization. Updates models (including oneOf/anyOf/generics) and ApiClient to separate legacy dictionaries from transport projections, with docs, tests, and a CI-backed sample.

  • New Features

    • Adds compatibleWithPythonLegacy (default false) to restore legacy public dictionary semantics.
    • Field aliases use normalized Python constructor names; wire names are accepted; explicit nameMappings are respected.
    • to_dict() emits all declared fields (uses None for missing), public names by default and wire names with serialize=True; shallow container conversion; supports oneOf/anyOf/generics; preserves custom/inherited to_dict(); helpers rendered per model.
    • to_json() and ApiClient detect generated models and keep the modern transport projection; adds a dedicated sample with runtime tests and CI across Python 3.10–3.14; docs updated.
  • Migration

    • No behavior change by default.
    • To enable, set additionalProperties.compatibleWithPythonLegacy: "true" in your generator config (see bin/configs/python-legacy-model-dictionaries.yaml).