Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# This file is part of the lib3to6 project
2# https://github.com/mbarkhau/lib3to6
3#
4# Copyright (c) 2019-2021 Manuel Barkhau (mbarkhau@gmail.com) - MIT License
5# SPDX-License-Identifier: MIT
7import ast
9from . import common
10from . import fixer_base as fb
13class FutureImportFixerBase(fb.FixerBase):
15 future_name: str
17 def apply_fix(self, ctx: common.BuildContext, tree: ast.Module) -> ast.Module:
18 self.required_imports.add(common.ImportDecl("__future__", self.future_name, None))
19 return tree
22class AnnotationsFutureFixer(FutureImportFixerBase):
24 version_info = common.VersionInfo(apply_since="3.7", apply_until="3.99")
26 future_name = "annotations"
29class GeneratorStopFutureFixer(FutureImportFixerBase):
31 version_info = common.VersionInfo(apply_since="3.5", apply_until="3.6")
33 future_name = "generator_stop"
36class UnicodeLiteralsFutureFixer(FutureImportFixerBase):
38 version_info = common.VersionInfo(apply_since="2.6", apply_until="2.7")
40 future_name = "unicode_literals"
43class PrintFunctionFutureFixer(FutureImportFixerBase):
45 version_info = common.VersionInfo(apply_since="2.6", apply_until="2.7")
47 future_name = "print_function"
50class WithStatementFutureFixer(FutureImportFixerBase):
52 version_info = common.VersionInfo(apply_since="2.5", apply_until="2.5")
54 future_name = "with_statement"
57class AbsoluteImportFutureFixer(FutureImportFixerBase):
59 version_info = common.VersionInfo(apply_since="2.5", apply_until="2.7")
61 future_name = "absolute_import"
64class DivisionFutureFixer(FutureImportFixerBase):
66 version_info = common.VersionInfo(apply_since="2.2", apply_until="2.7")
68 future_name = "division"
71class GeneratorsFutureFixer(FutureImportFixerBase):
73 version_info = common.VersionInfo(apply_since="2.2", apply_until="2.2")
75 future_name = "generators"
78class NestedScopesFutureFixer(FutureImportFixerBase):
80 version_info = common.VersionInfo(apply_since="2.1", apply_until="2.1")
82 future_name = "nested_scopes"
85class RemoveUnsupportedFuturesFixer(fb.FixerBase):
87 version_info = common.VersionInfo(apply_since="2.0", apply_until="3.99")
89 def apply_fix(self, ctx: common.BuildContext, tree: ast.Module) -> ast.Module:
90 target_version = ctx.cfg.target_version
91 supported_futures = set()
92 for cls in FutureImportFixerBase.__subclasses__():
93 # pylint:disable=no-member; yes it does
94 if cls.version_info.is_compatible_with(target_version):
95 supported_futures.add(cls.future_name)
97 nodes_to_del = []
98 for i, node in enumerate(tree.body):
99 is_doc_string = isinstance(node, ast.Expr) and (
100 isinstance(node.value, (ast.Constant, ast.Str))
101 )
102 if is_doc_string:
103 continue
105 if not isinstance(node, ast.ImportFrom):
106 break
108 is_future_import = node.module == '__future__' and node.level == 0
109 if not is_future_import:
110 break
112 new_names = [alias for alias in node.names if alias.name in supported_futures]
113 if new_names == node.names:
114 continue
116 if not any(new_names):
117 nodes_to_del.append(i)
118 else:
119 node.names = new_names
121 for i in reversed(nodes_to_del):
122 del tree.body[i : i + 1]
124 return tree