@@ -1658,7 +1658,15 @@ def attr(self): ...
1658
1658
class PG1 (Protocol [T ]):
1659
1659
attr : T
1660
1660
1661
- for protocol_class in P , P1 , PG , PG1 :
1661
+ @runtime_checkable
1662
+ class MethodP (Protocol ):
1663
+ def attr (self ): ...
1664
+
1665
+ @runtime_checkable
1666
+ class MethodPG (Protocol [T ]):
1667
+ def attr (self ) -> T : ...
1668
+
1669
+ for protocol_class in P , P1 , PG , PG1 , MethodP , MethodPG :
1662
1670
for klass in C , D , E , F :
1663
1671
with self .subTest (
1664
1672
klass = klass .__name__ ,
@@ -1683,7 +1691,12 @@ def attr(self): ...
1683
1691
class BadPG1 (Protocol [T ]):
1684
1692
attr : T
1685
1693
1686
- for obj in PG [T ], PG [C ], PG1 [T ], PG1 [C ], BadP , BadP1 , BadPG , BadPG1 :
1694
+ cases = (
1695
+ PG [T ], PG [C ], PG1 [T ], PG1 [C ], MethodPG [T ],
1696
+ MethodPG [C ], BadP , BadP1 , BadPG , BadPG1
1697
+ )
1698
+
1699
+ for obj in cases :
1687
1700
for klass in C , D , E , F , Empty :
1688
1701
with self .subTest (klass = klass .__name__ , obj = obj ):
1689
1702
with self .assertRaises (TypeError ):
@@ -1706,6 +1719,82 @@ def __dir__(self):
1706
1719
self .assertIsInstance (CustomDirWithX (), HasX )
1707
1720
self .assertNotIsInstance (CustomDirWithoutX (), HasX )
1708
1721
1722
+ def test_protocols_isinstance_attribute_access_with_side_effects (self ):
1723
+ class C :
1724
+ @property
1725
+ def attr (self ):
1726
+ raise AttributeError ('no' )
1727
+
1728
+ class CustomDescriptor :
1729
+ def __get__ (self , obj , objtype = None ):
1730
+ raise RuntimeError ("NO" )
1731
+
1732
+ class D :
1733
+ attr = CustomDescriptor ()
1734
+
1735
+ # Check that properties set on superclasses
1736
+ # are still found by the isinstance() logic
1737
+ class E (C ): ...
1738
+ class F (D ): ...
1739
+
1740
+ class WhyWouldYouDoThis :
1741
+ def __getattr__ (self , name ):
1742
+ raise RuntimeError ("wut" )
1743
+
1744
+ T = TypeVar ('T' )
1745
+
1746
+ @runtime_checkable
1747
+ class P (Protocol ):
1748
+ @property
1749
+ def attr (self ): ...
1750
+
1751
+ @runtime_checkable
1752
+ class P1 (Protocol ):
1753
+ attr : int
1754
+
1755
+ @runtime_checkable
1756
+ class PG (Protocol [T ]):
1757
+ @property
1758
+ def attr (self ): ...
1759
+
1760
+ @runtime_checkable
1761
+ class PG1 (Protocol [T ]):
1762
+ attr : T
1763
+
1764
+ @runtime_checkable
1765
+ class MethodP (Protocol ):
1766
+ def attr (self ): ...
1767
+
1768
+ @runtime_checkable
1769
+ class MethodPG (Protocol [T ]):
1770
+ def attr (self ) -> T : ...
1771
+
1772
+ for protocol_class in P , P1 , PG , PG1 , MethodP , MethodPG :
1773
+ for klass in C , D , E , F :
1774
+ with self .subTest (
1775
+ klass = klass .__name__ ,
1776
+ protocol_class = protocol_class .__name__
1777
+ ):
1778
+ self .assertIsInstance (klass (), protocol_class )
1779
+
1780
+ with self .subTest (
1781
+ klass = "WhyWouldYouDoThis" ,
1782
+ protocol_class = protocol_class .__name__
1783
+ ):
1784
+ self .assertNotIsInstance (WhyWouldYouDoThis (), protocol_class )
1785
+
1786
+ def test_protocols_isinstance___slots__ (self ):
1787
+ # As per the consensus in https://github.com/python/typing/issues/1367,
1788
+ # this is desirable behaviour
1789
+ @runtime_checkable
1790
+ class HasX (Protocol ):
1791
+ x : int
1792
+
1793
+ class HasNothingButSlots :
1794
+ __slots__ = ("x" ,)
1795
+
1796
+ self .assertIsInstance (HasNothingButSlots (), HasX )
1797
+
1709
1798
def test_protocols_isinstance_py36 (self ):
1710
1799
class APoint :
1711
1800
def __init__ (self , x , y , label ):
0 commit comments