-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Closed as duplicate of#11979
Closed as duplicate of#11979
Copy link
Labels
Description
Bug Report
When using a @runtime_checkable
protocol and checking isinstance(self, MyProtocol)
, mypy does not correctly narrow the type of self
if the isinstance
result is first stored in a variable. This results in false positives when accessing protocol members, even though the code is valid at runtime.
To Reproduce
from abc import ABC
from typing import Protocol, runtime_checkable
@runtime_checkable
class MyProtocol(Protocol):
def my_method(self, arg: int) -> str: ...
class Base(ABC):
def foo(self) -> None:
has_my_method = isinstance(self, MyProtocol)
if has_my_method:
# ❌ Mypy error:
# test.py:17: error: "Base" has no attribute "my_method" [attr-defined]
self.my_method(42)
if isinstance(self, MyProtocol):
# ✅ Works fine here
self.my_method(42)
class Extends(Base, MyProtocol):
def my_method(self, arg: int) -> str:
return f"Called with {arg}"
Expected Behavior
Both forms should refine self
to MyProtocol
inside the if
block, since semantically the two checks are equivalent at runtime. Maybe I'm missing something here?
For example, the same pattern works fine if there is no self involved:
from typing import Protocol, runtime_checkable
@runtime_checkable
class MyProtocol(Protocol):
def my_method(self, arg: int) -> str: ...
class MyClass:
def my_method(self, arg: int) -> str:
return f"Called with {arg}"
obj = MyClass()
has_my_method = isinstance(obj, MyProtocol)
if has_my_method:
# ✅ No error
obj.my_method(42)
Environment:
mypy 1.17.0 (compiled: yes)