typeshed icon indicating copy to clipboard operation
typeshed copied to clipboard

Explicitly mark subclasses of collections.abc protocols as abstract base classes

Open gracepetryk opened this issue 1 year ago • 2 comments

There are a few types in collection.abc that subclass protocols but are not protocols themselves. For example Sequence is a subclass of Collection and Reversible. It expects subclasses to implement __getitem__ and __len__, the latter being a requirement of the Collection protocol. I think that the stubs for these classes should explicitly subclass abc.ABC so that typecheckers require implementation of all abstract methods when the @final annotation is used.

Currently typecheckers disagree on how to handle these stubs. For this example mypy asks for __getitem__ and __len__ implementations and pyright throws no error:

from collections.abc import Sequence
from typing import final

@final
class Foo(Sequence[int]):
    pass
bash-3.2$ mypy test.py
test.py:5: error: Final class test.Foo has abstract attributes "__getitem__", "__len__"  [misc]
Found 1 error in 1 file (checked 1 source file)
bash-3.2$ pyright test.py
0 errors, 0 warnings, 0 informations

At runtime the types in collections.abc are already abstract base classes:

>>> from collections.abc import Sequence
>>> Sequence.__class__
<class 'abc.ABCMeta'>

gracepetryk avatar Jan 10 '24 01:01 gracepetryk

This sounds like something we would have tried before and didn't do for one reason or another. Possibly because we also mark some of the classes as protocols, and that might not interact well with ABCMeta. That said, as we strive to follow the implementation if possible, I agree that this something we should at least try do to – or at least document in the stubs why we don't do it.

Exploratory PR welcome, unless someone else knows why didn't do it before.

srittau avatar Jan 10 '24 14:01 srittau

There's a note in PEP-544 about this that to me sounds like marking all the non-protocol collection.abc classes as ABCs in the stubs would be a good solution. I'll submit a PR doing that a little later today.

Subclassing a protocol class would not turn the subclass into a protocol unless it also has typing.Protocol as an explicit base class. Without this base, the class is “downgraded” to a regular ABC that cannot be used with structural subtyping.

gracepetryk avatar Jan 10 '24 16:01 gracepetryk