Skip to content

Commit 107983d

Browse files
committed
Merge remote-tracking branch 'upstream/main' into fix/ubsan/clinic-test-111178
2 parents 5695216 + 0555778 commit 107983d

24 files changed

+341
-123
lines changed

Doc/library/annotationlib.rst

-6
Original file line numberDiff line numberDiff line change
@@ -204,12 +204,6 @@ Classes
204204
means may not have any information about their scope, so passing
205205
arguments to this method may be necessary to evaluate them successfully.
206206

207-
.. important::
208-
209-
Once a :class:`~ForwardRef` instance has been evaluated, it caches
210-
the evaluated value, and future calls to :meth:`evaluate` will return
211-
the cached value, regardless of the parameters passed in.
212-
213207
.. versionadded:: 3.14
214208

215209

Doc/library/string.rst

+50-37
Original file line numberDiff line numberDiff line change
@@ -325,11 +325,11 @@ The general form of a *standard format specifier* is:
325325
align: "<" | ">" | "=" | "^"
326326
sign: "+" | "-" | " "
327327
width_and_precision: [`width_with_grouping`][`precision_with_grouping`]
328-
width_with_grouping: [`width`][`grouping_option`]
329-
precision_with_grouping: "." [`precision`]`grouping_option`
328+
width_with_grouping: [`width`][`grouping`]
329+
precision_with_grouping: "." [`precision`][`grouping`]
330330
width: `~python-grammar:digit`+
331-
grouping_option: "_" | ","
332331
precision: `~python-grammar:digit`+
332+
grouping: "," | "_"
333333
type: "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g"
334334
: | "G" | "n" | "o" | "s" | "x" | "X" | "%"
335335

@@ -385,13 +385,13 @@ following:
385385
+---------+----------------------------------------------------------+
386386
| Option | Meaning |
387387
+=========+==========================================================+
388-
| ``'+'`` | indicates that a sign should be used for both |
388+
| ``'+'`` | Indicates that a sign should be used for both |
389389
| | positive as well as negative numbers. |
390390
+---------+----------------------------------------------------------+
391-
| ``'-'`` | indicates that a sign should be used only for negative |
391+
| ``'-'`` | Indicates that a sign should be used only for negative |
392392
| | numbers (this is the default behavior). |
393393
+---------+----------------------------------------------------------+
394-
| space | indicates that a leading space should be used on |
394+
| space | Indicates that a leading space should be used on |
395395
| | positive numbers, and a minus sign on negative numbers. |
396396
+---------+----------------------------------------------------------+
397397

@@ -419,30 +419,7 @@ decimal-point character appears in the result of these conversions
419419
only if a digit follows it. In addition, for ``'g'`` and ``'G'``
420420
conversions, trailing zeros are not removed from the result.
421421

422-
.. index:: single: , (comma); in string formatting
423-
424-
The ``','`` option signals the use of a comma for a thousands separator for
425-
floating-point presentation types and for integer presentation type ``'d'``.
426-
For other presentation types, this option is an error.
427-
For a locale aware separator, use the ``'n'`` integer presentation type
428-
instead.
429-
430-
.. versionchanged:: 3.1
431-
Added the ``','`` option (see also :pep:`378`).
432-
433-
.. index:: single: _ (underscore); in string formatting
434-
435-
The ``'_'`` option signals the use of an underscore for a thousands
436-
separator for floating-point presentation types and for integer
437-
presentation type ``'d'``. For integer presentation types ``'b'``,
438-
``'o'``, ``'x'``, and ``'X'``, underscores will be inserted every 4
439-
digits. For other presentation types, specifying this option is an
440-
error.
441-
442-
.. versionchanged:: 3.6
443-
Added the ``'_'`` option (see also :pep:`515`).
444-
445-
*width* is a decimal integer defining the minimum total field width,
422+
The *width* is a decimal integer defining the minimum total field width,
446423
including any prefixes, separators, and other formatting characters.
447424
If not specified, then the field width will be determined by the content.
448425

@@ -463,12 +440,43 @@ indicates the maximum field size - in other words, how many characters will be
463440
used from the field content. The *precision* is not allowed for integer
464441
presentation types.
465442

466-
The ``'_'`` or ``','`` option after *precision* means the use of an underscore
467-
or a comma for a thousands separator of the fractional part for floating-point
468-
presentation types.
443+
The *grouping* option after *width* and *precision* fields specifies
444+
a digit group separator for the integral and fractional parts
445+
of a number respectively. It can be one of the following:
446+
447+
.. index::
448+
single: , (comma); in string formatting
449+
single: _ (underscore); in string formatting
450+
451+
+---------+----------------------------------------------------------+
452+
| Option | Meaning |
453+
+=========+==========================================================+
454+
| ``','`` | Inserts a comma every 3 digits for |
455+
| | integer presentation type ``'d'`` and |
456+
| | floating-point presentation types, excluding ``'n'``. |
457+
| | For other presentation types, |
458+
| | this option is not supported. |
459+
+---------+----------------------------------------------------------+
460+
| ``'_'`` | Inserts an underscore every 3 digits for |
461+
| | integer presentation type ``'d'`` and |
462+
| | floating-point presentation types, excluding ``'n'``. |
463+
| | For integer presentation types |
464+
| | ``'b'``, ``'o'``, ``'x'``, and ``'X'``, |
465+
| | underscores are inserted every 4 digits. |
466+
| | For other presentation types, |
467+
| | this option is not supported. |
468+
+---------+----------------------------------------------------------+
469+
470+
For a locale aware separator, use the ``'n'`` presentation type instead.
471+
472+
.. versionchanged:: 3.1
473+
Added the ``','`` option (see also :pep:`378`).
474+
475+
.. versionchanged:: 3.6
476+
Added the ``'_'`` option (see also :pep:`515`).
469477

470478
.. versionchanged:: 3.14
471-
Support thousands separators for the fractional part.
479+
Support the *grouping* option for the fractional part.
472480

473481
Finally, the *type* determines how the data should be presented.
474482

@@ -507,7 +515,7 @@ The available integer presentation types are:
507515
+---------+----------------------------------------------------------+
508516
| ``'n'`` | Number. This is the same as ``'d'``, except that it uses |
509517
| | the current locale setting to insert the appropriate |
510-
| | number separator characters. |
518+
| | digit group separators. |
511519
+---------+----------------------------------------------------------+
512520
| None | The same as ``'d'``. |
513521
+---------+----------------------------------------------------------+
@@ -589,7 +597,8 @@ The available presentation types for :class:`float` and
589597
+---------+----------------------------------------------------------+
590598
| ``'n'`` | Number. This is the same as ``'g'``, except that it uses |
591599
| | the current locale setting to insert the appropriate |
592-
| | number separator characters. |
600+
| | digit group separators |
601+
| | for the integral part of a number. |
593602
+---------+----------------------------------------------------------+
594603
| ``'%'`` | Percentage. Multiplies the number by 100 and displays |
595604
| | in fixed (``'f'``) format, followed by a percent sign. |
@@ -716,12 +725,16 @@ Replacing ``%x`` and ``%o`` and converting the value to different bases::
716725
>>> "int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}".format(42)
717726
'int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010'
718727

719-
Using the comma or the underscore as a thousands separator::
728+
Using the comma or the underscore as a digit group separator::
720729

721730
>>> '{:,}'.format(1234567890)
722731
'1,234,567,890'
723732
>>> '{:_}'.format(1234567890)
724733
'1_234_567_890'
734+
>>> '{:_b}'.format(1234567890)
735+
'100_1001_1001_0110_0000_0010_1101_0010'
736+
>>> '{:_x}'.format(1234567890)
737+
'4996_02d2'
725738
>>> '{:_}'.format(123456789.123456789)
726739
'123_456_789.12345679'
727740
>>> '{:._}'.format(123456789.123456789)

Doc/library/typing.rst

+3-1
Original file line numberDiff line numberDiff line change
@@ -3449,7 +3449,9 @@ Introspection helpers
34493449
.. versionadded:: 3.7.4
34503450

34513451
.. versionchanged:: 3.14
3452-
This is now an alias for :class:`annotationlib.ForwardRef`.
3452+
This is now an alias for :class:`annotationlib.ForwardRef`. Several undocumented
3453+
behaviors of this class have been changed; for example, after a ``ForwardRef`` has
3454+
been evaluated, the evaluated value is no longer cached.
34533455

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

Doc/whatsnew/3.14.rst

+54-1
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ This example shows how these formats behave:
209209
...
210210
NameError: name 'Undefined' is not defined
211211
>>> get_annotations(func, format=Format.FORWARDREF)
212-
{'arg': ForwardRef('Undefined')}
212+
{'arg': ForwardRef('Undefined', owner=<function func at 0x...>)}
213213
>>> get_annotations(func, format=Format.STRING)
214214
{'arg': 'Undefined'}
215215

@@ -1075,6 +1075,54 @@ turtle
10751075
(Contributed by Marie Roald and Yngve Mardal Moe in :gh:`126350`.)
10761076

10771077

1078+
types
1079+
-----
1080+
1081+
* :class:`types.UnionType` is now an alias for :class:`typing.Union`.
1082+
See :ref:`below <whatsnew314-typing-union>` for more details.
1083+
(Contributed by Jelle Zijlstra in :gh:`105499`.)
1084+
1085+
1086+
typing
1087+
------
1088+
1089+
.. _whatsnew314-typing-union:
1090+
1091+
* :class:`types.UnionType` and :class:`typing.Union` are now aliases for each other,
1092+
meaning that both old-style unions (created with ``Union[int, str]``) and new-style
1093+
unions (``int | str``) now create instances of the same runtime type. This unifies
1094+
the behavior between the two syntaxes, but leads to some differences in behavior that
1095+
may affect users who introspect types at runtime:
1096+
1097+
- Both syntaxes for creating a union now produce the same string representation in
1098+
``repr()``. For example, ``repr(Union[int, str])``
1099+
is now ``"int | str"`` instead of ``"typing.Union[int, str]"``.
1100+
- Unions created using the old syntax are no longer cached. Previously, running
1101+
``Union[int, str]`` multiple times would return the same object
1102+
(``Union[int, str] is Union[int, str]`` would be ``True``), but now it will
1103+
return two different objects. Users should use ``==`` to compare unions for equality, not
1104+
``is``. New-style unions have never been cached this way.
1105+
This change could increase memory usage for some programs that use a large number of
1106+
unions created by subscripting ``typing.Union``. However, several factors offset this cost:
1107+
unions used in annotations are no longer evaluated by default in Python 3.14
1108+
because of :pep:`649`; an instance of :class:`types.UnionType` is
1109+
itself much smaller than the object returned by ``Union[]`` was on prior Python
1110+
versions; and removing the cache also saves some space. It is therefore
1111+
unlikely that this change will cause a significant increase in memory usage for most
1112+
users.
1113+
- Previously, old-style unions were implemented using the private class
1114+
``typing._UnionGenericAlias``. This class is no longer needed for the implementation,
1115+
but it has been retained for backward compatibility, with removal scheduled for Python
1116+
3.17. Users should use documented introspection helpers like :func:`typing.get_origin`
1117+
and :func:`typing.get_args` instead of relying on private implementation details.
1118+
- It is now possible to use :class:`typing.Union` itself in :func:`isinstance` checks.
1119+
For example, ``isinstance(int | str, typing.Union)`` will return ``True``; previously
1120+
this raised :exc:`TypeError`.
1121+
- The ``__args__`` attribute of :class:`typing.Union` objects is no longer writable.
1122+
1123+
(Contributed by Jelle Zijlstra in :gh:`105499`.)
1124+
1125+
10781126
unicodedata
10791127
-----------
10801128

@@ -1608,6 +1656,11 @@ Changes in the Python API
16081656
This temporary change affects other threads.
16091657
(Contributed by Serhiy Storchaka in :gh:`69998`.)
16101658

1659+
* :class:`types.UnionType` is now an alias for :class:`typing.Union`,
1660+
causing changes in some behaviors.
1661+
See :ref:`above <whatsnew314-typing-union>` for more details.
1662+
(Contributed by Jelle Zijlstra in :gh:`105499`.)
1663+
16111664

16121665
Build changes
16131666
=============

Lib/annotationlib.py

+31-30
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,16 @@ class Format(enum.IntEnum):
3232
# preserved for compatibility with the old typing.ForwardRef class. The remaining
3333
# names are private.
3434
_SLOTS = (
35-
"__forward_evaluated__",
36-
"__forward_value__",
3735
"__forward_is_argument__",
3836
"__forward_is_class__",
3937
"__forward_module__",
4038
"__weakref__",
4139
"__arg__",
42-
"__ast_node__",
43-
"__code__",
4440
"__globals__",
45-
"__owner__",
41+
"__code__",
42+
"__ast_node__",
4643
"__cell__",
44+
"__owner__",
4745
"__stringifier_dict__",
4846
)
4947

@@ -76,14 +74,12 @@ def __init__(
7674
raise TypeError(f"Forward reference must be a string -- got {arg!r}")
7775

7876
self.__arg__ = arg
79-
self.__forward_evaluated__ = False
80-
self.__forward_value__ = None
8177
self.__forward_is_argument__ = is_argument
8278
self.__forward_is_class__ = is_class
8379
self.__forward_module__ = module
80+
self.__globals__ = None
8481
self.__code__ = None
8582
self.__ast_node__ = None
86-
self.__globals__ = None
8783
self.__cell__ = None
8884
self.__owner__ = owner
8985

@@ -95,17 +91,11 @@ def evaluate(self, *, globals=None, locals=None, type_params=None, owner=None):
9591
9692
If the forward reference cannot be evaluated, raise an exception.
9793
"""
98-
if self.__forward_evaluated__:
99-
return self.__forward_value__
10094
if self.__cell__ is not None:
10195
try:
102-
value = self.__cell__.cell_contents
96+
return self.__cell__.cell_contents
10397
except ValueError:
10498
pass
105-
else:
106-
self.__forward_evaluated__ = True
107-
self.__forward_value__ = value
108-
return value
10999
if owner is None:
110100
owner = self.__owner__
111101

@@ -171,8 +161,6 @@ def evaluate(self, *, globals=None, locals=None, type_params=None, owner=None):
171161
else:
172162
code = self.__forward_code__
173163
value = eval(code, globals=globals, locals=locals)
174-
self.__forward_evaluated__ = True
175-
self.__forward_value__ = value
176164
return value
177165

178166
def _evaluate(self, globalns, localns, type_params=_sentinel, *, recursive_guard):
@@ -230,18 +218,30 @@ def __forward_code__(self):
230218
def __eq__(self, other):
231219
if not isinstance(other, ForwardRef):
232220
return NotImplemented
233-
if self.__forward_evaluated__ and other.__forward_evaluated__:
234-
return (
235-
self.__forward_arg__ == other.__forward_arg__
236-
and self.__forward_value__ == other.__forward_value__
237-
)
238221
return (
239222
self.__forward_arg__ == other.__forward_arg__
240223
and self.__forward_module__ == other.__forward_module__
224+
# Use "is" here because we use id() for this in __hash__
225+
# because dictionaries are not hashable.
226+
and self.__globals__ is other.__globals__
227+
and self.__forward_is_class__ == other.__forward_is_class__
228+
and self.__code__ == other.__code__
229+
and self.__ast_node__ == other.__ast_node__
230+
and self.__cell__ == other.__cell__
231+
and self.__owner__ == other.__owner__
241232
)
242233

243234
def __hash__(self):
244-
return hash((self.__forward_arg__, self.__forward_module__))
235+
return hash((
236+
self.__forward_arg__,
237+
self.__forward_module__,
238+
id(self.__globals__), # dictionaries are not hashable, so hash by identity
239+
self.__forward_is_class__,
240+
self.__code__,
241+
self.__ast_node__,
242+
self.__cell__,
243+
self.__owner__,
244+
))
245245

246246
def __or__(self, other):
247247
return types.UnionType[self, other]
@@ -250,11 +250,14 @@ def __ror__(self, other):
250250
return types.UnionType[other, self]
251251

252252
def __repr__(self):
253-
if self.__forward_module__ is None:
254-
module_repr = ""
255-
else:
256-
module_repr = f", module={self.__forward_module__!r}"
257-
return f"ForwardRef({self.__forward_arg__!r}{module_repr})"
253+
extra = []
254+
if self.__forward_module__ is not None:
255+
extra.append(f", module={self.__forward_module__!r}")
256+
if self.__forward_is_class__:
257+
extra.append(", is_class=True")
258+
if self.__owner__ is not None:
259+
extra.append(f", owner={self.__owner__!r}")
260+
return f"ForwardRef({self.__forward_arg__!r}{''.join(extra)})"
258261

259262

260263
class _Stringifier:
@@ -276,8 +279,6 @@ def __init__(
276279
# represent a single name).
277280
assert isinstance(node, (ast.AST, str))
278281
self.__arg__ = None
279-
self.__forward_evaluated__ = False
280-
self.__forward_value__ = None
281282
self.__forward_is_argument__ = False
282283
self.__forward_is_class__ = is_class
283284
self.__forward_module__ = None

0 commit comments

Comments
 (0)