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

Mypy cannot reason with default param for unbound TypeVar (False positive?) #16595

Closed
couling opened this issue Dec 1, 2023 · 2 comments
Closed
Labels
bug mypy got something wrong

Comments

@couling
Copy link

couling commented Dec 1, 2023

Bug Report

Default values are incorrectly flagged as incompatible with unbound TypeVar.

To Reproduce

import typing

_T = typing.TypeVar("_T")

def foo(bar: _T = ...) -> _T:
    return bar

Expected Behavior

This should be fine. Unbound typing.TypeVar("_T") should accept the same as typing.Any.

For example this does work:

import typing

_T = typing.TypeVar("_T")

def foo(bar: _T) -> _T:
    return bar

def test_this():
    # Perfectly valid 🎉
    x = foo(...)

Actual Behavior

error: Incompatible default for argument "default" (default has type "ellipsis", argument has type "_T")  [assignment]

Somewhat misleadingly, bar: _T = None results in an error stating

PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True

But this isn't implicitly optional: it's explicitly the same as Any.

Your Environment

  • Mypy version used: 1.7.1
  • Python version used: 3.10

Discussion on complexity

I realise this is likely to be a complex corner case to handle. In discussion it would be better to separate the complexity of changing this behaviour from the correctness of this behaviour.

There is a knock on inference here where there is more than one parameter using the same TypeVar. Eg:

def baz(a: _T, b: _T = 123) -> None:
    ....

Logically this would infer that these are subsequently all fine:

baz(321)
baz(321, 567)
baz("aaa", "bbb")

But this would be an error:

baz("aaa")

I realise that might be incredibly complex to implement.

At least...
It would be helpful if mypy could be more informative about this. If (mypy or python typing hinting in general) cannot reason with defaults and unbound TypeVars then it would be better for users to be told this.

@couling couling added the bug mypy got something wrong label Dec 1, 2023
@skewty
Copy link

skewty commented Feb 5, 2024

I am seeing a similar issue but with a bound TypeVar.

Perhaps subject could be edited and expanded by removing "unbounded" word?

See below:

from dataclasses import dataclass
from typing import TypeVar


@dataclass
class Location:
    id: int
    name: str


LocationT = TypeVar("LocationT", bound=Location)


# Location is the default model to use if not overriden; mypy complains about the assignment
def test_mypy(id_: int, name: str, model: type[LocationT] = Location) -> LocationT:  # type: ignore[assignment]
    return model(id_, name)


test_mypy(12, "Fred", Location)  # mypy accepts Location here

@hauntsaninja
Copy link
Collaborator

Duplicate of #3737

@hauntsaninja hauntsaninja marked this as a duplicate of #3737 Feb 5, 2024
@hauntsaninja hauntsaninja closed this as not planned Won't fix, can't repro, duplicate, stale Feb 5, 2024
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

3 participants