basedpyright icon indicating copy to clipboard operation
basedpyright copied to clipboard

infer types from super

Open KotlinIsland opened this issue 1 year ago • 9 comments

class A:
    def f(self, i: int) -> str:
        ...
class B(A):
    @override
    def f(self, i):
        reveal_type(i)  # int

KotlinIsland avatar Apr 12 '24 00:04 KotlinIsland

looks like pyright already does this, so all we need to do is make it not report reportMissingParameterType on the overridden method

DetachHead avatar Jun 13 '24 10:06 DetachHead

even though pyright is working here, there is no inlay hint on the parameter

KotlinIsland avatar Jul 20 '24 04:07 KotlinIsland

i think there still needs to be an option to still report reportMissingParameterType in such cases, because there are libraries that have decorators that rely on type annotations for runtime checks

from pydantic import validate_call

class Foo:
    @abstractmethod
    def foo(self, value: int):
        ...

class Bar(Foo):
    @override
    @validate_call
    def foo(self, value):
        ...

ideally there would be something in the type system you could put on a decorator to tell the type checker that type annotations get runtime evaluated

DetachHead avatar Aug 12 '24 07:08 DetachHead

Isn't it the case that because of Barbara's substitution principle (I feel like I'm on a first-name basis with Liskov at this point), [email protected] could be any supertype of int in your example, @DetachHead ?

jorenham avatar Aug 12 '24 13:08 jorenham

yeah it's contravariant because it's in an input position. though i still think it's safe to assume that if you don't specify the type then it should just assume it's the same as in the base class

DetachHead avatar Aug 12 '24 13:08 DetachHead

Yea that seems reasonable. It's in line with the current behavior:

https://pyright-play.net/?pythonVersion=3.13&strict=true&deprecateTypingAliases=true&code=GYJw9gtgBAhgRgYygSwgBzCALrOBnLEGBLCAUywAswATAKFEiiwE81kA7AcxXUxzAA3MiBDIaZOnQQAbGHjxQAYmDAAuOlC1QAAvAJES5KrU3aJwKMFUAKPGRnAANFEEwZAVzJqUHLAEoNbWCoADpwqVl5RQAhGBAbFTBAsy0dIRExCVSoCytbe0cXN08yQLCIkO0pOHioAF4oOIT-OlqQUOswGwAWACZW9s7bAGZQgEYe1rogA

https://basedpyright.com/?typeCheckingMode=all&code=GYJw9gtgBAhgRgYygSwgBzCALrOBnLEGBLCAUywAswATAKFEiiwE81kA7AcxXUxzAA3MiBDIaZOnQQAbGHjxQAYmDAAuOlC1QAAvAJES5KrU3aJwKMFUAKPGRnAANFEEwZAVzJqUHLAEoNbWCoADpwqVl5RQAhGBAbFTBAsy0dIRExCVSoCytbe0cXN08yQLCIkO0pOHioAF4oOIT-OlqQUOswGwAWACZW9s7bAGZQgEYe1rogA

jorenham avatar Aug 12 '24 13:08 jorenham

Apparantly mypy has a rather liberal interpretation of contravariance, and allows the following (if run with the default flags):

from abc import abstractmethod
from typing import override

class Foo:
    @abstractmethod
    def foo(self, value: int):
        ...

class Bar(Foo):
    @override
    def foo(self, value): ...
        

bar = Bar()
bar.foo(42)
bar.foo(3.14)
bar.foo('nope')  # mypy doesn't care about your problems

jorenham avatar Aug 12 '24 13:08 jorenham

yeah that's because mypy types it as Any if there's no annotation instead of inferring it from the base class like pyright does

class Foo:
    @abstractmethod
    def foo(self, value: int):
        ...

class Bar(Foo):
    @override
    def foo(self, value):
        reveal_type(value) # Any

DetachHead avatar Aug 12 '24 23:08 DetachHead

yeah that's because mypy types it as Any if there's no annotation instead of inferring it from the base class like pyright does

Ah I see.

I suppose that within the valid solution-space, mypy's would lie within the infemum. Or as Wolfgang Pauli once put it:

That is not only not right; it is not even wrong.

jorenham avatar Aug 13 '24 00:08 jorenham