Closed DetachHead closed 3 months ago
Pyright doesn't currently implement this check. It's not really a type checking issue, so a type checker isn't under obligation to catch errors like this one. I'll switch it to an enhancement request and consider it in that light.
It's not clear to me whether this is a bug in the runtime. I would have assumed that this was legal, so it's a surprise to me that it's not. Perhaps it was just an oversight when generic support was added to the language. Do you have any information that confirms this isn't simply a Python bug? Have you tried reporting it?
I suspect that no one has ever tried to do what you're doing here, so maybe it has never come up before. I don't think this is a common source of errors.
I'm going to close the enhancement request for now, but I'm willing to reconsider in the future if there's signal from other pyright users (in the form of additional upvotes on this issue) that this is important to them.
This isn't a Python bug, it's how generics work. Foo[int]
isn't a class, it's a generic alias object.
>>> from typing import *
>>> T = TypeVar('T')
>>> class Foo(Exception, Generic[T]): ...
...
>>> type(Foo)
<class 'type'>
>>> type(Foo[int])
<class 'typing._GenericAlias'>
Foo[int]
only functions as a subclass of Foo
when treated as a type annotation, but it's an unrelated object during runtime. Pyright in this code segment accidentally reads it as if it was an actual class.
it's a generic alias object
That's an implementation detail, not part of the mental model for most developers. In most cases, Foo[int]
acts like Foo
at runtime. For example, you can call Foo[int]
to invoke Foo
's constructor, and Foo[int].x
accesses class variable x
on Foo
. Clearly, the implementers of generic types went through some trouble to make it appear from a developer's perspective that Foo[int]
is a class. It's not clear to me whether it was an oversight that Foo[int]
cannot be used in an except
statement.
i agree with @erictraut here. the internal implementation details of python's type system seem to often come up when type annotations get evaluated at runtime and are a massive source of confusion for developers, so much so that pyright warns against some of them. though i really think it's python's respnsibility to hide these internals from the user as much as possible. that seems to be the direction theyr'e taking since most of the runtime errors pyright warns you about were fixed several years ago.
i've raised it here: https://github.com/python/cpython/issues/119094
@erictraut it was closed with the reasoning that it also doesn't work in isinstancec
checks. since pyright warns when you use use generic aliases in isinstance
checks, could this issue be re-opened?
Yes, I closed the CPython issue. Catching a generic alias doesn't make sense since the runtime can't know whether it's handling a Foo[str]
or a Foo[int]
, especially in the exception catching code (which doesn't look at __instancecheck__
or other dynamic behavior).
Technically type checkers should probably catch this but it feels low priority, since it's unlikely to come up in practice.
playground
this should be a type error because it fails at runtime with the following exception: