From bc68f2e5d40ac0ec2eecfa4ee3d2c30a89da7859 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 16 Jan 2025 21:19:29 -0800 Subject: [PATCH 1/2] gh-128661: Remove DeprecationWarning in evaluate_forward_ref It doesn't make sense to use a deprecation for evaluate_forward_ref, as it is a new function in Python 3.14 and doesn't have compatibility guarantees. I considered making it throw an error if type_params it not passed and there is no owner. However, I think this is too unfriendly for users. The case where this param is really needed is fairly esoteric and I don't think this case is worth the pain of forcing users to write "type_params=()". --- Doc/library/annotationlib.rst | 5 ++++- Doc/library/typing.rst | 2 +- Lib/test/test_typing.py | 15 +-------------- Lib/typing.py | 7 ++----- 4 files changed, 8 insertions(+), 21 deletions(-) diff --git a/Doc/library/annotationlib.rst b/Doc/library/annotationlib.rst index dcaff3d7fdbec5..7ce8e8c664a41a 100644 --- a/Doc/library/annotationlib.rst +++ b/Doc/library/annotationlib.rst @@ -192,7 +192,10 @@ Classes the global and local namespaces in which the name is evaluated. *type_params*, if given, must be a tuple of :ref:`type parameters ` that are in scope while the forward - reference is being evaluated. *owner* is the object that owns the + reference is being evaluated. This parameter should be provided (though it + may be an empty tuple) if the *owner* parameter is not given and the + :class:`~ForwardRef` instance does not have an owner set. + *owner* is the object that owns the annotation from which the forward reference derives, usually a function, class, or module. diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 0fee782121b0af..4e2e2905b02b3a 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -3439,7 +3439,7 @@ Introspection helpers the global and local namespaces. *type_params* is a tuple of :ref:`type parameters ` that are in scope when evaluating the forward reference. - This parameter must be provided (though it may be an empty tuple) if *owner* + This parameter should be provided (though it may be an empty tuple) if *owner* is not given and the forward reference does not already have an owner set. *format* specifies the format of the annotation and is a member of the :class:`annotationlib.Format` enum. diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index f002d28df60e9c..383565601cc69f 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -7284,20 +7284,7 @@ def test_evaluate_forward_ref(self): def test_evaluate_forward_ref_no_type_params(self): ref = ForwardRef('int') - with self.assertWarnsRegex( - DeprecationWarning, - ( - "Failing to pass a value to the 'type_params' parameter " - "of 'typing.evaluate_forward_ref' is deprecated, " - "as it leads to incorrect behaviour" - ), - ): - typing.evaluate_forward_ref(ref) - - # No warnings when `type_params` is passed: - with warnings.catch_warnings(record=True) as w: - typing.evaluate_forward_ref(ref, type_params=()) - self.assertEqual(w, []) + self.assertIs(typing.evaluate_forward_ref(ref), int) class CollectionsAbcTests(BaseTestCase): diff --git a/Lib/typing.py b/Lib/typing.py index 66570db7a5bd74..4c92128e1081c8 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1024,7 +1024,7 @@ def evaluate_forward_ref( owner=None, globals=None, locals=None, - type_params=_sentinel, + type_params=None, format=annotationlib.Format.VALUE, _recursive_guard=frozenset(), ): @@ -1044,15 +1044,12 @@ def evaluate_forward_ref( infer the namespaces to use for looking up names. *globals* and *locals* can also be explicitly given to provide the global and local namespaces. *type_params* is a tuple of type parameters that are in scope when - evaluating the forward reference. This parameter must be provided (though + evaluating the forward reference. This parameter should be provided (though it may be an empty tuple) if *owner* is not given and the forward reference does not already have an owner set. *format* specifies the format of the annotation and is a member of the annotationlib.Format enum. """ - if type_params is _sentinel: - _deprecation_warning_for_no_type_params_passed("typing.evaluate_forward_ref") - type_params = () if format == annotationlib.Format.STRING: return forward_ref.__forward_arg__ if forward_ref.__forward_arg__ in _recursive_guard: From 9f69ffed7ea6c36f7e4de290301ac4483fab5b53 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Mon, 3 Mar 2025 14:22:32 -0800 Subject: [PATCH 2/2] Better docs for fwdref evaluation --- Doc/library/annotationlib.rst | 31 ++++++++++++++++++------------- Doc/library/typing.rst | 12 ++---------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/Doc/library/annotationlib.rst b/Doc/library/annotationlib.rst index 7ce8e8c664a41a..ab9393e8cd8ab7 100644 --- a/Doc/library/annotationlib.rst +++ b/Doc/library/annotationlib.rst @@ -172,15 +172,31 @@ Classes :class:`~ForwardRef`. The string may not be exactly equivalent to the original source. - .. method:: evaluate(*, globals=None, locals=None, type_params=None, owner=None) + .. method:: evaluate(*, owner=None, globals=None, locals=None, type_params=None) Evaluate the forward reference, returning its value. This may throw an exception, such as :exc:`NameError`, if the forward - reference refers to names that do not exist. The arguments to this + reference refers to a name that cannot be resolved. The arguments to this method can be used to provide bindings for names that would otherwise be undefined. + The *owner* parameter provides the preferred mechanism for passing scope + information to this method. The owner of a :class:`~ForwardRef` is the + object that contains the annotation from which the :class:`~ForwardRef` + derives, such as a module object, type object, or function object. + + The *globals*, *locals*, and *type_params* parameters provide a more precise + mechanism for influencing the names that are available when the :class:`~ForwardRef` + is evaluated. *globals* and *locals* are passed to :func:`eval`, representing + the global and local namespaces in which the name is evaluated. + The *type_params* parameter is relevant for objects created using the native + syntax for :ref:`generic classes ` and :ref:`functions `. + It is a tuple of :ref:`type parameters ` that are in scope + while the forward reference is being evaluated. For example, if evaluating a + :class:`~ForwardRef` retrieved from an annotation found in the class namespace + of a generic class ``C``, *type_params* should be set to ``C.__type_params__``. + :class:`~ForwardRef` instances returned by :func:`get_annotations` retain references to information about the scope they originated from, so calling this method with no further arguments may be sufficient to @@ -188,17 +204,6 @@ Classes means may not have any information about their scope, so passing arguments to this method may be necessary to evaluate them successfully. - *globals* and *locals* are passed to :func:`eval`, representing - the global and local namespaces in which the name is evaluated. - *type_params*, if given, must be a tuple of - :ref:`type parameters ` that are in scope while the forward - reference is being evaluated. This parameter should be provided (though it - may be an empty tuple) if the *owner* parameter is not given and the - :class:`~ForwardRef` instance does not have an owner set. - *owner* is the object that owns the - annotation from which the forward reference derives, usually a function, - class, or module. - .. important:: Once a :class:`~ForwardRef` instance has been evaluated, it caches diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 4e2e2905b02b3a..353d0aed97f156 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -3431,16 +3431,8 @@ Introspection helpers * Supports the :attr:`~annotationlib.Format.FORWARDREF` and :attr:`~annotationlib.Format.STRING` formats. - *forward_ref* must be an instance of :class:`~annotationlib.ForwardRef`. - *owner*, if given, should be the object that holds the annotations that - the forward reference derived from, such as a module, class object, or function. - It is used to infer the namespaces to use for looking up names. - *globals* and *locals* can also be explicitly given to provide - the global and local namespaces. - *type_params* is a tuple of :ref:`type parameters ` that - are in scope when evaluating the forward reference. - This parameter should be provided (though it may be an empty tuple) if *owner* - is not given and the forward reference does not already have an owner set. + See the documentation for :meth:`annotationlib.ForwardRef.evaluate` for + the meaning of the *owner*, *globals*, *locals*, and *type_params* parameters. *format* specifies the format of the annotation and is a member of the :class:`annotationlib.Format` enum.