Hide keyboard shortcuts

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 

6 

7import ast 

8 

9from . import common 

10from . import fixer_base as fb 

11 

12 

13class FutureImportFixerBase(fb.FixerBase): 

14 

15 future_name: str 

16 

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 

20 

21 

22class AnnotationsFutureFixer(FutureImportFixerBase): 

23 

24 version_info = common.VersionInfo(apply_since="3.7", apply_until="3.99") 

25 

26 future_name = "annotations" 

27 

28 

29class GeneratorStopFutureFixer(FutureImportFixerBase): 

30 

31 version_info = common.VersionInfo(apply_since="3.5", apply_until="3.6") 

32 

33 future_name = "generator_stop" 

34 

35 

36class UnicodeLiteralsFutureFixer(FutureImportFixerBase): 

37 

38 version_info = common.VersionInfo(apply_since="2.6", apply_until="2.7") 

39 

40 future_name = "unicode_literals" 

41 

42 

43class PrintFunctionFutureFixer(FutureImportFixerBase): 

44 

45 version_info = common.VersionInfo(apply_since="2.6", apply_until="2.7") 

46 

47 future_name = "print_function" 

48 

49 

50class WithStatementFutureFixer(FutureImportFixerBase): 

51 

52 version_info = common.VersionInfo(apply_since="2.5", apply_until="2.5") 

53 

54 future_name = "with_statement" 

55 

56 

57class AbsoluteImportFutureFixer(FutureImportFixerBase): 

58 

59 version_info = common.VersionInfo(apply_since="2.5", apply_until="2.7") 

60 

61 future_name = "absolute_import" 

62 

63 

64class DivisionFutureFixer(FutureImportFixerBase): 

65 

66 version_info = common.VersionInfo(apply_since="2.2", apply_until="2.7") 

67 

68 future_name = "division" 

69 

70 

71class GeneratorsFutureFixer(FutureImportFixerBase): 

72 

73 version_info = common.VersionInfo(apply_since="2.2", apply_until="2.2") 

74 

75 future_name = "generators" 

76 

77 

78class NestedScopesFutureFixer(FutureImportFixerBase): 

79 

80 version_info = common.VersionInfo(apply_since="2.1", apply_until="2.1") 

81 

82 future_name = "nested_scopes" 

83 

84 

85class RemoveUnsupportedFuturesFixer(fb.FixerBase): 

86 

87 version_info = common.VersionInfo(apply_since="2.0", apply_until="3.99") 

88 

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) 

96 

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 

104 

105 if not isinstance(node, ast.ImportFrom): 

106 break 

107 

108 is_future_import = node.module == '__future__' and node.level == 0 

109 if not is_future_import: 

110 break 

111 

112 new_names = [alias for alias in node.names if alias.name in supported_futures] 

113 if new_names == node.names: 

114 continue 

115 

116 if not any(new_names): 

117 nodes_to_del.append(i) 

118 else: 

119 node.names = new_names 

120 

121 for i in reversed(nodes_to_del): 

122 del tree.body[i : i + 1] 

123 

124 return tree