@@ -2760,6 +2760,132 @@ def test_patma_255(self):
27602760 self .assertEqual (y , 1 )
27612761 self .assertIs (z , x )
27622762
2763+ def test_patma_runtime_checkable_protocol (self ):
2764+ # Runtime-checkable protocol
2765+ from typing import Protocol , runtime_checkable
2766+
2767+ @runtime_checkable
2768+ class P (Protocol ):
2769+ x : int
2770+ y : int
2771+
2772+ class A :
2773+ def __init__ (self , x : int , y : int ):
2774+ self .x = x
2775+ self .y = y
2776+
2777+ class B (A ): ...
2778+
2779+ for cls in (A , B ):
2780+ with self .subTest (cls = cls .__name__ ):
2781+ inst = cls (1 , 2 )
2782+ w = 0
2783+ match inst :
2784+ case P () as p :
2785+ self .assertIsInstance (p , cls )
2786+ self .assertEqual (p .x , 1 )
2787+ self .assertEqual (p .y , 2 )
2788+ w = 1
2789+ self .assertEqual (w , 1 )
2790+
2791+ q = 0
2792+ match inst :
2793+ case P (x = x , y = y ):
2794+ self .assertEqual (x , 1 )
2795+ self .assertEqual (y , 2 )
2796+ q = 1
2797+ self .assertEqual (q , 1 )
2798+
2799+
2800+ def test_patma_generic_protocol (self ):
2801+ # Runtime-checkable generic protocol
2802+ from typing import Generic , TypeVar , Protocol , runtime_checkable
2803+
2804+ T = TypeVar ('T' ) # not using PEP695 to be able to backport changes
2805+
2806+ @runtime_checkable
2807+ class P (Protocol [T ]):
2808+ a : T
2809+ b : T
2810+
2811+ class A :
2812+ def __init__ (self , x : int , y : int ):
2813+ self .x = x
2814+ self .y = y
2815+
2816+ class G (Generic [T ]):
2817+ def __init__ (self , x : T , y : T ):
2818+ self .x = x
2819+ self .y = y
2820+
2821+ for cls in (A , G ):
2822+ with self .subTest (cls = cls .__name__ ):
2823+ inst = cls (1 , 2 )
2824+ w = 0
2825+ match inst :
2826+ case P ():
2827+ w = 1
2828+ self .assertEqual (w , 0 )
2829+
2830+ def test_patma_protocol_with_match_args (self ):
2831+ # Runtime-checkable protocol with `__match_args__`
2832+ from typing import Protocol , runtime_checkable
2833+
2834+ # Used to fail before
2835+ # https://github.com/python/cpython/issues/110682
2836+ @runtime_checkable
2837+ class P (Protocol ):
2838+ __match_args__ = ('x' , 'y' )
2839+ x : int
2840+ y : int
2841+
2842+ class A :
2843+ def __init__ (self , x : int , y : int ):
2844+ self .x = x
2845+ self .y = y
2846+
2847+ class B (A ): ...
2848+
2849+ for cls in (A , B ):
2850+ with self .subTest (cls = cls .__name__ ):
2851+ inst = cls (1 , 2 )
2852+ w = 0
2853+ match inst :
2854+ case P () as p :
2855+ self .assertIsInstance (p , cls )
2856+ self .assertEqual (p .x , 1 )
2857+ self .assertEqual (p .y , 2 )
2858+ w = 1
2859+ self .assertEqual (w , 1 )
2860+
2861+ q = 0
2862+ match inst :
2863+ case P (x = x , y = y ):
2864+ self .assertEqual (x , 1 )
2865+ self .assertEqual (y , 2 )
2866+ q = 1
2867+ self .assertEqual (q , 1 )
2868+
2869+ j = 0
2870+ match inst :
2871+ case P (x = 1 , y = 2 ):
2872+ j = 1
2873+ self .assertEqual (j , 1 )
2874+
2875+ g = 0
2876+ match inst :
2877+ case P (x , y ):
2878+ self .assertEqual (x , 1 )
2879+ self .assertEqual (y , 2 )
2880+ g = 1
2881+ self .assertEqual (g , 1 )
2882+
2883+ h = 0
2884+ match inst :
2885+ case P (1 , 2 ):
2886+ h = 1
2887+ self .assertEqual (h , 1 )
2888+
27632889
27642890class TestSyntaxErrors (unittest .TestCase ):
27652891
@@ -3198,6 +3324,35 @@ def test_class_pattern_not_type(self):
31983324 w = 0
31993325 self .assertIsNone (w )
32003326
3327+ def test_regular_protocol (self ):
3328+ from typing import Protocol
3329+ class P (Protocol ): ...
3330+ msg = (
3331+ 'Instance and class checks can only be used '
3332+ 'with @runtime_checkable protocols'
3333+ )
3334+ w = None
3335+ with self .assertRaisesRegex (TypeError , msg ):
3336+ match 1 :
3337+ case P ():
3338+ w = 0
3339+ self .assertIsNone (w )
3340+
3341+ def test_positional_patterns_with_regular_protocol (self ):
3342+ from typing import Protocol
3343+ class P (Protocol ):
3344+ x : int # no `__match_args__`
3345+ y : int
3346+ class A :
3347+ x = 1
3348+ y = 2
3349+ w = None
3350+ with self .assertRaises (TypeError ):
3351+ match A ():
3352+ case P (x , y ):
3353+ w = 0
3354+ self .assertIsNone (w )
3355+
32013356
32023357class TestValueErrors (unittest .TestCase ):
32033358
0 commit comments