feat(python): add modelSerializationMethods option
2Y
4d ago+475+475+012345678901234567890123456789-40-40-01234567890123456789
Why
Python SDK models have no short way to turn a model into a dict or JSON string with the field names the API uses. Users have to call model_dump(by_alias=True, exclude_unset=True, ...) themselves.
What changed
Add python.modelSerializationMethods (default false). When enabled, every generated model gains:
to_dict(*, mode="python", use_api_names=True, exclude_unset=True, exclude_defaults=False, exclude_none=False, warnings=True)to_json(*, indent=2, use_api_names=True, exclude_unset=True, exclude_defaults=False, exclude_none=False, warnings=True)
Supporting changes:
- Model serializers emit Python field names when
use_api_names=False. With the option on,model_dump(by_alias=False)also emits Python field names; the defaultmodel_dump()keeps emitting API names. to_dictandto_jsonleave filtered fields out even withexclude_none=True. Other dumps keep theexclude_noneexception from #149, which request bodies rely on.- Const fields are marked as set in
model_post_init, soexclude_unsetkeeps them. Error-data models (<Name>Data) get the samemodel_post_init. - The unknown variant of an open union dumps as its raw payload in
to_dictandto_json, so the helpers return the data the server sent instead of the SDK's fallback object. Parsing that output gives the same unknown variant only when unknown union variants are allowed, as for responses; a plainmodel_validaterejects the unrecognized discriminator value.use_api_namesand theexclude_*options do not apply inside the raw payload, which has no schema.model_dumpand request bodies are unchanged. - A model field named
to_dictorto_jsongets a trailing underscore. SDK group accessors, global-parameter and server-variable constructor arguments, and flattened method parameters keep their names, because only models reserve these methods. Security constructor arguments follow the security model's field names, so they get the underscore too. - Method parameter documentation (SDK docs, Markdown parameter tables and docstrings) names parameters with the same sanitizer as the method signature. Previously a flattened
toJsonparameter was documented asto_json_while the method acceptsto_json. This also applies with the option disabled, for parameter names that are reserved differently for parameters and model fields: the review SDK's flattenedtypeparameter was documented astypewhile the method acceptstype_, and is now documented astype_. - Usage snippets name global parameters the same way the SDK constructor does. This also applies with the option disabled.
- With
preserveUnknownFieldsalso enabled, both helpers keep unknown fields, subject to the limitations listed in #146.
Test coverage
- The
unknown-fieldsfragment gains a group namedtoJsonwith atoJsonquery parameter, an object withtoDict/toJsonproperties, a const object with a defaulted field, and a required const in the error body. Its discriminatedChoiceunion becomes a component, used bychoiceand by a newchoicesarray. - tertiary (option enabled alone): helper defaults and options, field names, excluded fields, consts (including on error data), reserved names, the default
model_dump()of nested models and model lists, and unknown open-union variants at the top level, nested in a model and inside a list. - quaternary (enabled with
preserveUnknownFields, flattened parameters): helper round trips that keep unknown fields, unknown open-union variants nested in a model and inside a list alongside unknown fields, a flattenedto_jsonparameter whose signature, docstring and Markdown table agree, plus checks that unrecognized enums serialize without warnings. - secondary (option disabled): the helper names are not reserved.
Stack
- #145: unrecognized enum serialization
- #149: honour include/exclude filters in model dumps
- #146:
preserveUnknownFields - This PR:
modelSerializationMethods
Testing
TARGET=primary make test-pythonv2(option disabled): 724 passed.TARGET=secondary make test-pythonv2(option disabled): 333 passed, 1 skipped.TARGET=tertiary make test-pythonv2: 257 passed, 1 skipped. The nestedmodel_dump()test fails without the serializer fix, and the error-data const test fails withoutmodel_post_initon error data.TARGET=quaternary make test-pythonv2: 296 passed, 1 skipped.TARGET=review make test-pythonv2: 36 passed, 6 skipped.TARGET=primary make test-typescriptv2(fragment change): 802 passed.make check-template-pythonv2and prettier pass.TARGET=review make build-pythonv2: integrity validation passes; the review SDK gainsmodelSerializationMethods: falseingen.yaml, and the flattenedtypeparameter of two methods is now documented astype_in their docstrings and Markdown tables, matching the signature.git diff --checkpasses.
Public-safety check
- This change contains no credentials, customer documents, private repository URLs, private filesystem paths, or unredacted private logs.
- Title, body, comments, and commit messages name no customers or customer-derived identifiers, private paths or trackers, or workflow provenance, and are understandable without private context (
.claude/skills/public-repo-communication/SKILL.md). - Generated fixtures and review SDK changes are public-safe.
- I reviewed
git diff --check.