Skip to content

Commit 8386b24

Browse files
committed
first draft
1 parent 82d512a commit 8386b24

File tree

1 file changed

+89
-0
lines changed

1 file changed

+89
-0
lines changed

src/typing_extensions.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3928,6 +3928,95 @@ def get_annotations(obj, *, globals=None, locals=None, eval_str=False,
39283928
value if not isinstance(value, str) else eval(value, globals, locals)
39293929
for key, value in ann.items() }
39303930
return return_value
3931+
3932+
3933+
3934+
if hasattr(typing, "evaluate_forward_ref"):
3935+
evaluate_forward_ref = typing.evaluate_forward_ref
3936+
else:
3937+
if hasattr(typing, "_deprecation_warning_for_no_type_params_passed"):
3938+
_deprecation_warning_for_no_type_params_passed = (
3939+
typing._deprecation_warning_for_no_type_params_passed
3940+
)
3941+
else:
3942+
def _deprecation_warning_for_no_type_params_passed(funcname: str) -> None:
3943+
import warnings
3944+
3945+
depr_message = (
3946+
f"Failing to pass a value to the 'type_params' parameter "
3947+
f"of {funcname!r} is deprecated, as it leads to incorrect behaviour "
3948+
f"when calling {funcname} on a stringified annotation "
3949+
f"that references a PEP 695 type parameter. "
3950+
f"It will be disallowed in Python 3.15."
3951+
)
3952+
warnings.warn(depr_message, category=DeprecationWarning, stacklevel=3)
3953+
3954+
def evaluate_forward_ref(
3955+
forward_ref,
3956+
*,
3957+
owner=None,
3958+
globals=None,
3959+
locals=None,
3960+
type_params=_marker,
3961+
format=Format.VALUE,
3962+
_recursive_guard=frozenset(),
3963+
):
3964+
"""Evaluate a forward reference as a type hint.
3965+
3966+
This is similar to calling the ForwardRef.evaluate() method,
3967+
but unlike that method, evaluate_forward_ref() also:
3968+
3969+
* Recursively evaluates forward references nested within the type hint.
3970+
* Rejects certain objects that are not valid type hints.
3971+
* Replaces type hints that evaluate to None with types.NoneType.
3972+
* Supports the *FORWARDREF* and *STRING* formats.
3973+
3974+
*forward_ref* must be an instance of ForwardRef. *owner*, if given,
3975+
should be the object that holds the annotations that the forward reference
3976+
derived from, such as a module, class object, or function. It is used to
3977+
infer the namespaces to use for looking up names. *globals* and *locals*
3978+
can also be explicitly given to provide the global and local namespaces.
3979+
*type_params* is a tuple of type parameters that are in scope when
3980+
evaluating the forward reference. This parameter must be provided (though
3981+
it may be an empty tuple) if *owner* is not given and the forward reference
3982+
does not already have an owner set. *format* specifies the format of the
3983+
annotation and is a member of the annotationlib.Format enum.
3984+
3985+
"""
3986+
if type_params is _sentinel:
3987+
_deprecation_warning_for_no_type_params_passed("typing.evaluate_forward_ref")
3988+
type_params = ()
3989+
if format == Format.STRING:
3990+
return forward_ref.__forward_arg__
3991+
if forward_ref.__forward_arg__ in _recursive_guard:
3992+
return forward_ref
3993+
3994+
try:
3995+
value = forward_ref.evaluate(
3996+
globals=globals, locals=locals, type_params=type_params, owner=owner
3997+
)
3998+
except NameError:
3999+
if format == Format.FORWARDREF:
4000+
return forward_ref
4001+
else:
4002+
raise
4003+
4004+
type_ = typing._type_check(
4005+
value,
4006+
"Forward references must evaluate to types.",
4007+
is_argument=forward_ref.__forward_is_argument__,
4008+
allow_special_forms=forward_ref.__forward_is_class__,
4009+
)
4010+
return typing._eval_type(
4011+
type_,
4012+
globals,
4013+
locals,
4014+
type_params,
4015+
recursive_guard=_recursive_guard | {forward_ref.__forward_arg__},
4016+
format=format,
4017+
owner=owner,
4018+
)
4019+
39314020

39324021
# Aliases for items that have always been in typing.
39334022
# Explicitly assign these (rather than using `from typing import *` at the top),

0 commit comments

Comments
 (0)