Skip to content

Support nullable tagged unions - #812

Open
Aschenbath wants to merge 1 commit into
python-attrs:mainfrom
Aschenbath:fix/nullable-tagged-unions
Open

Aschenbath wants to merge 1 commit into
python-attrs:mainfrom
Aschenbath:fix/nullable-tagged-unions

Conversation

@Aschenbath

@Aschenbath Aschenbath commented Oct 25, 2026 •

Copy link
Copy Markdown

configure_tagged_union(A | B | None, converter) currently attempts to generate a tag and class hooks for NoneType, so configuration fails. Support explicitly configured nullable unions by excluding NoneType from the tag mapping and wrapping the existing hooks to pass None through unchanged. This also supports A | None and PEP 695 aliases.

Generate the default-member hook after registering the union hooks. Otherwise, a recursive default member can capture an untagged optional hook and reject a nested tag under forbid_extra_keys=True when the outer tag is missing or unknown. Custom tags, default members, strict validation, and input dictionaries retain their existing behavior for class values.

Addresses #345, following the explicit nullable-union wrapper approach suggested in the issue. Callers configure the complete nullable type, including None.

Validation:

  • 65 tagged-union tests pass, including nullable attrs/dataclass fields, custom tag maps, a single optional class, aliases, and recursive defaults.
  • The original implementation fails 22 new nullable cases; the recursive-default regression also catches four failures before delaying default-hook generation.
  • Full CPython 3.13 / Windows suite: 1,088 passed, 22 skipped, 15 xfailed.
  • Ruff lint/format, all 43 strategy documentation doctests, and Sphinx HTML with warnings treated as errors pass.

The full upstream CI workflow passes on this exact commit in the fork: all 10 jobs, covering CPython 3.10–3.15, PyPy 3.10, lint, package verification, and 100% combined coverage. The upstream Read the Docs build also passes.

Developed with AI assistance.

Pass None through without generating a class hook. Register the union before generating its default member hook so recursive defaults keep the tagged handlers.
@Aschenbath
Aschenbath marked this pull request as ready for review October 25, 2026 01:36

This branch has not been deployed

No deployments
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.

1 participant