Skip to content

Fix tagged unions dropping tags that are also member fields - #831

Closed
Aschenbath wants to merge 1 commit into
python-attrs:mainfrom
Aschenbath:fix-483-tagged-union-tag-field
Closed

Aschenbath wants to merge 1 commit into
python-attrs:mainfrom
Aschenbath:fix-483-tagged-union-tag-field

Conversation

@Aschenbath

Copy link
Copy Markdown

With forbid_extra_keys=True, configure_tagged_union popped the tag out of the payload before dispatching to the member's structure hook. That pop is needed so members that don't declare the tag don't trip the extra-keys check — but when a member class does declare a field with the tag's name, the pop removed data its hook requires:

@define
class SpecialDevice:
    hostname: str
    port: int
    type: str

@define
class StandardDevice:
    hostname: str
    type: str

c = Converter(forbid_extra_keys=True)
configure_tagged_union(SpecialDevice | StandardDevice, c, tag_name="type", ...)
c.structure({"type": "special", "hostname": "h", "port": 1234}, ...)
# ClassValidationError caused by KeyError: 'type'

This moves the pop from the dispatchers into the per-member wrapper: the dispatchers now pass the payload through, and each member hook receives a tag-stripped copy only if that member does not consume the tag as one of its own fields (checked against its init fields, accounting for cattrs' leading-underscore key renaming). The default= fallback for unknown tags keeps the previous behavior (tag stripped before the default handler runs). Non-forbid_extra_keys converters are untouched.

Tests: new cases in tests/strategies/test_tagged_unions.py cover the reported scenario with and without default= (structure succeeds, the member's type field is populated from the tag, unstructure round-trips) and confirm members that don't declare the tag still structure fine under forbid_extra_keys=True. The strategies suite plus tests/test_unions.py pass: 285 passed, 15 xfailed. A changelog entry is added under NEXT in HISTORY.md.

Fixes #483

@Aschenbath

Copy link
Copy Markdown
Author

Closing this one myself: I opened too many PRs here in a short time, which isn't fair to your review queue — sorry about that. I'm leaving #827 and #822 open. If this fix is something you'd want, I'm happy to reopen or rebase it later.

@Aschenbath Aschenbath closed this Nov 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

KeyError when using configure_tagged_union with existing field

1 participant