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

Generic class with a single upper bound of a union type #18313

Closed
ritsuki1227 opened this issue Dec 19, 2024 · 2 comments
Closed

Generic class with a single upper bound of a union type #18313

ritsuki1227 opened this issue Dec 19, 2024 · 2 comments
Labels
bug mypy got something wrong

Comments

@ritsuki1227
Copy link

ritsuki1227 commented Dec 19, 2024

Bug Report

When implementing the following generic class with a single upper bound of a union type, you get the following errors, while no errors are raised when using multiple upper-bounds.

To Reproduce

class Example1[T: (str, int)]:
    def foo(self, a: T) -> T:
        if isinstance(a, int):
            return a + 1
        elif isinstance(a, str):
            return a + "hello"


class Example2[T: int | str]:
    def bar(self, a: T) -> T:
        if isinstance(a, int):
            return a + 1
        elif isinstance(a, str):
            return a + "hello"

Expected Behavior

Class Example2 should raise no errors.

Actual Behavior

Class Example2 raises the following error:

error: Incompatible return value type (got "int", expected "T")  [return-value]
error: Incompatible return value type (got "str", expected "T")  [return-value]

Your Environment

  • Mypy version used: 1.13.0
  • Mypy command-line flags: --strict
  • Mypy configuration options from mypy.ini (and other config files):
  • Python version used: 3.12.3
@ritsuki1227 ritsuki1227 added the bug mypy got something wrong label Dec 19, 2024
@JelleZijlstra
Copy link
Member

This error is correct.

Your Example1 does not use multiple bounds, but constraints, which work differently. A TypeVar with constraints can be solved only to exactly int or str, and the method must return int if an int is given, and str if a str is given. But Example2 uses a bound, and the signature says that the return type must be exactly the same as the input type, for any consistent subtype of int | str. For example, bool is a subclass of int, so Example2().bar(True) should return bool, but in your implementation it doesn't: it returns 2, an int.

@JelleZijlstra JelleZijlstra closed this as not planned Won't fix, can't repro, duplicate, stale Dec 19, 2024
@ritsuki1227
Copy link
Author

@JelleZijlstra Thank you for your clear explanation even though it is an expected behavior. Your examples are also easy to understand.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong
Projects
None yet
Development

No branches or pull requests

2 participants