False negative when assigning abstract class to `type[T]`
The typing spec indicates that only instantiable class objects are compatible with type[T]. Pyright correct detects an attempt to assign an abstract class to type[T] in most cases, but it fails to report an error if the class is a subclass of a protocol that doesn't implement all of the protocol's methods.
from typing import Protocol
class AProto(Protocol):
def foo(self, a: str): ...
class A(AProto): ...
def func(x: type[AProto]): ...
# This should generate an error
func(A)
# So should this
v: type[AProto] = A
While mypy does raise an error for this it also raises one with distinct error code and not general type compatibility error. Here's mypy reporting,
main.py:12: error: Only concrete class can be given where "type[AProto]" is expected [type-abstract]
main.py:15: error: Can only assign concrete classes to a variable of type "type[AProto]" [type-abstract]
Found 2 errors in 1 file (checked 1 source file)
I'd similarly prefer that to be case here as it's fairly common for my codebase to pass abstract types and do some runtime introspection with them. Mostly methods like,
def create(t: type[T], config: bytes) -> T:
...
and T here is fine to be passed abstract, while concrete part is derived from second argument contents (or basically type safe json.load/pickle.load).
edit: Pondering most of code I have that does this would prefer TypeForm[T] over type[T] so if TypeForm[T] has no abstract restrictions that's enough and I'll eventually swap to it.
I've reviewed the typing spec, and it doesn't actually say that only instantiable classes are compatible with type[T]. This is arguably implied, but it's not explicitly stated. For that reason, I'm going to leave the current behavior in place since no pyright users have complained about it. I'm willing to revisit this in the future if and when the typing spec further clarifies the intended behavior.