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

Warn for incorrect TypeVar usage (with Generics) #16113

Open
Dreamsorcerer opened this issue Sep 14, 2023 · 5 comments
Open

Warn for incorrect TypeVar usage (with Generics) #16113

Dreamsorcerer opened this issue Sep 14, 2023 · 5 comments
Labels

Comments

@Dreamsorcerer
Copy link
Contributor

Feature

Sometimes a user less familiar with more advanced typing concepts will use a TypeVar in a way that doesn't add any typing information.

As an example: def foo() -> T:

I think, basically, anytime a TypeVar appears only 1 time in a function (or class) definition, this should be treated as an error.

Pitch

Code like this seems like an obvious sign the user has misunderstood TypeVar, and a warning should probably be emitted. They either want a normal type, or they missed an annotation somewhere.

@A5rocks
Copy link
Contributor

A5rocks commented Sep 14, 2023

I remember hitting cases like this more generally, but just for the record this currently fails:

import typing

T = typing.TypeVar("T")

def f() -> T:
    ...

with this output:

main.py:5: error: Missing return statement  [empty-body]
main.py:5: error: A function returning TypeVar should receive at least one argument containing the same TypeVar  [type-var]
Found 2 errors in 1 file (checked 1 source file)

... to try to demonstrate that "more general" case, this doesn't fail:

import typing

T = typing.TypeVar("T")

def f() -> list[T]:
    ...

@hauntsaninja
Copy link
Collaborator

hauntsaninja commented Sep 15, 2023

Yup, this is a check we added in 0.981

For list[T], I believe it was intentional to not have the warning trigger for it, see #13061 (comment). I'm not sure I agree with that, but would be curious to know what @Dreamsorcerer 's real world code looks like.

@Dreamsorcerer
Copy link
Contributor Author

Ah, OK. The case I just saw was a custom user object of -> Task[T]:
pyinvoke/invoke#956 (comment)

@Dreamsorcerer
Copy link
Contributor Author

OK, so I think it's all Generic types that don't trigger the warning. I'm not sure I understand the comment from @JukkaL, as that use case appears to be exactly the same as doing Bucket[Any], so why use a TypeVar?

Minimal reproducer:

from typing import Generic, TypeVar

T = TypeVar("T")

class Foo(Generic[T]):
    ...

def foo() -> Foo[T]:
    ...

@Dreamsorcerer Dreamsorcerer changed the title Warn for incorrect TypeVar usage Warn for incorrect TypeVar usage (with Generics) Sep 25, 2023
@clo-vis
Copy link

clo-vis commented Jul 24, 2024

Comparison between mypy and pyright:

from typing import AnyStr, TypeVar

T = TypeVar("T")

def fun0() -> T: raise ValueError()
def fun1() -> AnyStr: raise ValueError()
def fun2() -> list[T]: raise ValueError()
def fun3() -> list[AnyStr]: raise ValueError()
def fun4() -> AnyStr | None: raise ValueError()

reveal_type(fun0())
reveal_type(fun1())
reveal_type(fun2())
reveal_type(fun3())
reveal_type(fun4())
Line mypy pyright
def fun0() -> T: A function returning TypeVar should receive at least one argument containing the same TypeVar TypeVar "T" appears only once in generic function signature. Use "object" instead
def fun1() -> AnyStr: A function returning TypeVar should receive at least one argument containing the same TypeVar -
def fun2() -> list[T]: - TypeVar "T" appears only once in generic function signature. Use "object" instead
def fun3() -> list[AnyStr]: - -
def fun4() -> AnyStr | None: - -
reveal_type(fun0()) Never Unknown
reveal_type(fun1()) builtins.str Unknown
reveal_type(fun2()) builtin.list[Never] list[Unknown]
reveal_type(fun3()) builtin.list[str] list[Unknown]
reveal_type(fun4()) Union[builtin.str | None] None

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

No branches or pull requests

4 participants