Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Prev Previous commit
Next Next commit
Move tests around, add some more
  • Loading branch information
AlexWaygood committed Mar 31, 2023
commit 081218320d3173ccfebd1becebb2a8f7f0ecf28b
128 changes: 68 additions & 60 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2597,15 +2597,15 @@ def meth(x): ...
with self.assertRaises(TypeError):
isinstance(C(), BadPG)

def test_protocols_isinstance_attribute_access_with_side_effects(self):
def test_protocols_isinstance_properties_and_descriptors(self):
class C:
@property
def attr(self):
raise AttributeError('no')
return 42

class CustomDescriptor:
def __get__(self, obj, objtype=None):
raise RuntimeError("NO")
return 42

class D:
attr = CustomDescriptor()
Expand All @@ -2615,9 +2615,7 @@ class D:
class E(C): ...
class F(D): ...

class WhyWouldYouDoThis:
def __getattr__(self, name):
raise RuntimeError("wut")
class Empty: ...

T = TypeVar('T')

Expand All @@ -2639,41 +2637,76 @@ def attr(self): ...
class PG1(Protocol[T]):
attr: T

for protocol_class in P, P1, PG, PG1:
@runtime_checkable
class MethodP(Protocol):
def attr(self): ...

@runtime_checkable
class MethodPG(Protocol[T]):
def attr(self) -> T: ...

for protocol_class in P, P1, PG, PG1, MethodP, MethodPG:
for klass in C, D, E, F:
with self.subTest(
klass=klass.__name__,
protocol_class=protocol_class.__name__
):
self.assertIsInstance(klass(), protocol_class)

with self.subTest(
klass="WhyWouldYouDoThis",
protocol_class=protocol_class.__name__
):
self.assertNotIsInstance(WhyWouldYouDoThis(), protocol_class)
with self.subTest(klass="Empty", protocol_class=protocol_class.__name__):
self.assertNotIsInstance(Empty(), protocol_class)

def test_protocols_isinstance___slots__(self):
# As per the consensus in https://github.com/python/typing/issues/1367,
# this is desirable behaviour
class BadP(Protocol):
@property
def attr(self): ...

class BadP1(Protocol):
attr: int

class BadPG(Protocol[T]):
@property
def attr(self): ...

class BadPG1(Protocol[T]):
attr: T

cases = (
PG[T], PG[C], PG1[T], PG1[C], MethodPG[T],
MethodPG[C], BadP, BadP1, BadPG, BadPG1
)

for obj in cases:
for klass in C, D, E, F, Empty:
with self.subTest(klass=klass.__name__, obj=obj):
with self.assertRaises(TypeError):
isinstance(klass(), obj)

def test_protocols_isinstance_not_fooled_by_custom_dir(self):
@runtime_checkable
class HasX(Protocol):
x: int

class HasNothingButSlots:
__slots__ = ("x",)
class CustomDirWithX:
x = 10
def __dir__(self):
return []

self.assertIsInstance(HasNothingButSlots(), HasX)
class CustomDirWithoutX:
def __dir__(self):
return ["x"]

def test_protocols_isinstance_properties_and_descriptors(self):
self.assertIsInstance(CustomDirWithX(), HasX)
self.assertNotIsInstance(CustomDirWithoutX(), HasX)

def test_protocols_isinstance_attribute_access_with_side_effects(self):
class C:
@property
def attr(self):
return 42
raise AttributeError('no')

class CustomDescriptor:
def __get__(self, obj, objtype=None):
return 42
raise RuntimeError("NO")

class D:
attr = CustomDescriptor()
Expand All @@ -2683,7 +2716,9 @@ class D:
class E(C): ...
class F(D): ...

class Empty: ...
class WhyWouldYouDoThis:
def __getattr__(self, name):
raise RuntimeError("wut")

T = TypeVar('T')

Expand Down Expand Up @@ -2721,50 +2756,23 @@ def attr(self) -> T: ...
):
self.assertIsInstance(klass(), protocol_class)

with self.subTest(klass="Empty", protocol_class=protocol_class.__name__):
self.assertNotIsInstance(Empty(), protocol_class)

class BadP(Protocol):
@property
def attr(self): ...

class BadP1(Protocol):
attr: int

class BadPG(Protocol[T]):
@property
def attr(self): ...

class BadPG1(Protocol[T]):
attr: T

cases = (
PG[T], PG[C], PG1[T], PG1[C], MethodPG[T],
MethodPG[C], BadP, BadP1, BadPG, BadPG1
)

for obj in cases:
for klass in C, D, E, F, Empty:
with self.subTest(klass=klass.__name__, obj=obj):
with self.assertRaises(TypeError):
isinstance(klass(), obj)
with self.subTest(
klass="WhyWouldYouDoThis",
protocol_class=protocol_class.__name__
):
self.assertNotIsInstance(WhyWouldYouDoThis(), protocol_class)

def test_protocols_isinstance_not_fooled_by_custom_dir(self):
def test_protocols_isinstance___slots__(self):
# As per the consensus in https://github.com/python/typing/issues/1367,
# this is desirable behaviour
@runtime_checkable
class HasX(Protocol):
x: int

class CustomDirWithX:
x = 10
def __dir__(self):
return []

class CustomDirWithoutX:
def __dir__(self):
return ["x"]
class HasNothingButSlots:
__slots__ = ("x",)

self.assertIsInstance(CustomDirWithX(), HasX)
self.assertNotIsInstance(CustomDirWithoutX(), HasX)
self.assertIsInstance(HasNothingButSlots(), HasX)

def test_protocols_isinstance_py36(self):
class APoint:
Expand Down