Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
- Drop support for Python 3.8 (including PyPy-3.8). Patch by [Victorien Plot](https://github.com/Viicos).
- Do not attempt to re-export names that have been removed from `typing`,
anticipating the removal of `typing.no_type_check_decorator` in Python 3.15.
Patch by Jelle Zijlstra.
- Update `typing_extensions.Format` and `typing_extensions.evaluate_forward_ref` to align
with changes in Python 3.14. Patch by Jelle Zijlstra.
- Fix tests for Python 3.14. Patch by Jelle Zijlstra.

New features:

- Add support for inline typed dictionaries ([PEP 764](https://peps.python.org/pep-0764/)).
Patch by [Victorien Plot](https://github.com/Viicos).
- Add `typing_extensions.Reader` and `typing_extensions.Writer`. Patch by
Sebastian Rittau.
- Fix tests for Python 3.14. Patch by Jelle Zijlstra.

# Release 4.13.2 (April 10, 2025)

Expand Down
18 changes: 14 additions & 4 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,7 @@ Functions

.. versionadded:: 4.2.0

.. function:: evaluate_forward_ref(forward_ref, *, owner=None, globals=None, locals=None, type_params=None, format=Format.VALUE)
.. function:: evaluate_forward_ref(forward_ref, *, owner=None, globals=None, locals=None, type_params=None, format=None)

Evaluate an :py:class:`typing.ForwardRef` as a :py:term:`type hint`.

Expand All @@ -796,7 +796,7 @@ Functions
This parameter must 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:`Format` enum.
the :class:`Format` enum, defaulting :attr:`Format.VALUE`.
Comment thread
JelleZijlstra marked this conversation as resolved.
Outdated

.. versionadded:: 4.13.0

Expand Down Expand Up @@ -952,9 +952,19 @@ Enums
for the annotations. This format is identical to the return value for
the function under earlier versions of Python.

.. attribute:: VALUE_WITH_FAKE_GLOBALS

Equal to 2. Special value used to signal that an annotate function is being
evaluated in a special environment with fake globals. When passed this
value, annotate functions should either return the same value as for
the :attr:`Format.VALUE` format, or raise :exc:`NotImplementedError`
to signal that they do not support execution in this environment.
This format is only used internally and should not be passed to
the functions in this module.

.. attribute:: FORWARDREF

Equal to 2. When :pep:`649` is implemented, this format will attempt to return the
Equal to 3. When :pep:`649` is implemented, this format will attempt to return the
conventional Python values for the annotations. However, if it encounters
an undefined name, it dynamically creates a proxy object (a ForwardRef)
that substitutes for that value in the expression.
Expand All @@ -964,7 +974,7 @@ Enums

.. attribute:: STRING

Equal to 3. When :pep:`649` is implemented, this format will produce an annotation
Equal to 4. When :pep:`649` is implemented, this format will produce an annotation
dictionary where the values have been replaced by strings containing
an approximation of the original source code for the annotation expressions.

Expand Down
5 changes: 2 additions & 3 deletions src/test_typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
from _typed_dict_test_helper import Foo, FooGeneric, VeryAnnotated
from typing_extensions import (
_FORWARD_REF_HAS_CLASS,
_PEP_649_OR_749_IMPLEMENTED,
Annotated,
Any,
AnyStr,
Expand Down Expand Up @@ -8533,7 +8532,7 @@ def test_stock_annotations_in_module(self):
get_annotations(isa.MyClass, format=Format.STRING),
{"a": "int", "b": "str"},
)
mycls = "MyClass" if _PEP_649_OR_749_IMPLEMENTED else "inspect_stock_annotations.MyClass"
mycls = "MyClass" if sys.version_info >= (3, 14) else "inspect_stock_annotations.MyClass"
self.assertEqual(
get_annotations(isa.function, format=Format.STRING),
{"a": "int", "b": "str", "return": mycls},
Expand Down Expand Up @@ -8581,7 +8580,7 @@ def test_stock_annotations_on_wrapper(self):
get_annotations(wrapped, format=Format.FORWARDREF),
{"a": int, "b": str, "return": isa.MyClass},
)
mycls = "MyClass" if _PEP_649_OR_749_IMPLEMENTED else "inspect_stock_annotations.MyClass"
mycls = "MyClass" if sys.version_info >= (3, 14) else "inspect_stock_annotations.MyClass"
self.assertEqual(
get_annotations(wrapped, format=Format.STRING),
{"a": "int", "b": "str", "return": mycls},
Expand Down
30 changes: 9 additions & 21 deletions src/typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3821,27 +3821,15 @@ def __eq__(self, other: object) -> bool:
__all__.append("CapsuleType")


# Using this convoluted approach so that this keeps working
# whether we end up using PEP 649 as written, PEP 749, or
# some other variation: in any case, inspect.get_annotations
# will continue to exist and will gain a `format` parameter.
_PEP_649_OR_749_IMPLEMENTED = (
hasattr(inspect, 'get_annotations')
and inspect.get_annotations.__kwdefaults__ is not None
and "format" in inspect.get_annotations.__kwdefaults__
)


class Format(enum.IntEnum):
VALUE = 1
VALUE_WITH_FAKE_GLOBALS = 2
FORWARDREF = 3
STRING = 4


if _PEP_649_OR_749_IMPLEMENTED:
get_annotations = inspect.get_annotations
if sys.version_info >= (3,14):
from annotationlib import Format, get_annotations
else:
class Format(enum.IntEnum):
VALUE = 1
VALUE_WITH_FAKE_GLOBALS = 2
FORWARDREF = 3
STRING = 4

def get_annotations(obj, *, globals=None, locals=None, eval_str=False,
format=Format.VALUE):
"""Compute the annotations dict for an object.
Expand Down Expand Up @@ -4122,7 +4110,7 @@ def evaluate_forward_ref(
globals=None,
locals=None,
type_params=None,
format=Format.VALUE,
format=None,
_recursive_guard=frozenset(),
):
"""Evaluate a forward reference as a type hint.
Expand Down
Loading