class PG(Protocol[T]):
def meth(x): ...
+ @runtime_checkable
+ class WeirdProto(Protocol):
+ meth = str.maketrans
+
+ @runtime_checkable
+ class WeirdProto2(Protocol):
+ meth = lambda *args, **kwargs: None
+
+ class CustomCallable:
+ def __call__(self, *args, **kwargs):
+ pass
+
+ @runtime_checkable
+ class WeirderProto(Protocol):
+ meth = CustomCallable()
+
class BadP(Protocol):
def meth(x): ...
class C:
def meth(x): ...
- self.assertIsInstance(C(), P)
- self.assertIsInstance(C(), PG)
+ class C2:
+ def __init__(self):
+ self.meth = lambda: None
+
+ for klass in C, C2:
+ for proto in P, PG, WeirdProto, WeirdProto2, WeirderProto:
+ with self.subTest(klass=klass.__name__, proto=proto.__name__):
+ self.assertIsInstance(klass(), proto)
+
with self.assertRaises(TypeError):
isinstance(C(), PG[T])
with self.assertRaises(TypeError):
self.assertIsInstance(C(1), P)
self.assertIsInstance(C(1), PG)
+ def test_protocols_isinstance_monkeypatching(self):
+ @runtime_checkable
+ class HasX(Protocol):
+ x: int
+
+ class Foo: ...
+
+ f = Foo()
+ self.assertNotIsInstance(f, HasX)
+ f.x = 42
+ self.assertIsInstance(f, HasX)
+ del f.x
+ self.assertNotIsInstance(f, HasX)
+
def test_protocol_checks_after_subscript(self):
class P(Protocol[T]): pass
class C(P[T]): pass