@@ -349,17 +349,9 @@ def _belongs_to_runtime(r: types.ModuleType, attr: str) -> bool:
349
349
yield from verify (stub_entry , runtime_entry , object_path + [entry ])
350
350
351
351
352
- @verify .register (nodes .TypeInfo )
353
- def verify_typeinfo (
354
- stub : nodes .TypeInfo , runtime : MaybeMissing [type [Any ]], object_path : list [str ]
352
+ def _verify_final (
353
+ stub : nodes .TypeInfo , runtime : type [Any ], object_path : list [str ]
355
354
) -> Iterator [Error ]:
356
- if isinstance (runtime , Missing ):
357
- yield Error (object_path , "is not present at runtime" , stub , runtime , stub_desc = repr (stub ))
358
- return
359
- if not isinstance (runtime , type ):
360
- yield Error (object_path , "is not a type" , stub , runtime , stub_desc = repr (stub ))
361
- return
362
-
363
355
try :
364
356
365
357
class SubClass (runtime ): # type: ignore
@@ -380,6 +372,59 @@ class SubClass(runtime): # type: ignore
380
372
# Examples: ctypes.Array, ctypes._SimpleCData
381
373
pass
382
374
375
+
376
+ def _verify_metaclass (
377
+ stub : nodes .TypeInfo , runtime : type [Any ], object_path : list [str ]
378
+ ) -> Iterator [Error ]:
379
+ # We exclude protocols, because of how complex their implementation is in different versions of
380
+ # python. Enums are also hard, ignoring.
381
+ # TODO: check that metaclasses are identical?
382
+ if not stub .is_protocol and not stub .is_enum :
383
+ runtime_metaclass = type (runtime )
384
+ if runtime_metaclass is not type and stub .metaclass_type is None :
385
+ # This means that runtime has a custom metaclass, but a stub does not.
386
+ yield Error (
387
+ object_path ,
388
+ "is inconsistent, metaclass differs" ,
389
+ stub ,
390
+ runtime ,
391
+ stub_desc = "N/A" ,
392
+ runtime_desc = f"{ runtime_metaclass } " ,
393
+ )
394
+ elif (
395
+ runtime_metaclass is type
396
+ and stub .metaclass_type is not None
397
+ # We ignore extra `ABCMeta` metaclass on stubs, this might be typing hack.
398
+ # We also ignore `builtins.type` metaclass as an implementation detail in mypy.
399
+ and not mypy .types .is_named_instance (
400
+ stub .metaclass_type , ("abc.ABCMeta" , "builtins.type" )
401
+ )
402
+ ):
403
+ # This means that our stub has a metaclass that is not present at runtime.
404
+ yield Error (
405
+ object_path ,
406
+ "metaclass mismatch" ,
407
+ stub ,
408
+ runtime ,
409
+ stub_desc = f"{ stub .metaclass_type .type .fullname } " ,
410
+ runtime_desc = "N/A" ,
411
+ )
412
+
413
+
414
+ @verify .register (nodes .TypeInfo )
415
+ def verify_typeinfo (
416
+ stub : nodes .TypeInfo , runtime : MaybeMissing [type [Any ]], object_path : list [str ]
417
+ ) -> Iterator [Error ]:
418
+ if isinstance (runtime , Missing ):
419
+ yield Error (object_path , "is not present at runtime" , stub , runtime , stub_desc = repr (stub ))
420
+ return
421
+ if not isinstance (runtime , type ):
422
+ yield Error (object_path , "is not a type" , stub , runtime , stub_desc = repr (stub ))
423
+ return
424
+
425
+ yield from _verify_final (stub , runtime , object_path )
426
+ yield from _verify_metaclass (stub , runtime , object_path )
427
+
383
428
# Check everything already defined on the stub class itself (i.e. not inherited)
384
429
to_check = set (stub .names )
385
430
# Check all public things on the runtime class
0 commit comments