Repository navigation
Merge typing.Union and types.UnionType #105499
Description
Activity
- addedtype-featureA feature request or enhancementA feature request or enhancement3.13only security fixesonly security fixes
on Jun 8, 2023 I put up a first implementation at #105511. Some thoughts on the details:
- I implemented it by making
typing.Unionjust a re-export oftypes.UnionType, but I feel it might actually be more intuitive iftyping.Unionwas the canonical name of the object, andtypes.UnionTypewas 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 totypes.UnionTypeto satisfy sometest_typingtests. - 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 becausetypes.UnionTypeis (unliketyping.Union) an actual type.
- I implemented it by making
This broken an AST walker I had written for Python 3.9, after I upgraded all my
Union[X, Y]toX | Y, something is expected to be purely syntactical change.Reacted by Simon-Martin SchröderWill 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 issues
@marscapone, no, but other changes in Python 3.14 (PEP-649) will fix that case.
See also https://mypy.readthedocs.io/en/stable/runtime_troubles.html and
from __future__ import annotations, for mostly solutions in Python 3.7 onwards- added 3 commits that reference this issue
on Mar 12, 2025 - added a commit that references this issue
on Mar 19, 2025 - added 2 commits that reference this issue
on Mar 29, 2025 - added 3 commits that reference this issue
on Jul 21, 2025 I think this was a mistake.
types.UnionTypewas intentionally named so to avoid confusion withtyping.Union(see #88895
).types.UnionTypeshould not be subscriptable because it is not generic type (and if it was a generic type, subscription would have different semantic than fortyping.Union).types.UnionTypecorresponds totyping._UnionGenericAlias, nottyping.Union.- added a commit that references this issue
on Aug 7, 2026
Currently, unions created through
typing.Union[A, B]and through the PEP-604 syntaxA | Bare 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:
typing.Unionan alias fortypes.UnionTypeand make it sotypes.UnionType[A, B]works, accepting the same typesUnionaccepts now.|operator accepts to accept more types that are commonly used in unions.Linked PRs
functools.reduce()to reconstructUnionobjects #155280