GeezerVison is showing github.com — Merge `typing.Union` and `types.UnionType` · Issue #105499 · python/cpython
Merge typing.Union and types.UnionType #105499DescriptionCurrently, unions created through typing.Union[A, B] and through the PEP-604 syntax A | B are at runtime instances of completely different types, and they differ in exactly what elements they accept. This is confusing and makes it harder for users to detect unions at runtime.
I propose to proceed in two steps:
- Make
typing.Union an alias for types.UnionType and make it so types.UnionType[A, B] works, accepting the same types Union accepts now.
- Loosen the rules for what the
| operator accepts to accept more types that are commonly used in unions.
Linked PRs
Reacted by Alex Waygood, James Hilton-Balfe, Danipulok, Carl Meyer, Taylor, T-256, George Sakkis, Qi Zhang, Feuermurmel, Brian Pugh and 16 more ActivityJelleZijlstra commented on Jun 8, 2023 I put up a first implementation at #105511. Some thoughts on the details:
- I implemented it by making
typing.Union just a re-export of types.UnionType, but I feel it might actually be more intuitive if typing.Union was the canonical name of the object, and types.UnionType was an alias. We could change the implementation to set the module and name differently.
- The repr() of all unions changes to use the
| syntax.
- I added dummy
__name__, __qualname__, and __origin__ fields to types.UnionType to satisfy some test_typing tests.
- We no longer support writing to a union's
__args__ attribute. A test relied on this, but nobody should have been assigning to __args__ anyway, so I'm fine with this change.
- There's a couple of behavior changes around
issubclass() and subclassing because types.UnionType is (unlike typing.Union) an actual type.
tibbe commented on Jun 14, 2023 This broken an AST walker I had written for Python 3.9, after I upgraded all my Union[X, Y] to X | Y, something is expected to be purely syntactical change. Reacted by Simon-Martin Schröder samsonvd commented on Sep 28, 2024 Will this also fix the issue of unsupported operand type(s) for |: 'str' and ... when using a string reference of a type?
i.e.
class Foo:
def get_self(self) -> "Foo" | None:
pass
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# File "<stdin>", line 2, in Foo
# TypeError: unsupported operand type(s) for |: 'str' and 'NoneType'
from typing import Union
class Foo:
def get_self(self) -> Union["Foo", None]:
pass
# no issuesJelleZijlstra commented on Sep 28, 2024 hauntsaninja commented on Sep 28, 2024 serhiy-storchaka commented on Jul 24, 2025 I think this was a mistake. types.UnionType was intentionally named so to avoid confusion with typing.Union (see #88895
). types.UnionType should not be subscriptable because it is not generic type (and if it was a generic type, subscription would have different semantic than for typing.Union). types.UnionType corresponds to typing._UnionGenericAlias, not typing.Union. added a commit that references this issue on Aug 7, 2026gh-105499: Avoid using `functools.reduce()` to reconstruct `Union` ob…
MetadataMetadataDevelopmentNo branches or pull requestsIssue actions
|