|
9 | 9 | import logging
|
10 | 10 | import os.path
|
11 | 11 | import re
|
| 12 | +import sys |
12 | 13 | import threading
|
13 | 14 | import types
|
14 | 15 | import typing
|
@@ -668,13 +669,30 @@ class _FromDict(Protocol):
|
668 | 669 | def from_dict(cls, raw: dict):
|
669 | 670 | pass
|
670 | 671 |
|
| 672 | + # Internal utility for evaluating forward references; mypy handles version checks, but only top-level. |
| 673 | + if sys.version_info >= (3, 12, 4): |
| 674 | + # Since Python 3.12.4, `ForwardRef._evaluate` requires recursive_guard as a keyword, and has an additional |
| 675 | + # parameter for type information. |
| 676 | + @staticmethod |
| 677 | + def _evaluate_forward_ref(type_ref: typing.ForwardRef) -> type: |
| 678 | + """Evaluate a forward reference to a type.""" |
| 679 | + # pylint: disable-next=protected-access |
| 680 | + return type_ref._evaluate(globals(), locals(), (), recursive_guard=frozenset()) # type: ignore[arg-type,misc,return-value] |
| 681 | + else: |
| 682 | + # Older versions of Python do |
| 683 | + @staticmethod |
| 684 | + def _evaluate_forward_ref(type_ref: typing.ForwardRef) -> type: |
| 685 | + """Evaluate a forward reference to a type.""" |
| 686 | + # pylint: disable-next=protected-access |
| 687 | + return type_ref._evaluate(globals(), locals(), recursive_guard=frozenset()) # type: ignore[return-value] |
| 688 | + |
671 | 689 | @classmethod
|
672 | 690 | def _unmarshal(cls, inst: Any, path: list[str], type_ref: type[T]) -> T | None:
|
673 | 691 | """The `_unmarshal` method is a private method that is used to deserialize a dictionary to an object of type
|
674 | 692 | `type_ref`. This method is called by the `load` method."""
|
675 | 693 | # Forward-references aren't always resolved, so we need to handle them. (Assumes reference is visible here.)
|
676 | 694 | if isinstance(type_ref, typing.ForwardRef):
|
677 |
| - type_ref = type_ref._evaluate(globals(), locals(), frozenset()) # pylint: disable=protected-access |
| 695 | + type_ref = cls._evaluate_forward_ref(type_ref) |
678 | 696 | if dataclasses.is_dataclass(type_ref):
|
679 | 697 | return cls._unmarshal_dataclass(inst, path, type_ref)
|
680 | 698 | if isinstance(type_ref, enum.EnumMeta):
|
|
0 commit comments