@@ -1137,20 +1137,23 @@ def my_static_method(cls, x: int, y: str) -> None:
11371137 def my_class_method (x : int , y : str ) -> None :
11381138 pass
11391139
1140- for _ in range (2 ): # Makes sure that the cache is also exercised
1141- check_type (Foo (), MyProtocol )
1140+ check_type (Foo (), MyProtocol )
11421141
1143- def test_missing_member (self ) -> None :
1142+ @pytest .mark .parametrize ("has_member" , [True , False ])
1143+ def test_member_checks (self , has_member : bool ) -> None :
11441144 class MyProtocol (Protocol ):
11451145 member : int
11461146
11471147 class Foo :
1148- pass
1148+ def __init__ (self , member : int ):
1149+ if member :
1150+ self .member = member
11491151
1150- obj = Foo ()
1151- for _ in range (2 ): # Makes sure that the cache is also exercised
1152- pytest .raises (TypeCheckError , check_type , obj , MyProtocol ).match (
1153- f"^{ qualified_name (obj )} is not compatible with the "
1152+ if has_member :
1153+ check_type (Foo (1 ), MyProtocol )
1154+ else :
1155+ pytest .raises (TypeCheckError , check_type , Foo (0 ), MyProtocol ).match (
1156+ f"^{ qualified_name (Foo )} is not compatible with the "
11541157 f"{ MyProtocol .__qualname__ } protocol because it has no attribute named "
11551158 f"'member'"
11561159 )
@@ -1163,12 +1166,11 @@ def meth(self) -> None:
11631166 class Foo :
11641167 pass
11651168
1166- for _ in range (2 ): # Makes sure that the cache is also exercised
1167- pytest .raises (TypeCheckError , check_type , Foo (), MyProtocol ).match (
1168- f"^{ qualified_name (Foo )} is not compatible with the "
1169- f"{ MyProtocol .__qualname__ } protocol because it has no method named "
1170- f"'meth'"
1171- )
1169+ pytest .raises (TypeCheckError , check_type , Foo (), MyProtocol ).match (
1170+ f"^{ qualified_name (Foo )} is not compatible with the "
1171+ f"{ MyProtocol .__qualname__ } protocol because it has no method named "
1172+ f"'meth'"
1173+ )
11721174
11731175 def test_too_many_posargs (self ) -> None :
11741176 class MyProtocol (Protocol ):
@@ -1179,13 +1181,11 @@ class Foo:
11791181 def meth (self , x : str ) -> None :
11801182 pass
11811183
1182- obj = Foo ()
1183- for _ in range (2 ): # Makes sure that the cache is also exercised
1184- pytest .raises (TypeCheckError , check_type , Foo (), MyProtocol ).match (
1185- f"^{ qualified_name (obj )} is not compatible with the "
1186- f"{ MyProtocol .__qualname__ } protocol because its 'meth' method has too "
1187- f"many mandatory positional arguments"
1188- )
1184+ pytest .raises (TypeCheckError , check_type , Foo (), MyProtocol ).match (
1185+ f"^{ qualified_name (Foo )} is not compatible with the "
1186+ f"{ MyProtocol .__qualname__ } protocol because its 'meth' method has too "
1187+ f"many mandatory positional arguments"
1188+ )
11891189
11901190 def test_wrong_posarg_name (self ) -> None :
11911191 class MyProtocol (Protocol ):
@@ -1196,13 +1196,11 @@ class Foo:
11961196 def meth (self , y : str ) -> None :
11971197 pass
11981198
1199- obj = Foo ()
1200- for _ in range (2 ): # Makes sure that the cache is also exercised
1201- pytest .raises (TypeCheckError , check_type , Foo (), MyProtocol ).match (
1202- rf"^{ qualified_name (obj )} is not compatible with the "
1203- rf"{ MyProtocol .__qualname__ } protocol because its 'meth' method has a "
1204- rf"positional argument \(y\) that should be named 'x' at this position"
1205- )
1199+ pytest .raises (TypeCheckError , check_type , Foo (), MyProtocol ).match (
1200+ rf"^{ qualified_name (Foo )} is not compatible with the "
1201+ rf"{ MyProtocol .__qualname__ } protocol because its 'meth' method has a "
1202+ rf"positional argument \(y\) that should be named 'x' at this position"
1203+ )
12061204
12071205 def test_too_few_posargs (self ) -> None :
12081206 class MyProtocol (Protocol ):
@@ -1213,13 +1211,11 @@ class Foo:
12131211 def meth (self ) -> None :
12141212 pass
12151213
1216- obj = Foo ()
1217- for _ in range (2 ): # Makes sure that the cache is also exercised
1218- pytest .raises (TypeCheckError , check_type , Foo (), MyProtocol ).match (
1219- f"^{ qualified_name (obj )} is not compatible with the "
1220- f"{ MyProtocol .__qualname__ } protocol because its 'meth' method has too "
1221- f"few positional arguments"
1222- )
1214+ pytest .raises (TypeCheckError , check_type , Foo (), MyProtocol ).match (
1215+ f"^{ qualified_name (Foo )} is not compatible with the "
1216+ f"{ MyProtocol .__qualname__ } protocol because its 'meth' method has too "
1217+ f"few positional arguments"
1218+ )
12231219
12241220 def test_no_varargs (self ) -> None :
12251221 class MyProtocol (Protocol ):
@@ -1230,13 +1226,11 @@ class Foo:
12301226 def meth (self ) -> None :
12311227 pass
12321228
1233- obj = Foo ()
1234- for _ in range (2 ): # Makes sure that the cache is also exercised
1235- pytest .raises (TypeCheckError , check_type , Foo (), MyProtocol ).match (
1236- f"^{ qualified_name (obj )} is not compatible with the "
1237- f"{ MyProtocol .__qualname__ } protocol because its 'meth' method should "
1238- f"accept variable positional arguments but doesn't"
1239- )
1229+ pytest .raises (TypeCheckError , check_type , Foo (), MyProtocol ).match (
1230+ f"^{ qualified_name (Foo )} is not compatible with the "
1231+ f"{ MyProtocol .__qualname__ } protocol because its 'meth' method should "
1232+ f"accept variable positional arguments but doesn't"
1233+ )
12401234
12411235 def test_no_kwargs (self ) -> None :
12421236 class MyProtocol (Protocol ):
@@ -1247,13 +1241,11 @@ class Foo:
12471241 def meth (self ) -> None :
12481242 pass
12491243
1250- obj = Foo ()
1251- for _ in range (2 ): # Makes sure that the cache is also exercised
1252- pytest .raises (TypeCheckError , check_type , Foo (), MyProtocol ).match (
1253- f"^{ qualified_name (obj )} is not compatible with the "
1254- f"{ MyProtocol .__qualname__ } protocol because its 'meth' method should "
1255- f"accept variable keyword arguments but doesn't"
1256- )
1244+ pytest .raises (TypeCheckError , check_type , Foo (), MyProtocol ).match (
1245+ f"^{ qualified_name (Foo )} is not compatible with the "
1246+ f"{ MyProtocol .__qualname__ } protocol because its 'meth' method should "
1247+ f"accept variable keyword arguments but doesn't"
1248+ )
12571249
12581250 def test_missing_kwarg (self ) -> None :
12591251 class MyProtocol (Protocol ):
@@ -1264,13 +1256,11 @@ class Foo:
12641256 def meth (self ) -> None :
12651257 pass
12661258
1267- obj = Foo ()
1268- for _ in range (2 ): # Makes sure that the cache is also exercised
1269- pytest .raises (TypeCheckError , check_type , Foo (), MyProtocol ).match (
1270- f"^{ qualified_name (obj )} is not compatible with the "
1271- f"{ MyProtocol .__qualname__ } protocol because its 'meth' method is "
1272- f"missing keyword-only arguments: x"
1273- )
1259+ pytest .raises (TypeCheckError , check_type , Foo (), MyProtocol ).match (
1260+ f"^{ qualified_name (Foo )} is not compatible with the "
1261+ f"{ MyProtocol .__qualname__ } protocol because its 'meth' method is "
1262+ f"missing keyword-only arguments: x"
1263+ )
12741264
12751265 def test_extra_kwarg (self ) -> None :
12761266 class MyProtocol (Protocol ):
@@ -1281,13 +1271,43 @@ class Foo:
12811271 def meth (self , * , x : str ) -> None :
12821272 pass
12831273
1284- obj = Foo ()
1285- for _ in range (2 ): # Makes sure that the cache is also exercised
1286- pytest .raises (TypeCheckError , check_type , Foo (), MyProtocol ).match (
1287- f"^{ qualified_name (obj )} is not compatible with the "
1288- f"{ MyProtocol .__qualname__ } protocol because its 'meth' method has "
1289- f"mandatory keyword-only arguments not present in the protocol: x"
1290- )
1274+ pytest .raises (TypeCheckError , check_type , Foo (), MyProtocol ).match (
1275+ f"^{ qualified_name (Foo )} is not compatible with the "
1276+ f"{ MyProtocol .__qualname__ } protocol because its 'meth' method has "
1277+ f"mandatory keyword-only arguments not present in the protocol: x"
1278+ )
1279+
1280+ def test_instance_staticmethod_mismatch (self ) -> None :
1281+ class MyProtocol (Protocol ):
1282+ @staticmethod
1283+ def meth () -> None :
1284+ pass
1285+
1286+ class Foo :
1287+ def meth (self ) -> None :
1288+ pass
1289+
1290+ pytest .raises (TypeCheckError , check_type , Foo (), MyProtocol ).match (
1291+ f"^{ qualified_name (Foo )} is not compatible with the "
1292+ f"{ MyProtocol .__qualname__ } protocol because its 'meth' method should "
1293+ f"be a static method but it's an instance method"
1294+ )
1295+
1296+ def test_instance_classmethod_mismatch (self ) -> None :
1297+ class MyProtocol (Protocol ):
1298+ @classmethod
1299+ def meth (cls ) -> None :
1300+ pass
1301+
1302+ class Foo :
1303+ def meth (self ) -> None :
1304+ pass
1305+
1306+ pytest .raises (TypeCheckError , check_type , Foo (), MyProtocol ).match (
1307+ f"^{ qualified_name (Foo )} is not compatible with the "
1308+ f"{ MyProtocol .__qualname__ } protocol because its 'meth' method should "
1309+ f"be a class method but it's an instance method"
1310+ )
12911311
12921312
12931313class TestRecursiveType :
0 commit comments