Skip to content

Commit

Permalink
pythongh-118418: Deprecate failing to pass a value to the *type_param…
Browse files Browse the repository at this point in the history
…s* parameter of some private `typing` APIs
  • Loading branch information
AlexWaygood committed May 7, 2024
1 parent 9762122 commit c416507
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 11 deletions.
25 changes: 25 additions & 0 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -6308,6 +6308,31 @@ def test_or(self):
self.assertEqual(X | "x", Union[X, "x"])
self.assertEqual("x" | X, Union["x", X])

def test_deprecation_for_no_type_params_passed_to__evaluate(self):
with self.assertWarnsRegex(
DeprecationWarning,
(
"Failing to pass a value to the `type_params` parameter "
"of 'typing._eval_type' is deprecated"
)
) as cm:
self.assertEqual(typing._eval_type(list["int"], globals(), {}), list[int])

self.assertEqual(cm.filename, __file__)

f = ForwardRef("int")

with self.assertWarnsRegex(
DeprecationWarning,
(
"Failing to pass a value to the `type_params` parameter "
"of 'typing.ForwardRef._evaluate' is deprecated"
)
) as cm:
self.assertIs(f._evaluate(globals(), {}, recursive_guard=frozenset()), int)

self.assertEqual(cm.filename, __file__)


@lru_cache()
def cached_func(x, y):
Expand Down
41 changes: 30 additions & 11 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -437,13 +437,38 @@ def inner(*args, **kwds):
return decorator


def _eval_type(t, globalns, localns, type_params=None, *, recursive_guard=frozenset()):
def _deprecation_warning_for_no_type_params_passed(funcname: str) -> None:
import warnings

depr_message = (
f"Failing to pass a value to the `type_params` parameter "
f"of {funcname!r} is deprecated, as it leads to incorrect behaviour "
f"when calling {funcname} on a stringified annotation "
f"that references a PEP-695 type parameter. "
f"It will be disallowed in Python 3.15."
)
warnings.warn(depr_message, category=DeprecationWarning, stacklevel=3)


class _Sentinel:
__slots__ = ()
def __repr__(self):
return '<sentinel>'


_sentinel = _Sentinel()


def _eval_type(t, globalns, localns, type_params=_sentinel, *, recursive_guard=frozenset()):
"""Evaluate all forward references in the given type t.
For use of globalns and localns see the docstring for get_type_hints().
recursive_guard is used to prevent infinite recursion with a recursive
ForwardRef.
"""
if type_params is _sentinel:
_deprecation_warning_for_no_type_params_passed("typing._eval_type")
type_params = ()
if isinstance(t, ForwardRef):
return t._evaluate(globalns, localns, type_params, recursive_guard=recursive_guard)
if isinstance(t, (_GenericAlias, GenericAlias, types.UnionType)):
Expand Down Expand Up @@ -1018,7 +1043,10 @@ def __init__(self, arg, is_argument=True, module=None, *, is_class=False):
self.__forward_is_class__ = is_class
self.__forward_module__ = module

def _evaluate(self, globalns, localns, type_params=None, *, recursive_guard):
def _evaluate(self, globalns, localns, type_params=_sentinel, *, recursive_guard):
if type_params is _sentinel:
_deprecation_warning_for_no_type_params_passed("typing.ForwardRef._evaluate")
type_params = ()
if self.__forward_arg__ in recursive_guard:
return self
if not self.__forward_evaluated__ or localns is not globalns:
Expand Down Expand Up @@ -2998,15 +3026,6 @@ def __new__(cls, typename, bases, ns):
return nm_tpl


class _Sentinel:
__slots__ = ()
def __repr__(self):
return '<sentinel>'


_sentinel = _Sentinel()


def NamedTuple(typename, fields=_sentinel, /, **kwargs):
"""Typed version of namedtuple.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
A :exc:`DeprecationWarning` is now emitted if you fail to pass a value to
the new *type_params* parameter of ``typing._eval_type()`` or
``typing.ForwardRef._evaluate()``. (Using either of these private and
undocumented functions is discouraged to begin with, but failing to pass a
value to the ``type_params`` parameter may lead to incorrect behaviour on
Python 3.12 or newer.)

0 comments on commit c416507

Please sign in to comment.