Skip to content

Generic argument is not being identified #18933

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

Open
Alc-Alc opened this issue Apr 17, 2025 · 4 comments
Open

Generic argument is not being identified #18933

Alc-Alc opened this issue Apr 17, 2025 · 4 comments
Labels
bug mypy got something wrong topic-pep-695 Issues related to PEP 695 syntax

Comments

@Alc-Alc
Copy link

Alc-Alc commented Apr 17, 2025

Bug Report

The code in this mypy playground raises the following error.

Name "T" is not defined  [name-defined]

However, as seen in this pyright playground there is no error, which leads me to believe that the snippet is well defined.

This one is probably related but the revealed types do not seem to match as well (the ? in the type name seems to be rather strange).

mypy

"__main__.Repo[T?, U`-2]"

pyright

"Repo[T@some, U@some]"

To Reproduce (this is the same code as in the mypy playground)

from typing import cast, reveal_type
from collections.abc import Callable

class Repo[T, U]: ...

def some[T, U, **P](func: Callable[P, U]) -> Callable[P, U]:
    def wrapper(*args: P.args, **kwargs: P.kwargs) -> U:
        reveal_type(cast(Repo[T, U], args[0]))
        return func(*args, **kwargs)
    return wrapper

Expected Behavior

No errors from mypy, similar behavior to pyright.

Actual Behavior

I am not sure if mypy is misdiagnosing this, if you feel this is intended behavior I can try raising an issue with pyright.

Your Environment

  • Mypy version used: 1.15.0 (playground)
  • Pyright version used: 1.1.399 (playground)
  • Mypy command-line flags: default settings in mypy playground (if I am not mistaken, there are no extra flags)
  • Mypy configuration options from mypy.ini (and other config files): N/A
  • Python version used: 3.13 (for both playgrounds)

Thank You

Edit: Simplified the example a bit by removing the bounds and awaitables.

@Alc-Alc Alc-Alc added the bug mypy got something wrong label Apr 17, 2025
@A5rocks
Copy link
Collaborator

A5rocks commented Apr 18, 2025

Minimized:

def some[T]() -> None:
    x: list[T]
    reveal_type(x)

@A5rocks A5rocks added the topic-pep-695 Issues related to PEP 695 syntax label Apr 18, 2025
@sterliakov
Copy link
Collaborator

sterliakov commented Apr 19, 2025

This is funny! Yes, type vars are now bound in the function body if typevar is used in argument types or return types (or comes from parent scope - class or function). It's a bug to not bind them by PEP695 syntax ("name-defined" is wrong error code). However, your usage (and especially the simplified snippet in the previous comment) is still invalid - semantically, T has no meaning there, it isn't coming from the signature or parent scopes. Same as in

from typing import TypeVar

T = TypeVar("T")
def foo() -> None:
    x: T  # E: Type variable "__main__.T" is unbound  [valid-type] \
          # N: (Hint: Use "Generic[T]" or "Protocol[T]" base class to bind "T" inside a class) \
          # N: (Hint: Use "T" in function signature to bind "T" inside a function)

where mypy produces a correct error. IMO the cleanest solution would be to emit exactly the same error in the OP case.

@Alc-Alc
Copy link
Author

Alc-Alc commented Apr 20, 2025

Thanks for responding @sterliakov.

I tried a slightly modified version of @A5rocks' snippet (assigned x to an empty list to remove the unbound error). It indeed fails in Pyright when using TypeVar but not when using 695 syntax. For completion sake, here are all the 4 versions.

Pyright (TypeVar) - Intended behavior Type variable "T" has no meaning in this context
Pyright 695 - no issues (Bugged behavior?)

Mypy (TypeVar) - Intended behavior Type variable "__main__.T" is unbound [valid-type]
Mypy 696 - Intended behavior but misleading error message Name "T" is not defined [name-defined]

Is Pyright wrong and should I raise an issue there?

PS: I am aware I might have repeated what you both mentioned with different phrasing, but if I am planning to raise this in Pyright, I believe a single comment with the entire context could be useful.

PPS: This might be tangential and I can move this part to discussion (or any other relevant forum), do you mind helping me understand how I can express my original use case in mypy if this is intended behavior? I want Repo to be generic on T and U.

@A5rocks
Copy link
Collaborator

A5rocks commented Apr 20, 2025

No, I think this should work with PEP 695 syntax. The user is explicitly binding the type variable in the function and mypy should respect that intent even if there's no arguments for it (maybe there should be an error about the [T] on the function).

@Alc-Alc the reason this doesn't work for TypeVar is because mypy doesn't know what is generic in T! Imagine this:

def f():
  def g():
    x: T

Which function is generic in T? (also it's an antipattern but I think it's important to have lints specifically for that antipattern)


but also, what @sterliakov is pointing out is that your function does not take any argument for T, so mypy will never know what type T is. This shouldn't matter at function declaration though (though it's a sign you're missing something) and at usage mypy can fill it in with Never.

You probably mean something like this:

from typing import cast, reveal_type
from collections.abc import Callable

class Repo[T, U]: ...

def some[U, **P](func: Callable[P, U]) -> Callable[P, U]:
    def wrapper(*args: P.args, **kwargs: P.kwargs) -> U:
        reveal_type(cast(Repo[object, U], args[0]))
        return func(*args, **kwargs)
    return wrapper

or even better:

def some[T, U, **P](func: Callable[Concatenate[Repo[T, U], P], U]) -> Callable[Concatenate[Repo[T, U], P], U]:
    def wrapper(repo: Repo[T, U], /, *args: P.args, **kwargs: P.kwargs) -> U:
        reveal_type(repo)
        return func(repo, *args, **kwargs)
    return wrapper

(all above code is untested)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-pep-695 Issues related to PEP 695 syntax
Projects
None yet
Development

No branches or pull requests

3 participants