Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge typing.Union and types.UnionType #105499

Open
JelleZijlstra opened this issue Jun 8, 2023 · 5 comments
Open

Merge typing.Union and types.UnionType #105499

JelleZijlstra opened this issue Jun 8, 2023 · 5 comments
Assignees
Labels
3.13 bugs and security fixes topic-typing type-feature A feature request or enhancement

Comments

@JelleZijlstra
Copy link
Member

JelleZijlstra commented Jun 8, 2023

Currently, 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:

  1. Make typing.Union an alias for types.UnionType and make it so types.UnionType[A, B] works, accepting the same types Union accepts now.
  2. Loosen the rules for what the | operator accepts to accept more types that are commonly used in unions.

Linked PRs

@JelleZijlstra
Copy link
Member Author

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
Copy link

tibbe commented 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.

@MarsCapone
Copy link

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 issues

@JelleZijlstra
Copy link
Member Author

@MarsCapone, no, but other changes in Python 3.14 (PEP-649) will fix that case.

@hauntsaninja
Copy link
Contributor

hauntsaninja commented Sep 28, 2024

See also https://mypy.readthedocs.io/en/stable/runtime_troubles.html and from __future__ import annotations, for mostly solutions in Python 3.7 onwards

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.13 bugs and security fixes topic-typing type-feature A feature request or enhancement
Projects
None yet
Development

No branches or pull requests

4 participants