mirror of
https://github.com/python/cpython.git
synced 2025-09-27 02:39:58 +00:00
gh-118418: Deprecate failing to pass a value to the *type_params* parameter of some private typing
APIs (#118695)
This commit is contained in:
parent
6f768b71ba
commit
0f8a07d158
3 changed files with 61 additions and 11 deletions
|
@ -6308,6 +6308,31 @@ class ForwardRefTests(BaseTestCase):
|
||||||
self.assertEqual(X | "x", Union[X, "x"])
|
self.assertEqual(X | "x", Union[X, "x"])
|
||||||
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()
|
@lru_cache()
|
||||||
def cached_func(x, y):
|
def cached_func(x, y):
|
||||||
|
|
|
@ -437,13 +437,38 @@ def _tp_cache(func=None, /, *, typed=False):
|
||||||
return decorator
|
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.
|
"""Evaluate all forward references in the given type t.
|
||||||
|
|
||||||
For use of globalns and localns see the docstring for get_type_hints().
|
For use of globalns and localns see the docstring for get_type_hints().
|
||||||
recursive_guard is used to prevent infinite recursion with a recursive
|
recursive_guard is used to prevent infinite recursion with a recursive
|
||||||
ForwardRef.
|
ForwardRef.
|
||||||
"""
|
"""
|
||||||
|
if type_params is _sentinel:
|
||||||
|
_deprecation_warning_for_no_type_params_passed("typing._eval_type")
|
||||||
|
type_params = ()
|
||||||
if isinstance(t, ForwardRef):
|
if isinstance(t, ForwardRef):
|
||||||
return t._evaluate(globalns, localns, type_params, recursive_guard=recursive_guard)
|
return t._evaluate(globalns, localns, type_params, recursive_guard=recursive_guard)
|
||||||
if isinstance(t, (_GenericAlias, GenericAlias, types.UnionType)):
|
if isinstance(t, (_GenericAlias, GenericAlias, types.UnionType)):
|
||||||
|
@ -1018,7 +1043,10 @@ class ForwardRef(_Final, _root=True):
|
||||||
self.__forward_is_class__ = is_class
|
self.__forward_is_class__ = is_class
|
||||||
self.__forward_module__ = module
|
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:
|
if self.__forward_arg__ in recursive_guard:
|
||||||
return self
|
return self
|
||||||
if not self.__forward_evaluated__ or localns is not globalns:
|
if not self.__forward_evaluated__ or localns is not globalns:
|
||||||
|
@ -2998,15 +3026,6 @@ class NamedTupleMeta(type):
|
||||||
return nm_tpl
|
return nm_tpl
|
||||||
|
|
||||||
|
|
||||||
class _Sentinel:
|
|
||||||
__slots__ = ()
|
|
||||||
def __repr__(self):
|
|
||||||
return '<sentinel>'
|
|
||||||
|
|
||||||
|
|
||||||
_sentinel = _Sentinel()
|
|
||||||
|
|
||||||
|
|
||||||
def NamedTuple(typename, fields=_sentinel, /, **kwargs):
|
def NamedTuple(typename, fields=_sentinel, /, **kwargs):
|
||||||
"""Typed version of namedtuple.
|
"""Typed version of namedtuple.
|
||||||
|
|
||||||
|
|
|
@ -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.)
|
Loading…
Add table
Add a link
Reference in a new issue