summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Waygood <Alex.Waygood@Gmail.com>2024-05-07 11:12:28 (GMT)
committerGitHub <noreply@github.com>2024-05-07 11:12:28 (GMT)
commit0f8a07d158ba0a0dfd3584d8195f30dd16738555 (patch)
treec646b685c4e05550e499975e732b9abfe9db7cca
parent6f768b71bab837c6c4aac4d3ddd251e55025fe0b (diff)
downloadcpython-0f8a07d158ba0a0dfd3584d8195f30dd16738555.zip
cpython-0f8a07d158ba0a0dfd3584d8195f30dd16738555.tar.gz
cpython-0f8a07d158ba0a0dfd3584d8195f30dd16738555.tar.bz2
gh-118418: Deprecate failing to pass a value to the *type_params* parameter of some private `typing` APIs (#118695)
-rw-r--r--Lib/test/test_typing.py25
-rw-r--r--Lib/typing.py41
-rw-r--r--Misc/NEWS.d/next/Library/2024-05-07-11-23-11.gh-issue-118418.QPMdJm.rst6
3 files changed, 61 insertions, 11 deletions
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 8f0be1f..0126133 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -6308,6 +6308,31 @@ class ForwardRefTests(BaseTestCase):
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):
diff --git a/Lib/typing.py b/Lib/typing.py
index c159fcf..e485836 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -437,13 +437,38 @@ def _tp_cache(func=None, /, *, typed=False):
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)):
@@ -1018,7 +1043,10 @@ class ForwardRef(_Final, _root=True):
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:
@@ -2998,15 +3026,6 @@ class NamedTupleMeta(type):
return nm_tpl
-class _Sentinel:
- __slots__ = ()
- def __repr__(self):
- return '<sentinel>'
-
-
-_sentinel = _Sentinel()
-
-
def NamedTuple(typename, fields=_sentinel, /, **kwargs):
"""Typed version of namedtuple.
diff --git a/Misc/NEWS.d/next/Library/2024-05-07-11-23-11.gh-issue-118418.QPMdJm.rst b/Misc/NEWS.d/next/Library/2024-05-07-11-23-11.gh-issue-118418.QPMdJm.rst
new file mode 100644
index 0000000..be371c5
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-05-07-11-23-11.gh-issue-118418.QPMdJm.rst
@@ -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.)