Skip to content

Commit b0544ba

Browse files
authored
bpo-38605: Revert making 'from __future__ import annotations' the default (GH-25490)
This reverts commits 044a104 and 1be456a, adapting the code to changes that happened after it.
1 parent d35eef3 commit b0544ba

32 files changed

+436
-523
lines changed

Doc/reference/compound_stmts.rst

+7-3
Original file line numberDiff line numberDiff line change
@@ -1244,9 +1244,13 @@ following the parameter name. Any parameter may have an annotation, even those
12441244
``*identifier`` or ``**identifier``. Functions may have "return" annotation of
12451245
the form "``-> expression``" after the parameter list. These annotations can be
12461246
any valid Python expression. The presence of annotations does not change the
1247-
semantics of a function. The annotation values are available as string values
1248-
in a dictionary keyed by the parameters' names in the :attr:`__annotations__`
1249-
attribute of the function object.
1247+
semantics of a function. The annotation values are available as values of
1248+
a dictionary keyed by the parameters' names in the :attr:`__annotations__`
1249+
attribute of the function object. If the ``annotations`` import from
1250+
:mod:`__future__` is used, annotations are preserved as strings at runtime which
1251+
enables postponed evaluation. Otherwise, they are evaluated when the function
1252+
definition is executed. In this case annotations may be evaluated in
1253+
a different order than they appear in the source code.
12501254

12511255
.. index:: pair: lambda; expression
12521256

Doc/reference/simple_stmts.rst

+5-2
Original file line numberDiff line numberDiff line change
@@ -877,11 +877,14 @@ can appear before a future statement are:
877877
* blank lines, and
878878
* other future statements.
879879

880+
The only feature that requires using the future statement is
881+
``annotations`` (see :pep:`563`).
882+
880883
All historical features enabled by the future statement are still recognized
881884
by Python 3. The list includes ``absolute_import``, ``division``,
882885
``generators``, ``generator_stop``, ``unicode_literals``,
883-
``print_function``, ``nested_scopes``, ``with_statement`` and ``annotations``.
884-
They are all redundant because they are always enabled, and only kept for
886+
``print_function``, ``nested_scopes`` and ``with_statement``. They are
887+
all redundant because they are always enabled, and only kept for
885888
backwards compatibility.
886889

887890
A future statement is recognized and treated specially at compile time: Changes

Doc/whatsnew/3.10.rst

-16
Original file line numberDiff line numberDiff line change
@@ -624,22 +624,6 @@ This section covers major changes affecting :pep:`484` type annotations and
624624
the :mod:`typing` module.
625625
626626
627-
PEP 563: Postponed Evaluation of Annotations Becomes Default
628-
------------------------------------------------------------
629-
630-
In Python 3.7, postponed evaluation of annotations was added,
631-
to be enabled with a ``from __future__ import annotations``
632-
directive. In 3.10 this became the default behavior, even
633-
without that future directive. With this being default, all
634-
annotations stored in :attr:`__annotations__` will be strings.
635-
If needed, annotations can be resolved at runtime using
636-
:func:`typing.get_type_hints`. See :pep:`563` for a full
637-
description. Also, the :func:`inspect.signature` will try to
638-
resolve types from now on, and when it fails it will fall back to
639-
showing the string annotations. (Contributed by Batuhan Taskaya
640-
in :issue:`38605`.)
641-
642-
643627
PEP 604: New Type Union Operator
644628
--------------------------------
645629

Lib/dataclasses.py

+3-10
Original file line numberDiff line numberDiff line change
@@ -413,10 +413,8 @@ def _create_fn(name, args, body, *, globals=None, locals=None,
413413

414414
ns = {}
415415
exec(txt, globals, ns)
416-
func = ns['__create_fn__'](**locals)
417-
for arg, annotation in func.__annotations__.copy().items():
418-
func.__annotations__[arg] = locals[annotation]
419-
return func
416+
return ns['__create_fn__'](**locals)
417+
420418

421419
def _field_assign(frozen, name, value, self_name):
422420
# If we're a frozen class, then assign to our fields in __init__
@@ -667,11 +665,6 @@ def _is_type(annotation, cls, a_module, a_type, is_type_predicate):
667665
# a eval() penalty for every single field of every dataclass
668666
# that's defined. It was judged not worth it.
669667

670-
# Strip away the extra quotes as a result of double-stringifying when the
671-
# 'annotations' feature became default.
672-
if annotation.startswith(("'", '"')) and annotation.endswith(("'", '"')):
673-
annotation = annotation[1:-1]
674-
675668
match = _MODULE_IDENTIFIER_RE.match(annotation)
676669
if match:
677670
ns = None
@@ -1020,7 +1013,7 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen,
10201013
if not getattr(cls, '__doc__'):
10211014
# Create a class doc-string.
10221015
cls.__doc__ = (cls.__name__ +
1023-
str(inspect.signature(cls)).replace(' -> NoneType', ''))
1016+
str(inspect.signature(cls)).replace(' -> None', ''))
10241017

10251018
if match_args:
10261019
_set_new_attribute(cls, '__match_args__',

Lib/importlib/_bootstrap_external.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ def _write_atomic(path, data, mode=0o666):
349349
# Python 3.10a6 3434 (PEP 634: Structural Pattern Matching)
350350
# Python 3.10a7 3435 Use instruction offsets (as opposed to byte offsets).
351351
# Python 3.10b1 3436 (Add GEN_START bytecode #43683)
352+
# Python 3.10b1 3437 (Undo making 'annotations' future by default - We like to dance among core devs!)
352353

353354
#
354355
# MAGIC must change whenever the bytecode emitted by the compiler may no
@@ -358,7 +359,7 @@ def _write_atomic(path, data, mode=0o666):
358359
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
359360
# in PC/launcher.c must also be updated.
360361

361-
MAGIC_NUMBER = (3436).to_bytes(2, 'little') + b'\r\n'
362+
MAGIC_NUMBER = (3437).to_bytes(2, 'little') + b'\r\n'
362363
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
363364

364365
_PYCACHE = '__pycache__'

Lib/inspect.py

+2-17
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
import tokenize
4646
import token
4747
import types
48-
import typing
4948
import warnings
5049
import functools
5150
import builtins
@@ -1893,10 +1892,7 @@ def _signature_is_functionlike(obj):
18931892
code = getattr(obj, '__code__', None)
18941893
defaults = getattr(obj, '__defaults__', _void) # Important to use _void ...
18951894
kwdefaults = getattr(obj, '__kwdefaults__', _void) # ... and not None here
1896-
try:
1897-
annotations = _get_type_hints(obj)
1898-
except AttributeError:
1899-
annotations = None
1895+
annotations = getattr(obj, '__annotations__', None)
19001896

19011897
return (isinstance(code, types.CodeType) and
19021898
isinstance(name, str) and
@@ -2137,16 +2133,6 @@ def p(name_node, default_node, default=empty):
21372133

21382134
return cls(parameters, return_annotation=cls.empty)
21392135

2140-
def _get_type_hints(func, **kwargs):
2141-
try:
2142-
return typing.get_type_hints(func, **kwargs)
2143-
except Exception:
2144-
# First, try to use the get_type_hints to resolve
2145-
# annotations. But for keeping the behavior intact
2146-
# if there was a problem with that (like the namespace
2147-
# can't resolve some annotation) continue to use
2148-
# string annotations
2149-
return func.__annotations__
21502136

21512137
def _signature_from_builtin(cls, func, skip_bound_arg=True):
21522138
"""Private helper function to get signature for
@@ -2191,8 +2177,7 @@ def _signature_from_function(cls, func, skip_bound_arg=True,
21912177
positional = arg_names[:pos_count]
21922178
keyword_only_count = func_code.co_kwonlyargcount
21932179
keyword_only = arg_names[pos_count:pos_count + keyword_only_count]
2194-
annotations = _get_type_hints(func, globalns=globalns, localns=localns)
2195-
2180+
annotations = func.__annotations__
21962181
defaults = func.__defaults__
21972182
kwdefaults = func.__kwdefaults__
21982183

Lib/test/dataclass_module_1.py

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
#from __future__ import annotations
2+
USING_STRINGS = False
3+
4+
# dataclass_module_1.py and dataclass_module_1_str.py are identical
5+
# except only the latter uses string annotations.
6+
17
import dataclasses
28
import typing
39

Lib/test/dataclass_module_1_str.py

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from __future__ import annotations
2+
USING_STRINGS = True
3+
4+
# dataclass_module_1.py and dataclass_module_1_str.py are identical
5+
# except only the latter uses string annotations.
6+
7+
import dataclasses
8+
import typing
9+
10+
T_CV2 = typing.ClassVar[int]
11+
T_CV3 = typing.ClassVar
12+
13+
T_IV2 = dataclasses.InitVar[int]
14+
T_IV3 = dataclasses.InitVar
15+
16+
@dataclasses.dataclass
17+
class CV:
18+
T_CV4 = typing.ClassVar
19+
cv0: typing.ClassVar[int] = 20
20+
cv1: typing.ClassVar = 30
21+
cv2: T_CV2
22+
cv3: T_CV3
23+
not_cv4: T_CV4 # When using string annotations, this field is not recognized as a ClassVar.
24+
25+
@dataclasses.dataclass
26+
class IV:
27+
T_IV4 = dataclasses.InitVar
28+
iv0: dataclasses.InitVar[int]
29+
iv1: dataclasses.InitVar
30+
iv2: T_IV2
31+
iv3: T_IV3
32+
not_iv4: T_IV4 # When using string annotations, this field is not recognized as an InitVar.

Lib/test/dataclass_module_2.py

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
#from __future__ import annotations
2+
USING_STRINGS = False
3+
4+
# dataclass_module_2.py and dataclass_module_2_str.py are identical
5+
# except only the latter uses string annotations.
6+
17
from dataclasses import dataclass, InitVar
28
from typing import ClassVar
39

Lib/test/dataclass_module_2_str.py

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from __future__ import annotations
2+
USING_STRINGS = True
3+
4+
# dataclass_module_2.py and dataclass_module_2_str.py are identical
5+
# except only the latter uses string annotations.
6+
7+
from dataclasses import dataclass, InitVar
8+
from typing import ClassVar
9+
10+
T_CV2 = ClassVar[int]
11+
T_CV3 = ClassVar
12+
13+
T_IV2 = InitVar[int]
14+
T_IV3 = InitVar
15+
16+
@dataclass
17+
class CV:
18+
T_CV4 = ClassVar
19+
cv0: ClassVar[int] = 20
20+
cv1: ClassVar = 30
21+
cv2: T_CV2
22+
cv3: T_CV3
23+
not_cv4: T_CV4 # When using string annotations, this field is not recognized as a ClassVar.
24+
25+
@dataclass
26+
class IV:
27+
T_IV4 = InitVar
28+
iv0: InitVar[int]
29+
iv1: InitVar
30+
iv2: T_IV2
31+
iv3: T_IV3
32+
not_iv4: T_IV4 # When using string annotations, this field is not recognized as an InitVar.

Lib/test/dataclass_textanno.py

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations
2+
13
import dataclasses
24

35

0 commit comments

Comments
 (0)