Repository navigation
fix(python): resolve enum discriminator tags in dict union input - #204
Conversation
There was a problem hiding this comment.
No issues found across 7 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Shadow auto-approve: would auto-approve. Fixes Python union discriminator handling so enum members in dict inputs use their .value, correcting Python 3.11+ behavior, with secondary tests for top-level and nested cases. Focused bug fix that preserves non-enum behavior and is pinned by tests.
View guided diff | Turn on auto-fix | Re-trigger cubic
get_discriminator formatted dict tag values with an f-string. Since Python 3.11, formatting a mixed-in (str, Enum) member yields "ClassName.MEMBER" instead of its value, so closed discriminated unions rejected dict input carrying an enum member as the tag with union_tag_invalid. Unwrap enum values in the dict branch, as the attribute branches already did, through a shared helper.
e7dccb5 to
1bb17ce
Compare
There was a problem hiding this comment.
All reported issues were addressed across 10 reviewed files. 1 file intentionally excluded from review.
Shadow auto-approve: would not auto-approve because issues were found.
View guided diff | Turn on auto-fix | Re-trigger cubic
Generator Snapshot TestingSnapshot tests are running. Snapshot results: https://github.com/speakeasy-api/openapi-generation-snapshots/issues/161#issuecomment-6751158594 |
The enum discriminator tag tests cover a pythonv2 regression, not a cross-target feature, so they no longer register test IDs or add skip entries to other targets.
There was a problem hiding this comment.
0 issues found across 12 files (changes from recent commits).
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Shadow auto-approve: would auto-approve. Fixes Python union discriminator handling so enum members in dict inputs use their .value instead of Python 3.11+ Enum repr formatting, with new secondary tests covering top-level and nested cases. The behavior change is narrowly scoped, preserves non-enum behavior, and is pinned by tests.
View guided diff | Turn on auto-fix | Re-trigger cubic
Why
With
enumFormat: enum, a closed discriminated union fails validation on Python 3.11+ when it receives a dict whose discriminator holds an enum member instead of a raw string. On 3.10 the same input works:Generated usage snippets build request dicts this way when
enumFormat: enum, so copying them reproduces the error.get_discriminator(utils/annotations.py) builds the discriminator from a dict withf"{field[key]}". Python 3.11 changedEnum.__format__so that a mixed-in(str, Enum)or(int, Enum)member formats asClassName.MEMBER. Before 3.11 it formatted as its value. The attribute branches of the same function already unwrapped.value; only the dict branch was affected.What changed
get_discriminatorconverts discriminator values through a nestedto_discriminatorhelper, which uses.valuefor enum members. The dict branch and both attribute branches use it, and the two duplicated attribute-branch blocks are gone. Behavior is unchanged on Python 3.10, where mixed-in enums already formatted as their value.parse_open_unionlooks the value up in a dict keyed by string, and a(str, Enum)member hashes and compares equal to its value.secondarytest fragmentoneof-enum-tag-nested.yamladdsoneOfEnumTagNestedPost. Its request body uses a oneOf, told apart by a single-value enumtypeproperty, once as an object property and once as array items. The oneOf is only used in a request, so it stays closed and goes throughget_discriminator.enumFormat: enum) send enum-member discriminators in dicts at the top level (existingnullableOneOfSchemaPost) and nested (new operation).utils/annotations.pyand itsgen.lockchecksum change.Testing
annotations.pyand pass on 3.10. With the fix they pass on 3.10, 3.11, 3.12 and 3.13.TARGET=secondary make test-pythonv2: 384 passed, 1 skipped (local Python 3.10). CI covers 3.10–3.14.TARGET=review make test-pythonv2: passed.TARGET=primary make test-pythonv2: passed (run before the helper was renamed; no behavior change since).TARGET=secondary make build-<target>for go, typescriptv2, csharp, javav2, php, ruby, cli and mcp-typescript: passed, since the new fragment applies to every target's secondary variant. Their test suites, and terraform, postman and unity, were not run locally.make lint: passed.Public-safety check
.claude/skills/public-repo-communication/SKILL.md).git diff --check.