Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

__instancecheck__ on an instance works at runtime, but mypy thinks it's invalid #12974

Closed
glyph opened this issue Jun 12, 2022 · 4 comments
Closed
Labels
feature priority-2-low topic-runtime-semantics mypy doesn't model runtime semantics correctly

Comments

@glyph
Copy link

glyph commented Jun 12, 2022

Bug Report

class Classish:
  def __instancecheck__(self, other: object) -> bool:
    return other == 7

c = Classish()
print(isinstance(3, c))
print(isinstance(7, c))

Expected Behavior

This seems like it should be valid, since at runtime it prints False then True as one would expect.

Actual Behavior

what.py:6: error: Argument 2 to "isinstance" has incompatible type "Classish"; expected "Union[type, UnionType, Tuple[Union[type, UnionType, Tuple[Any, ...]], ...]]"

Your Environment

  • Mypy version used: mypy 0.961 (compiled: yes)
  • Mypy command-line flags: none
  • Mypy configuration options from mypy.ini (and other config files):
  • Python version used: 3.10.4 (python.org)
  • Operating system and version:
ProductName:	macOS
ProductVersion:	12.4
BuildVersion:	21F79

** P.S. **

If you just want to close this one because this is not really what isinstance is supposed to mean in the context of static type checking, that kinda makes sense, I would not strongly argue that this really needs to work. It just seems somewhat at odds with the hookable runtime behavior of isinstance.

@glyph glyph added the bug mypy got something wrong label Jun 12, 2022
@AlexWaygood
Copy link
Member

Here's the current typeshed stub for isinstance:

import types
from typing import Any

def isinstance(
    __obj: object, __class_or_tuple: type | types.UnionType | tuple[type | types.UnionType | tuple[Any, ...], ...]
) -> bool: ...

We could change this to something like this:

import types
from typing import Any, Protocol

class _SupportsInstanceCheck(Protocol):
    def __instancecheck__(self, other: object) -> bool: ...

def isinstance(
    __obj: object, __class_or_tuple: type | types.UnionType | _SupportsInstanceCheck | tuple[type | types.UnionType | _SupportsInstanceCheck | tuple[Any, ...], ...]
) -> bool: ...

But I think doing so might be a bad idea. isinstance() is heavily special-cased by type checkers, and they won't be able to understand code that uses dynamic __instancecheck__ hooks anyway. The benefit seems pretty niche, no?

@AlexWaygood AlexWaygood added feature topic-runtime-semantics mypy doesn't model runtime semantics correctly priority-2-low and removed bug mypy got something wrong labels Jun 12, 2022
@glyph
Copy link
Author

glyph commented Jun 12, 2022

But I think doing so might be a bad idea. isinstance() is heavily special-cased by type checkers, and they won't be able to understand code that uses dynamic __instancecheck__ hooks anyway.

I think if this is to be supported, it does need to have a separate @override or something, for being a type-guard in one case and not in the other. I don't think the special-casing of other type-checkers should inform Mypy's decision much though?

The benefit seems pretty niche, no?

Yeah, definitely, this is not a feature I'd push hard for.

@AlexWaygood
Copy link
Member

I don't think the special-casing of other type-checkers should inform Mypy's decision much though?

The point is that we'd have to make this change over at the typeshed repo rather than mypy (mypy vendors its stdlib stubs from typeshed). Mypy isn't the only type checker that uses typeshed's stubs: they're also used by pyright, pytype, pyre and pycharm. Are you prepared to file issues at all of them and make sure that this proposed change to the stub wouldn't break them? ;)

@AlexWaygood
Copy link
Member

Closing for the reasons I mentioned above: I don't think this is worth the possible breakage to type checkers, sorry :)

(This proposed change would also probably need to be discussed over at the typeshed repo rather than here, since the first thing that needs to happen in order for this to be fixed would be for the typeshed stubs to be changed.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature priority-2-low topic-runtime-semantics mypy doesn't model runtime semantics correctly
Projects
None yet
Development

No branches or pull requests

2 participants