pythonpython-typingpyright

Why are generic arguments described by `T@function_name` by pyright?


Given the following block of code:

import typing as tp

T = tp.TypeVar("T")

def dummy(item: T) -> T:
    return item

reveal_type(dummy)

When run onto it, pyright prints:

> pyright myfile.py
[...]
information: Type of "dummy" is "(item: T@dummy) -> T@dummy"
0 errors, 0 warnings, 1 information 

Note the T@dummy in the output.

Note: I found in the pyright doc this paragraph that mentions this phenomenon in the special case of self and cls argument, without more details.


Solution

  • To answer this lets look at the following case:

    from typing import TypeVar, Generic
    
    T = TypeVar("T")
    
    class Baz:
       def __init__(self, a: T):
          self.arg = a
    
       def boo(self, a: T):
           return self.arg
    

    First you T is a global variable that can be used in various ways during your script. The "@Scope" is used to differentiate where it is used. In some cases, especially inside a class, it is very important do differentiate.

    The signature of Baz.boo is boo(a: T@Baz.boo) -> T@Baz.__init__ the return type, while being the same variable, is different and is the type that was fixed to self.arg during Baz.__init__.

    While this is a guess, internally it will be much easier to track and just display "TypeVarName@Scope" compared to adding checks that compare if the locations are truly the same and then strip the location part.