ban calling instance methods on classes
Description
from typing import override
class Fruit:
def enjoy(self) -> None:
print("tasty fruit")
class Banana(Fruit):
def __init__(self):
self.length: int = 42
@override
def enjoy(self) -> None:
if self.length > 10:
print("mmm banana")
def foo(t: type[Fruit]):
t.enjoy(Fruit())
foo(Banana) # AttributeError: 'Fruit' object has no attribute 'length'
i think the reason it's unsafe is that because self is a normal argument when the method is called on the class, and its type is Self which is essentially a TypeVar, it needs to be contravariant because it's an input parameter.
this is not an issue when you call the method on the instance because it's impossible to call the method with the wrong type as the self argument:
def foo(t: type[Fruit]):
t().enjoy() # no error
Fruit().enjoy() # no error
upstream issue: https://github.com/microsoft/pyright/issues/11007
The only thing that should be done with type[X] is call classmethod or staticmethod or access ClassVar
and a temporary allowance until we have intersections:
calling the object to make an instance of it
That should normally be done with Callable[[], X], but in some cases someone might need to also access one of the previously mentioned things, like accessing a ClassVar - That should be done with Callable[[], X] & type[X] - but until we have intersections, we have to allow calling the type to make an instance of it.