(
stub: nodes.TypeInfo,
runtime: MaybeMissing[type[Any]],
object_path: list[str],
*,
is_alias_target: bool = False,
)
| 643 | |
| 644 | @verify.register(nodes.TypeInfo) |
| 645 | def verify_typeinfo( |
| 646 | stub: nodes.TypeInfo, |
| 647 | runtime: MaybeMissing[type[Any]], |
| 648 | object_path: list[str], |
| 649 | *, |
| 650 | is_alias_target: bool = False, |
| 651 | ) -> Iterator[Error]: |
| 652 | if stub.is_type_check_only and not is_alias_target: |
| 653 | # This type only exists in stubs, we only check that the runtime part |
| 654 | # is missing. Other checks are not required. |
| 655 | if not isinstance(runtime, Missing): |
| 656 | yield Error( |
| 657 | object_path, |
| 658 | 'is marked as "@type_check_only", but also exists at runtime', |
| 659 | stub, |
| 660 | runtime, |
| 661 | stub_desc=repr(stub), |
| 662 | ) |
| 663 | return |
| 664 | |
| 665 | if isinstance(runtime, Missing): |
| 666 | msg = "is not present at runtime" |
| 667 | if is_probably_private(stub.name): |
| 668 | msg += '. Maybe mark it as "@type_check_only"?' |
| 669 | yield Error(object_path, msg, stub, runtime, stub_desc=repr(stub)) |
| 670 | return |
| 671 | if not isinstance(runtime, type): |
| 672 | # Yes, some runtime objects can be not types, no way to tell mypy about that. |
| 673 | yield Error(object_path, "is not a type", stub, runtime, stub_desc=repr(stub)) # type: ignore[unreachable] |
| 674 | return |
| 675 | |
| 676 | yield from _verify_final(stub, runtime, object_path) |
| 677 | yield from _verify_disjoint_base(stub, runtime, object_path) |
| 678 | is_runtime_typeddict = stub.typeddict_type is not None and is_typeddict(runtime) |
| 679 | yield from _verify_metaclass( |
| 680 | stub, runtime, object_path, is_runtime_typeddict=is_runtime_typeddict |
| 681 | ) |
| 682 | |
| 683 | # Check everything already defined on the stub class itself (i.e. not inherited) |
| 684 | # |
| 685 | # Filter out non-identifier names, as these are (hopefully always?) whacky/fictional things |
| 686 | # (like __mypy-replace or __mypy-post_init, etc.) that don't exist at runtime, |
| 687 | # and exist purely for internal mypy reasons |
| 688 | to_check = {name for name in stub.names if name.isidentifier()} |
| 689 | # Check all public things on the runtime class |
| 690 | to_check.update( |
| 691 | m for m in vars(runtime) if not is_probably_private(m) and m not in IGNORABLE_CLASS_DUNDERS |
| 692 | ) |
| 693 | # Special-case the __init__ method for Protocols and the __new__ method for TypedDicts |
| 694 | # |
| 695 | # TODO: On Python <3.11, __init__ methods on Protocol classes |
| 696 | # are silently discarded and replaced. |
| 697 | # However, this is not the case on Python 3.11+. |
| 698 | # Ideally, we'd figure out a good way of validating Protocol __init__ methods on 3.11+. |
| 699 | if stub.is_protocol: |
| 700 | to_check.discard("__init__") |
| 701 | if is_runtime_typeddict: |
| 702 | to_check.discard("__new__") |
no test coverage detected
searching dependent graphs…