@@ -2597,15 +2597,15 @@ def meth(x): ...
25972597 with self .assertRaises (TypeError ):
25982598 isinstance (C (), BadPG )
25992599
2600- def test_protocols_isinstance_attribute_access_with_side_effects (self ):
2600+ def test_protocols_isinstance_properties_and_descriptors (self ):
26012601 class C :
26022602 @property
26032603 def attr (self ):
2604- raise AttributeError ( 'no' )
2604+ return 42
26052605
26062606 class CustomDescriptor :
26072607 def __get__ (self , obj , objtype = None ):
2608- raise RuntimeError ( "NO" )
2608+ return 42
26092609
26102610 class D :
26112611 attr = CustomDescriptor ()
@@ -2615,9 +2615,7 @@ class D:
26152615 class E (C ): ...
26162616 class F (D ): ...
26172617
2618- class WhyWouldYouDoThis :
2619- def __getattr__ (self , name ):
2620- raise RuntimeError ("wut" )
2618+ class Empty : ...
26212619
26222620 T = TypeVar ('T' )
26232621
@@ -2639,41 +2637,76 @@ def attr(self): ...
26392637 class PG1 (Protocol [T ]):
26402638 attr : T
26412639
2642- for protocol_class in P , P1 , PG , PG1 :
2640+ @runtime_checkable
2641+ class MethodP (Protocol ):
2642+ def attr (self ): ...
2643+
2644+ @runtime_checkable
2645+ class MethodPG (Protocol [T ]):
2646+ def attr (self ) -> T : ...
2647+
2648+ for protocol_class in P , P1 , PG , PG1 , MethodP , MethodPG :
26432649 for klass in C , D , E , F :
26442650 with self .subTest (
26452651 klass = klass .__name__ ,
26462652 protocol_class = protocol_class .__name__
26472653 ):
26482654 self .assertIsInstance (klass (), protocol_class )
26492655
2650- with self .subTest (
2651- klass = "WhyWouldYouDoThis" ,
2652- protocol_class = protocol_class .__name__
2653- ):
2654- self .assertNotIsInstance (WhyWouldYouDoThis (), protocol_class )
2656+ with self .subTest (klass = "Empty" , protocol_class = protocol_class .__name__ ):
2657+ self .assertNotIsInstance (Empty (), protocol_class )
26552658
2656- def test_protocols_isinstance___slots__ (self ):
2657- # As per the consensus in https://github.com/python/typing/issues/1367,
2658- # this is desirable behaviour
2659+ class BadP (Protocol ):
2660+ @property
2661+ def attr (self ): ...
2662+
2663+ class BadP1 (Protocol ):
2664+ attr : int
2665+
2666+ class BadPG (Protocol [T ]):
2667+ @property
2668+ def attr (self ): ...
2669+
2670+ class BadPG1 (Protocol [T ]):
2671+ attr : T
2672+
2673+ cases = (
2674+ PG [T ], PG [C ], PG1 [T ], PG1 [C ], MethodPG [T ],
2675+ MethodPG [C ], BadP , BadP1 , BadPG , BadPG1
2676+ )
2677+
2678+ for obj in cases :
2679+ for klass in C , D , E , F , Empty :
2680+ with self .subTest (klass = klass .__name__ , obj = obj ):
2681+ with self .assertRaises (TypeError ):
2682+ isinstance (klass (), obj )
2683+
2684+ def test_protocols_isinstance_not_fooled_by_custom_dir (self ):
26592685 @runtime_checkable
26602686 class HasX (Protocol ):
26612687 x : int
26622688
2663- class HasNothingButSlots :
2664- __slots__ = ("x" ,)
2689+ class CustomDirWithX :
2690+ x = 10
2691+ def __dir__ (self ):
2692+ return []
26652693
2666- self .assertIsInstance (HasNothingButSlots (), HasX )
2694+ class CustomDirWithoutX :
2695+ def __dir__ (self ):
2696+ return ["x" ]
26672697
2668- def test_protocols_isinstance_properties_and_descriptors (self ):
2698+ self .assertIsInstance (CustomDirWithX (), HasX )
2699+ self .assertNotIsInstance (CustomDirWithoutX (), HasX )
2700+
2701+ def test_protocols_isinstance_attribute_access_with_side_effects (self ):
26692702 class C :
26702703 @property
26712704 def attr (self ):
2672- return 42
2705+ raise AttributeError ( 'no' )
26732706
26742707 class CustomDescriptor :
26752708 def __get__ (self , obj , objtype = None ):
2676- return 42
2709+ raise RuntimeError ( "NO" )
26772710
26782711 class D :
26792712 attr = CustomDescriptor ()
@@ -2683,7 +2716,9 @@ class D:
26832716 class E (C ): ...
26842717 class F (D ): ...
26852718
2686- class Empty : ...
2719+ class WhyWouldYouDoThis :
2720+ def __getattr__ (self , name ):
2721+ raise RuntimeError ("wut" )
26872722
26882723 T = TypeVar ('T' )
26892724
@@ -2721,50 +2756,23 @@ def attr(self) -> T: ...
27212756 ):
27222757 self .assertIsInstance (klass (), protocol_class )
27232758
2724- with self .subTest (klass = "Empty" , protocol_class = protocol_class .__name__ ):
2725- self .assertNotIsInstance (Empty (), protocol_class )
2726-
2727- class BadP (Protocol ):
2728- @property
2729- def attr (self ): ...
2730-
2731- class BadP1 (Protocol ):
2732- attr : int
2733-
2734- class BadPG (Protocol [T ]):
2735- @property
2736- def attr (self ): ...
2737-
2738- class BadPG1 (Protocol [T ]):
2739- attr : T
2740-
2741- cases = (
2742- PG [T ], PG [C ], PG1 [T ], PG1 [C ], MethodPG [T ],
2743- MethodPG [C ], BadP , BadP1 , BadPG , BadPG1
2744- )
2745-
2746- for obj in cases :
2747- for klass in C , D , E , F , Empty :
2748- with self .subTest (klass = klass .__name__ , obj = obj ):
2749- with self .assertRaises (TypeError ):
2750- isinstance (klass (), obj )
2759+ with self .subTest (
2760+ klass = "WhyWouldYouDoThis" ,
2761+ protocol_class = protocol_class .__name__
2762+ ):
2763+ self .assertNotIsInstance (WhyWouldYouDoThis (), protocol_class )
27512764
2752- def test_protocols_isinstance_not_fooled_by_custom_dir (self ):
2765+ def test_protocols_isinstance___slots__ (self ):
2766+ # As per the consensus in https://github.com/python/typing/issues/1367,
2767+ # this is desirable behaviour
27532768 @runtime_checkable
27542769 class HasX (Protocol ):
27552770 x : int
27562771
2757- class CustomDirWithX :
2758- x = 10
2759- def __dir__ (self ):
2760- return []
2761-
2762- class CustomDirWithoutX :
2763- def __dir__ (self ):
2764- return ["x" ]
2772+ class HasNothingButSlots :
2773+ __slots__ = ("x" ,)
27652774
2766- self .assertIsInstance (CustomDirWithX (), HasX )
2767- self .assertNotIsInstance (CustomDirWithoutX (), HasX )
2775+ self .assertIsInstance (HasNothingButSlots (), HasX )
27682776
27692777 def test_protocols_isinstance_py36 (self ):
27702778 class APoint :
0 commit comments