diff options
author | wyfo <joperez@hotmail.fr> | 2020-07-22 19:47:28 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-22 19:47:28 (GMT) |
commit | 653f420b53a3aa87316cef59de8d3f5d9e11deb4 (patch) | |
tree | 4ec1efe11e2698f2c56790f013c1cf1ae80c677b /Lib/typing.py | |
parent | bf2f76ec0976c09de79c8827764f30e3b6fba776 (diff) | |
download | cpython-653f420b53a3aa87316cef59de8d3f5d9e11deb4.zip cpython-653f420b53a3aa87316cef59de8d3f5d9e11deb4.tar.gz cpython-653f420b53a3aa87316cef59de8d3f5d9e11deb4.tar.bz2 |
bpo-41341: Recursive evaluation of ForwardRef in get_type_hints (#21553)
The issue raised by recursive evaluation is infinite recursion with
recursive types. In that case, only the first recursive ForwardRef is
evaluated.
Diffstat (limited to 'Lib/typing.py')
-rw-r--r-- | Lib/typing.py | 20 |
1 files changed, 14 insertions, 6 deletions
diff --git a/Lib/typing.py b/Lib/typing.py index fd657ca..5da032b 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -244,14 +244,16 @@ def _tp_cache(func): return inner -def _eval_type(t, globalns, localns): +def _eval_type(t, globalns, localns, recursive_guard=frozenset()): """Evaluate all forward reverences in the given type t. For use of globalns and localns see the docstring for get_type_hints(). + recursive_guard is used to prevent prevent infinite recursion + with recursive ForwardRef. """ if isinstance(t, ForwardRef): - return t._evaluate(globalns, localns) + return t._evaluate(globalns, localns, recursive_guard) if isinstance(t, (_GenericAlias, GenericAlias)): - ev_args = tuple(_eval_type(a, globalns, localns) for a in t.__args__) + ev_args = tuple(_eval_type(a, globalns, localns, recursive_guard) for a in t.__args__) if ev_args == t.__args__: return t if isinstance(t, GenericAlias): @@ -477,7 +479,9 @@ class ForwardRef(_Final, _root=True): self.__forward_value__ = None self.__forward_is_argument__ = is_argument - def _evaluate(self, globalns, localns): + def _evaluate(self, globalns, localns, recursive_guard): + if self.__forward_arg__ in recursive_guard: + return self if not self.__forward_evaluated__ or localns is not globalns: if globalns is None and localns is None: globalns = localns = {} @@ -485,10 +489,14 @@ class ForwardRef(_Final, _root=True): globalns = localns elif localns is None: localns = globalns - self.__forward_value__ = _type_check( + type_ =_type_check( eval(self.__forward_code__, globalns, localns), "Forward references must evaluate to types.", - is_argument=self.__forward_is_argument__) + is_argument=self.__forward_is_argument__, + ) + self.__forward_value__ = _eval_type( + type_, globalns, localns, recursive_guard | {self.__forward_arg__} + ) self.__forward_evaluated__ = True return self.__forward_value__ |