1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
# This file is part of the lib3to6 project
# https://github.com/mbarkhau/lib3to6
#
# Copyright (c) 2019-2021 Manuel Barkhau (mbarkhau@gmail.com) - MIT License
# SPDX-License-Identifier: MIT
import ast
from . import common
from . import fixer_base as fb
class FutureImportFixerBase(fb.FixerBase):
future_name: str
def apply_fix(self, ctx: common.BuildContext, tree: ast.Module) -> ast.Module:
self.required_imports.add(common.ImportDecl("__future__", self.future_name, None))
return tree
class AnnotationsFutureFixer(FutureImportFixerBase):
version_info = common.VersionInfo(apply_since="3.7", apply_until="3.99")
future_name = "annotations"
class GeneratorStopFutureFixer(FutureImportFixerBase):
version_info = common.VersionInfo(apply_since="3.5", apply_until="3.6")
future_name = "generator_stop"
class UnicodeLiteralsFutureFixer(FutureImportFixerBase):
version_info = common.VersionInfo(apply_since="2.6", apply_until="2.7")
future_name = "unicode_literals"
class PrintFunctionFutureFixer(FutureImportFixerBase):
version_info = common.VersionInfo(apply_since="2.6", apply_until="2.7")
future_name = "print_function"
class WithStatementFutureFixer(FutureImportFixerBase):
version_info = common.VersionInfo(apply_since="2.5", apply_until="2.5")
future_name = "with_statement"
class AbsoluteImportFutureFixer(FutureImportFixerBase):
version_info = common.VersionInfo(apply_since="2.5", apply_until="2.7")
future_name = "absolute_import"
class DivisionFutureFixer(FutureImportFixerBase):
version_info = common.VersionInfo(apply_since="2.2", apply_until="2.7")
future_name = "division"
class GeneratorsFutureFixer(FutureImportFixerBase):
version_info = common.VersionInfo(apply_since="2.2", apply_until="2.2")
future_name = "generators"
class NestedScopesFutureFixer(FutureImportFixerBase):
version_info = common.VersionInfo(apply_since="2.1", apply_until="2.1")
future_name = "nested_scopes"
class RemoveUnsupportedFuturesFixer(fb.FixerBase):
version_info = common.VersionInfo(apply_since="2.0", apply_until="3.99")
def apply_fix(self, ctx: common.BuildContext, tree: ast.Module) -> ast.Module:
target_version = ctx.cfg.target_version
supported_futures = set()
for cls in FutureImportFixerBase.__subclasses__():
# pylint:disable=no-member; yes it does
if cls.version_info.is_compatible_with(target_version):
supported_futures.add(cls.future_name)
nodes_to_del = []
for i, node in enumerate(tree.body):
is_doc_string = isinstance(node, ast.Expr) and (
isinstance(node.value, (ast.Constant, ast.Str))
)
if is_doc_string:
continue
if not isinstance(node, ast.ImportFrom):
break
is_future_import = node.module == '__future__' and node.level == 0
if not is_future_import:
break
new_names = [alias for alias in node.names if alias.name in supported_futures]
if new_names == node.names:
continue
if not any(new_names):
nodes_to_del.append(i)
else:
node.names = new_names
for i in reversed(nodes_to_del):
del tree.body[i : i + 1]
return tree
|