|
26 | 26 | from functools import singledispatch
|
27 | 27 | from pathlib import Path
|
28 | 28 | from typing import Any, Generic, Iterator, TypeVar, Union
|
29 |
| -from typing_extensions import get_origin |
| 29 | +from typing_extensions import get_origin, is_typeddict |
30 | 30 |
|
31 | 31 | import mypy.build
|
32 | 32 | import mypy.modulefinder
|
@@ -436,12 +436,12 @@ class SubClass(runtime): # type: ignore[misc]
|
436 | 436 |
|
437 | 437 |
|
438 | 438 | def _verify_metaclass(
|
439 |
| - stub: nodes.TypeInfo, runtime: type[Any], object_path: list[str] |
| 439 | + stub: nodes.TypeInfo, runtime: type[Any], object_path: list[str], *, is_runtime_typeddict: bool |
440 | 440 | ) -> Iterator[Error]:
|
441 | 441 | # We exclude protocols, because of how complex their implementation is in different versions of
|
442 |
| - # python. Enums are also hard, ignoring. |
| 442 | + # python. Enums are also hard, as are runtime TypedDicts; ignoring. |
443 | 443 | # TODO: check that metaclasses are identical?
|
444 |
| - if not stub.is_protocol and not stub.is_enum: |
| 444 | + if not stub.is_protocol and not stub.is_enum and not is_runtime_typeddict: |
445 | 445 | runtime_metaclass = type(runtime)
|
446 | 446 | if runtime_metaclass is not type and stub.metaclass_type is None:
|
447 | 447 | # This means that runtime has a custom metaclass, but a stub does not.
|
@@ -485,22 +485,27 @@ def verify_typeinfo(
|
485 | 485 | return
|
486 | 486 |
|
487 | 487 | yield from _verify_final(stub, runtime, object_path)
|
488 |
| - yield from _verify_metaclass(stub, runtime, object_path) |
| 488 | + is_runtime_typeddict = stub.typeddict_type is not None and is_typeddict(runtime) |
| 489 | + yield from _verify_metaclass( |
| 490 | + stub, runtime, object_path, is_runtime_typeddict=is_runtime_typeddict |
| 491 | + ) |
489 | 492 |
|
490 | 493 | # Check everything already defined on the stub class itself (i.e. not inherited)
|
491 | 494 | to_check = set(stub.names)
|
492 | 495 | # Check all public things on the runtime class
|
493 | 496 | to_check.update(
|
494 | 497 | m for m in vars(runtime) if not is_probably_private(m) and m not in IGNORABLE_CLASS_DUNDERS
|
495 | 498 | )
|
496 |
| - # Special-case the __init__ method for Protocols |
| 499 | + # Special-case the __init__ method for Protocols and the __new__ method for TypedDicts |
497 | 500 | #
|
498 | 501 | # TODO: On Python <3.11, __init__ methods on Protocol classes
|
499 | 502 | # are silently discarded and replaced.
|
500 | 503 | # However, this is not the case on Python 3.11+.
|
501 | 504 | # Ideally, we'd figure out a good way of validating Protocol __init__ methods on 3.11+.
|
502 | 505 | if stub.is_protocol:
|
503 | 506 | to_check.discard("__init__")
|
| 507 | + if is_runtime_typeddict: |
| 508 | + to_check.discard("__new__") |
504 | 509 |
|
505 | 510 | for entry in sorted(to_check):
|
506 | 511 | mangled_entry = entry
|
|
0 commit comments