Do not count `__slots__` as a protocol member
Refs https://github.com/python/mypy/pull/9314 Closes https://github.com/python/mypy/issues/11884
It's not so clear-cut, but would it be worth special-casing __class_getitem__ in the same way? It might avoid regressions like this (cc. @hauntsaninja)
It's not so clear-cut, but would it be worth special-casing class_getitem in the same way?
Can you please open a new issue for it? Probably we need to discuss / research all special cases separatelly. But, it looks like a good candidate 👍
It's not so clear-cut, but would it be worth special-casing class_getitem in the same way?
Can you please open a new issue for it? Probably we need to discuss / research all special cases separatelly. But, it looks like a good candidate 👍
Sure!
New issue filed here: https://github.com/python/mypy/issues/11886
Now I am also thinking: what if I want to have a function / interface / contract / whatever that only works with slotted types? How can I express this?
For example:
def pretty_print_slots(klass_with_slots: ???) -> None:
...
I guess what Eric said in https://github.com/python/mypy/issues/11886 really makes sense. So, proably we can ignore protocols __slots__ = () definition as a "performance hack", we need to treat __slots__: str | Iterable[str] as a part of the protocol.
Do you agree?
That sounds like a decent solution too, tried it out a bit and found some weird behavior in current mypy somewhat related to this, just bringing this up because it's a bit funny:
This fails:
import typing
@typing.runtime_checkable
class Foo(typing.Protocol):
__slots__ = ()
class Bar(Foo):
...
print(issubclass(Bar, Foo)) # this fails
and this works:
import typing
@typing.runtime_checkable
class Foo(typing.Protocol):
__slots__: str | typing.Iterable[str] = ()
class Bar(Foo):
...
print(issubclass(Bar, Foo)) # this does not ?
(Anyways, that'll get fixed by this too, it's just some weird behavior...)
Basically yes, I agree that would make sense to me -- though I'm sure any solution would be nice.
We are blocked by https://github.com/python/mypy/issues/11891
We are blocked by #11891
I wonder if it's even helpful for typeshed to define __slots__ in the stub for object (as it does currently), or if it should be removed. Given that __slots__ are so special, it doesn't seem like it does much for the type-checker.
@AlexWaygood well, technically, object does not have __slots__.
>>> object.__slots__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'object' has no attribute '__slots__'. Did you mean: '__class__'?
>>> object().__slots__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute '__slots__'. Did you mean: '__class__'?
My vote is to remove them (my opinion is pretty simple: typeshed should be as close to source as possible).
According to mypy_primer, this change has no effect on the checked open source code. 🤖🎉
Diff from mypy_primer, showing the effect of this PR on open source code:
discord.py (https://github.com/Rapptz/discord.py)
- discord/ext/commands/core.py:2333: error: Argument 1 to "is_owner" of "BotBase" has incompatible type "Union[discord.user.User, Member]"; expected "discord.abc.User"
What's the status of this?
Instead of hard-coding __slots__, shouldn't this check a collection of what to exclude so that what's excluded can be easily updated? From the discussion on #11886, apparently Python uses this collection to decide what to exclude from Protocol. Perhaps follow exactly what Python excludes rather than debating which ones should be special-cased in Mypy? I assume if this route is taken then Mypy would need a collection for each Python version with differing exclusions.
Maybe I should try making a separate PR with my suggestions?
@HexDecimal I've deleted my fork by accident. You can re-submit this if you need this feature :)
I'll go ahead and attempt my own PR. I mostly want to fetch your test to work with.
Great, ping me to review your PR :)