python-minifier 2.11.2__py2-none-any.whl → 2.11.3__py2-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- python_minifier/__init__.py +12 -8
- python_minifier/__init__.pyi +6 -1
- python_minifier/__main__.py +10 -7
- python_minifier/ast_annotation/__init__.py +82 -0
- python_minifier/ast_compare.py +1 -3
- python_minifier/ast_compat.py +38 -0
- python_minifier/ast_printer.py +8 -5
- python_minifier/expression_printer.py +14 -13
- python_minifier/f_string.py +13 -14
- python_minifier/ministring.py +3 -3
- python_minifier/module_printer.py +13 -14
- python_minifier/rename/__init__.py +1 -1
- python_minifier/rename/bind_names.py +2 -1
- python_minifier/rename/binding.py +39 -40
- python_minifier/rename/mapper.py +66 -50
- python_minifier/rename/rename_literals.py +17 -15
- python_minifier/rename/renamer.py +26 -28
- python_minifier/rename/resolve_names.py +8 -7
- python_minifier/rename/util.py +7 -5
- python_minifier/token_printer.py +3 -0
- python_minifier/transforms/combine_imports.py +0 -1
- python_minifier/transforms/constant_folding.py +16 -10
- python_minifier/transforms/remove_annotations.py +18 -16
- python_minifier/transforms/remove_annotations_options.py +3 -1
- python_minifier/transforms/remove_annotations_options.pyi +8 -7
- python_minifier/transforms/remove_asserts.py +1 -2
- python_minifier/transforms/remove_debug.py +4 -3
- python_minifier/transforms/remove_exception_brackets.py +12 -7
- python_minifier/transforms/remove_explicit_return_none.py +5 -4
- python_minifier/transforms/remove_literal_statements.py +5 -6
- python_minifier/transforms/remove_object_base.py +2 -1
- python_minifier/transforms/remove_pass.py +1 -2
- python_minifier/transforms/remove_posargs.py +3 -4
- python_minifier/transforms/suite_transformer.py +6 -5
- python_minifier/util.py +12 -18
- {python_minifier-2.11.2.dist-info → python_minifier-2.11.3.dist-info}/METADATA +1 -1
- python_minifier-2.11.3.dist-info/RECORD +45 -0
- python_minifier-2.11.2.dist-info/RECORD +0 -44
- {python_minifier-2.11.2.dist-info → python_minifier-2.11.3.dist-info}/LICENSE +0 -0
- {python_minifier-2.11.2.dist-info → python_minifier-2.11.3.dist-info}/WHEEL +0 -0
- {python_minifier-2.11.2.dist-info → python_minifier-2.11.3.dist-info}/entry_points.txt +0 -0
- {python_minifier-2.11.2.dist-info → python_minifier-2.11.3.dist-info}/top_level.txt +0 -0
- {python_minifier-2.11.2.dist-info → python_minifier-2.11.3.dist-info}/zip-safe +0 -0
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import python_minifier.ast_compat as ast
|
|
2
|
+
from python_minifier.ast_annotation import get_parent, set_parent
|
|
2
3
|
|
|
3
4
|
from python_minifier.rename.binding import Binding
|
|
4
5
|
from python_minifier.rename.util import insert
|
|
5
6
|
from python_minifier.transforms.suite_transformer import NodeVisitor
|
|
6
|
-
from python_minifier.util import
|
|
7
|
+
from python_minifier.util import is_constant_node
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
def replace(old_node, new_node):
|
|
10
|
-
parent = old_node
|
|
11
|
-
new_node
|
|
11
|
+
parent = get_parent(old_node)
|
|
12
|
+
set_parent(new_node, parent)
|
|
12
13
|
new_node.namespace = old_node.namespace
|
|
13
14
|
|
|
14
15
|
for field, old_value in ast.iter_fields(parent):
|
|
@@ -43,7 +44,7 @@ class HoistedBinding(Binding):
|
|
|
43
44
|
|
|
44
45
|
@property
|
|
45
46
|
def value(self):
|
|
46
|
-
if
|
|
47
|
+
if is_constant_node(self._value_node, (ast.Str, ast.Bytes)):
|
|
47
48
|
return self._value_node.s
|
|
48
49
|
else:
|
|
49
50
|
return self._value_node.value
|
|
@@ -84,6 +85,7 @@ class HoistedBinding(Binding):
|
|
|
84
85
|
|
|
85
86
|
return rename_cost <= current_cost
|
|
86
87
|
|
|
88
|
+
|
|
87
89
|
class HoistedValue(object):
|
|
88
90
|
"""
|
|
89
91
|
HoistedValue comparator object
|
|
@@ -132,7 +134,7 @@ class HoistLiterals(NodeVisitor):
|
|
|
132
134
|
|
|
133
135
|
"""
|
|
134
136
|
|
|
135
|
-
if
|
|
137
|
+
if isinstance(node.namespace, (ast.FunctionDef, ast.Module, ast.AsyncFunctionDef)):
|
|
136
138
|
return node.namespace
|
|
137
139
|
return self.nearest_function_namespace(node.namespace)
|
|
138
140
|
|
|
@@ -154,18 +156,18 @@ class HoistLiterals(NodeVisitor):
|
|
|
154
156
|
|
|
155
157
|
"""
|
|
156
158
|
|
|
157
|
-
|
|
159
|
+
path = []
|
|
158
160
|
|
|
159
161
|
while True:
|
|
160
162
|
namespace = self.nearest_function_namespace(node)
|
|
161
|
-
|
|
163
|
+
path.insert(0, namespace)
|
|
162
164
|
|
|
163
165
|
if isinstance(namespace, ast.Module):
|
|
164
166
|
break
|
|
165
167
|
|
|
166
168
|
node = namespace
|
|
167
169
|
|
|
168
|
-
return
|
|
170
|
+
return path
|
|
169
171
|
|
|
170
172
|
def common_path(self, n1_path, n2_path):
|
|
171
173
|
|
|
@@ -201,7 +203,7 @@ class HoistLiterals(NodeVisitor):
|
|
|
201
203
|
|
|
202
204
|
def visit_Str(self, node):
|
|
203
205
|
|
|
204
|
-
if isinstance(node
|
|
206
|
+
if isinstance(get_parent(node), ast.Expr):
|
|
205
207
|
# This is literal statement
|
|
206
208
|
# The RemoveLiteralStatements transformer must have left it here, so ignore it.
|
|
207
209
|
return
|
|
@@ -213,11 +215,10 @@ class HoistLiterals(NodeVisitor):
|
|
|
213
215
|
|
|
214
216
|
def visit_JoinedStr(self, node):
|
|
215
217
|
for v in node.values:
|
|
216
|
-
if
|
|
218
|
+
if is_constant_node(v, ast.Str):
|
|
217
219
|
# Can't hoist this!
|
|
218
220
|
continue
|
|
219
|
-
|
|
220
|
-
self.visit(v)
|
|
221
|
+
self.visit(v)
|
|
221
222
|
|
|
222
223
|
def visit_NameConstant(self, node):
|
|
223
224
|
self.get_binding(node.value, node).add_reference(node)
|
|
@@ -235,15 +236,16 @@ class HoistLiterals(NodeVisitor):
|
|
|
235
236
|
if not self._ignore_slots:
|
|
236
237
|
return self.generic_visit(node)
|
|
237
238
|
|
|
238
|
-
if not
|
|
239
|
+
if not isinstance(node.namespace, ast.ClassDef):
|
|
239
240
|
return self.generic_visit(node)
|
|
240
241
|
|
|
241
242
|
for target in node.targets:
|
|
242
|
-
if
|
|
243
|
+
if isinstance(target, ast.Name) and target.id == '__slots__':
|
|
243
244
|
# This is a __slots__ assignment, don't hoist the literals
|
|
244
|
-
return
|
|
245
|
+
return None
|
|
245
246
|
|
|
246
247
|
return self.generic_visit(node)
|
|
247
248
|
|
|
249
|
+
|
|
248
250
|
def rename_literals(module):
|
|
249
251
|
HoistLiterals()(module)
|
|
@@ -55,7 +55,7 @@ def reservation_scope(namespace, binding):
|
|
|
55
55
|
|
|
56
56
|
"""
|
|
57
57
|
|
|
58
|
-
namespaces =
|
|
58
|
+
namespaces = {namespace}
|
|
59
59
|
|
|
60
60
|
for node in binding.references:
|
|
61
61
|
while node is not namespace:
|
|
@@ -112,7 +112,7 @@ class UniqueNameAssigner(object):
|
|
|
112
112
|
def __call__(self, module):
|
|
113
113
|
assert isinstance(module, ast.Module)
|
|
114
114
|
|
|
115
|
-
for
|
|
115
|
+
for _namespace, binding in sorted_bindings(module):
|
|
116
116
|
if binding.allow_rename:
|
|
117
117
|
binding.new_name = self.available_name()
|
|
118
118
|
|
|
@@ -154,6 +154,8 @@ class NameAssigner(object):
|
|
|
154
154
|
if self.is_available(prefix + name, reservation_scope):
|
|
155
155
|
return prefix + name
|
|
156
156
|
|
|
157
|
+
return None
|
|
158
|
+
|
|
157
159
|
def is_available(self, name, reservation_scope):
|
|
158
160
|
"""
|
|
159
161
|
Is a name unreserved in a reservation scope
|
|
@@ -165,11 +167,7 @@ class NameAssigner(object):
|
|
|
165
167
|
|
|
166
168
|
"""
|
|
167
169
|
|
|
168
|
-
for namespace in reservation_scope
|
|
169
|
-
if name in namespace.assigned_names:
|
|
170
|
-
return False
|
|
171
|
-
|
|
172
|
-
return True
|
|
170
|
+
return all(name not in namespace.assigned_names for namespace in reservation_scope)
|
|
173
171
|
|
|
174
172
|
def __call__(self, module, prefix_globals, reserved_globals=None):
|
|
175
173
|
assert isinstance(module, ast.Module)
|
|
@@ -184,6 +182,26 @@ class NameAssigner(object):
|
|
|
184
182
|
for name in reserved_globals:
|
|
185
183
|
module.assigned_names.add(name)
|
|
186
184
|
|
|
185
|
+
def should_rename(binding, name, scope):
|
|
186
|
+
if binding.should_rename(name):
|
|
187
|
+
return True
|
|
188
|
+
|
|
189
|
+
# It's no longer efficient to do this rename
|
|
190
|
+
|
|
191
|
+
if isinstance(binding, NameBinding):
|
|
192
|
+
# Check that the original name is still available
|
|
193
|
+
|
|
194
|
+
if binding.reserved == binding.name:
|
|
195
|
+
# We already reserved it (this is probably an arg)
|
|
196
|
+
return False
|
|
197
|
+
|
|
198
|
+
if not self.is_available(binding.name, scope):
|
|
199
|
+
# The original name has already been assigned to another binding,
|
|
200
|
+
# so we need to rename this anyway.
|
|
201
|
+
return True
|
|
202
|
+
|
|
203
|
+
return False
|
|
204
|
+
|
|
187
205
|
for namespace, binding in sorted_bindings(module):
|
|
188
206
|
scope = reservation_scope(namespace, binding)
|
|
189
207
|
|
|
@@ -194,27 +212,7 @@ class NameAssigner(object):
|
|
|
194
212
|
else:
|
|
195
213
|
name = self.available_name(scope)
|
|
196
214
|
|
|
197
|
-
|
|
198
|
-
if binding.should_rename(name):
|
|
199
|
-
return True
|
|
200
|
-
|
|
201
|
-
# It's no longer efficient to do this rename
|
|
202
|
-
|
|
203
|
-
if isinstance(binding, NameBinding):
|
|
204
|
-
# Check that the original name is still available
|
|
205
|
-
|
|
206
|
-
if binding.reserved == binding.name:
|
|
207
|
-
# We already reserved it (this is probably an arg)
|
|
208
|
-
return False
|
|
209
|
-
|
|
210
|
-
if not self.is_available(binding.name, scope):
|
|
211
|
-
# The original name has already been assigned to another binding,
|
|
212
|
-
# so we need to rename this anyway.
|
|
213
|
-
return True
|
|
214
|
-
|
|
215
|
-
return False
|
|
216
|
-
|
|
217
|
-
if should_rename():
|
|
215
|
+
if should_rename(binding, name, scope):
|
|
218
216
|
binding.rename(name)
|
|
219
217
|
else:
|
|
220
218
|
# Any existing name will become reserved
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import python_minifier.ast_compat as ast
|
|
2
2
|
|
|
3
3
|
from python_minifier.rename.binding import BuiltinBinding, NameBinding
|
|
4
|
-
from python_minifier.rename.util import get_global_namespace, get_nonlocal_namespace
|
|
5
|
-
from python_minifier.util import is_ast_node
|
|
4
|
+
from python_minifier.rename.util import builtins, get_global_namespace, get_nonlocal_namespace
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
def get_binding(name, namespace):
|
|
@@ -34,6 +33,7 @@ def get_binding(name, namespace):
|
|
|
34
33
|
namespace.bindings.append(binding)
|
|
35
34
|
return binding
|
|
36
35
|
|
|
36
|
+
|
|
37
37
|
def get_binding_disallow_class_namespace_rename(name, namespace):
|
|
38
38
|
binding = get_binding(name, namespace)
|
|
39
39
|
|
|
@@ -43,6 +43,7 @@ def get_binding_disallow_class_namespace_rename(name, namespace):
|
|
|
43
43
|
|
|
44
44
|
return binding
|
|
45
45
|
|
|
46
|
+
|
|
46
47
|
def resolve_names(node):
|
|
47
48
|
"""
|
|
48
49
|
Resolve unbound names to a NameBinding
|
|
@@ -65,7 +66,7 @@ def resolve_names(node):
|
|
|
65
66
|
binding = get_binding_disallow_class_namespace_rename(node.name, node.namespace)
|
|
66
67
|
binding.add_reference(node)
|
|
67
68
|
|
|
68
|
-
elif
|
|
69
|
+
elif isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) and node.name in node.namespace.nonlocal_names:
|
|
69
70
|
binding = get_binding_disallow_class_namespace_rename(node.name, node.namespace)
|
|
70
71
|
binding.add_reference(node)
|
|
71
72
|
|
|
@@ -91,15 +92,15 @@ def resolve_names(node):
|
|
|
91
92
|
if isinstance(node.name, str) and node.name in node.namespace.nonlocal_names:
|
|
92
93
|
get_binding_disallow_class_namespace_rename(node.name, node.namespace).add_reference(node)
|
|
93
94
|
|
|
94
|
-
elif
|
|
95
|
+
elif isinstance(node, ast.Nonlocal):
|
|
95
96
|
for name in node.names:
|
|
96
97
|
get_binding_disallow_class_namespace_rename(name, node.namespace).add_reference(node)
|
|
97
|
-
elif
|
|
98
|
+
elif isinstance(node, (ast.MatchAs, ast.MatchStar)) and node.name in node.namespace.nonlocal_names:
|
|
98
99
|
get_binding_disallow_class_namespace_rename(node.name, node.namespace).add_reference(node)
|
|
99
|
-
elif
|
|
100
|
+
elif isinstance(node, ast.MatchMapping) and node.rest in node.namespace.nonlocal_names:
|
|
100
101
|
get_binding_disallow_class_namespace_rename(node.rest, node.namespace).add_reference(node)
|
|
101
102
|
|
|
102
|
-
elif
|
|
103
|
+
elif isinstance(node, ast.Exec):
|
|
103
104
|
get_global_namespace(node).tainted = True
|
|
104
105
|
|
|
105
106
|
for child in ast.iter_child_nodes(node):
|
python_minifier/rename/util.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import python_minifier.ast_compat as ast
|
|
2
1
|
import sys
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
import python_minifier.ast_compat as ast
|
|
4
|
+
|
|
5
|
+
from python_minifier.util import is_constant_node
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
def create_is_namespace():
|
|
@@ -32,6 +33,7 @@ def iter_child_namespaces(node):
|
|
|
32
33
|
for c in iter_child_namespaces(child):
|
|
33
34
|
yield c
|
|
34
35
|
|
|
36
|
+
|
|
35
37
|
def get_global_namespace(node):
|
|
36
38
|
"""
|
|
37
39
|
Return the global namespace for a node
|
|
@@ -125,7 +127,7 @@ def insert(suite, new_node):
|
|
|
125
127
|
|
|
126
128
|
if not inserted:
|
|
127
129
|
if (isinstance(node, ast.ImportFrom) and node.module == '__future__') or (
|
|
128
|
-
isinstance(node, ast.Expr) and
|
|
130
|
+
isinstance(node, ast.Expr) and is_constant_node(node.value, ast.Str)
|
|
129
131
|
):
|
|
130
132
|
pass
|
|
131
133
|
else:
|
|
@@ -164,7 +166,7 @@ def find__all__(module):
|
|
|
164
166
|
if isinstance(name, ast.Name) and name.id == '__all__':
|
|
165
167
|
return True
|
|
166
168
|
|
|
167
|
-
elif
|
|
169
|
+
elif isinstance(node, (ast.AugAssign, ast.AnnAssign)):
|
|
168
170
|
if isinstance(node.target, ast.Name) and node.target.id == '__all__':
|
|
169
171
|
return True
|
|
170
172
|
|
|
@@ -178,7 +180,7 @@ def find__all__(module):
|
|
|
178
180
|
continue
|
|
179
181
|
|
|
180
182
|
for el in node.value.elts:
|
|
181
|
-
if
|
|
183
|
+
if is_constant_node(el, ast.Str):
|
|
182
184
|
names.append(el.s)
|
|
183
185
|
|
|
184
186
|
return names
|
python_minifier/token_printer.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import re
|
|
4
4
|
import sys
|
|
5
5
|
|
|
6
|
+
|
|
6
7
|
class TokenTypes(object):
|
|
7
8
|
NoToken = 0
|
|
8
9
|
Identifier = 1
|
|
@@ -15,6 +16,7 @@ class TokenTypes(object):
|
|
|
15
16
|
NewLine = 8
|
|
16
17
|
EndStatement = 9
|
|
17
18
|
|
|
19
|
+
|
|
18
20
|
class Delimiter(object):
|
|
19
21
|
def __init__(self, terminal_printer, delimiter=',', add_parens=False):
|
|
20
22
|
"""
|
|
@@ -74,6 +76,7 @@ class Delimiter(object):
|
|
|
74
76
|
else:
|
|
75
77
|
self._terminal_printer.delimiter(self._delimiter)
|
|
76
78
|
|
|
79
|
+
|
|
77
80
|
class TokenPrinter(object):
|
|
78
81
|
"""
|
|
79
82
|
Concatenates terminal symbols of the python grammar
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import python_minifier.ast_compat as ast
|
|
2
1
|
import math
|
|
3
2
|
import sys
|
|
4
3
|
|
|
4
|
+
import python_minifier.ast_compat as ast
|
|
5
|
+
from python_minifier.ast_annotation import get_parent
|
|
6
|
+
|
|
5
7
|
from python_minifier.ast_compare import compare_ast
|
|
6
8
|
from python_minifier.expression_printer import ExpressionPrinter
|
|
7
9
|
from python_minifier.transforms.suite_transformer import SuiteTransformer
|
|
8
|
-
from python_minifier.util import
|
|
10
|
+
from python_minifier.util import is_constant_node
|
|
11
|
+
|
|
9
12
|
|
|
10
13
|
class FoldConstants(SuiteTransformer):
|
|
11
14
|
"""
|
|
@@ -22,9 +25,9 @@ class FoldConstants(SuiteTransformer):
|
|
|
22
25
|
|
|
23
26
|
# Check this is a constant expression that could be folded
|
|
24
27
|
# We don't try to fold strings or bytes, since they have probably been arranged this way to make the source shorter and we are unlikely to beat that
|
|
25
|
-
if not
|
|
28
|
+
if not is_constant_node(node.left, (ast.Num, ast.NameConstant)):
|
|
26
29
|
return node
|
|
27
|
-
if not
|
|
30
|
+
if not is_constant_node(node.right, (ast.Num, ast.NameConstant)):
|
|
28
31
|
return node
|
|
29
32
|
|
|
30
33
|
if isinstance(node.op, ast.Div):
|
|
@@ -68,7 +71,7 @@ class FoldConstants(SuiteTransformer):
|
|
|
68
71
|
try:
|
|
69
72
|
folded_expression = unparse_expression(new_node)
|
|
70
73
|
folded_value = safe_eval(folded_expression)
|
|
71
|
-
except Exception
|
|
74
|
+
except Exception:
|
|
72
75
|
# This can happen if the value is too large to be represented as a literal
|
|
73
76
|
# or if the value is unparsed as nan, inf or -inf - which are not valid python literals
|
|
74
77
|
return node
|
|
@@ -91,7 +94,8 @@ class FoldConstants(SuiteTransformer):
|
|
|
91
94
|
return node
|
|
92
95
|
|
|
93
96
|
# New representation is shorter and has the same value, so use it
|
|
94
|
-
return self.add_child(new_node, node
|
|
97
|
+
return self.add_child(new_node, get_parent(node), node.namespace)
|
|
98
|
+
|
|
95
99
|
|
|
96
100
|
def equal_value_and_type(a, b):
|
|
97
101
|
if type(a) != type(b):
|
|
@@ -102,13 +106,15 @@ def equal_value_and_type(a, b):
|
|
|
102
106
|
|
|
103
107
|
return a == b
|
|
104
108
|
|
|
109
|
+
|
|
105
110
|
def safe_eval(expression):
|
|
106
|
-
|
|
107
|
-
|
|
111
|
+
empty_globals = {}
|
|
112
|
+
empty_locals = {}
|
|
108
113
|
|
|
109
114
|
# This will return the value, or could raise an exception
|
|
110
|
-
return eval(expression,
|
|
115
|
+
return eval(expression, empty_globals, empty_locals)
|
|
116
|
+
|
|
111
117
|
|
|
112
118
|
def unparse_expression(node):
|
|
113
119
|
expression_printer = ExpressionPrinter()
|
|
114
|
-
return expression_printer(node)
|
|
120
|
+
return expression_printer(node)
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import python_minifier.ast_compat as ast
|
|
2
1
|
import sys
|
|
3
2
|
|
|
3
|
+
import python_minifier.ast_compat as ast
|
|
4
|
+
from python_minifier.ast_annotation import get_parent
|
|
5
|
+
|
|
4
6
|
from python_minifier.transforms.remove_annotations_options import RemoveAnnotationsOptions
|
|
5
7
|
from python_minifier.transforms.suite_transformer import SuiteTransformer
|
|
6
8
|
|
|
@@ -71,20 +73,20 @@ class RemoveAnnotations(SuiteTransformer):
|
|
|
71
73
|
if sys.version_info < (3, 7):
|
|
72
74
|
return False
|
|
73
75
|
|
|
74
|
-
if not isinstance(node
|
|
76
|
+
if not isinstance(get_parent(node), ast.ClassDef):
|
|
75
77
|
return False
|
|
76
78
|
|
|
77
|
-
if len(node.
|
|
79
|
+
if len(get_parent(node).decorator_list) == 0:
|
|
78
80
|
return False
|
|
79
81
|
|
|
80
|
-
for
|
|
81
|
-
if isinstance(
|
|
82
|
+
for decorator_node in get_parent(node).decorator_list:
|
|
83
|
+
if isinstance(decorator_node, ast.Name) and decorator_node.id == 'dataclass':
|
|
82
84
|
return True
|
|
83
|
-
elif isinstance(
|
|
85
|
+
elif isinstance(decorator_node, ast.Attribute) and decorator_node.attr == 'dataclass':
|
|
84
86
|
return True
|
|
85
|
-
elif isinstance(
|
|
87
|
+
elif isinstance(decorator_node, ast.Call) and isinstance(decorator_node.func, ast.Name) and decorator_node.func.id == 'dataclass':
|
|
86
88
|
return True
|
|
87
|
-
elif isinstance(
|
|
89
|
+
elif isinstance(decorator_node, ast.Call) and isinstance(decorator_node.func, ast.Attribute) and decorator_node.func.attr == 'dataclass':
|
|
88
90
|
return True
|
|
89
91
|
|
|
90
92
|
return False
|
|
@@ -93,24 +95,24 @@ class RemoveAnnotations(SuiteTransformer):
|
|
|
93
95
|
if sys.version_info < (3, 5):
|
|
94
96
|
return False
|
|
95
97
|
|
|
96
|
-
if not isinstance(node
|
|
98
|
+
if not isinstance(get_parent(node), ast.ClassDef):
|
|
97
99
|
return False
|
|
98
100
|
|
|
99
|
-
if len(node.
|
|
101
|
+
if len(get_parent(node).bases) == 0:
|
|
100
102
|
return False
|
|
101
103
|
|
|
102
104
|
tricky_types = ['NamedTuple', 'TypedDict']
|
|
103
105
|
|
|
104
|
-
for
|
|
105
|
-
if isinstance(
|
|
106
|
+
for base_node in get_parent(node).bases:
|
|
107
|
+
if isinstance(base_node, ast.Name) and base_node.id in tricky_types:
|
|
106
108
|
return True
|
|
107
|
-
elif isinstance(
|
|
109
|
+
elif isinstance(base_node, ast.Attribute) and base_node.attr in tricky_types:
|
|
108
110
|
return True
|
|
109
111
|
|
|
110
112
|
return False
|
|
111
113
|
|
|
112
114
|
# is this a class attribute or a variable?
|
|
113
|
-
if isinstance(node
|
|
115
|
+
if isinstance(get_parent(node), ast.ClassDef):
|
|
114
116
|
if not self._options.remove_class_attribute_annotations:
|
|
115
117
|
return node
|
|
116
118
|
else:
|
|
@@ -120,11 +122,11 @@ class RemoveAnnotations(SuiteTransformer):
|
|
|
120
122
|
if is_dataclass_field(node) or is_typing_sensitive(node):
|
|
121
123
|
return node
|
|
122
124
|
elif node.value:
|
|
123
|
-
return self.add_child(ast.Assign([node.target], node.value), parent=node
|
|
125
|
+
return self.add_child(ast.Assign([node.target], node.value), parent=get_parent(node), namespace=node.namespace)
|
|
124
126
|
else:
|
|
125
127
|
# Valueless annotations cause the interpreter to treat the variable as a local.
|
|
126
128
|
# I don't know of another way to do that without assigning to it, so
|
|
127
129
|
# keep it as an AnnAssign, but replace the annotation with '0'
|
|
128
130
|
|
|
129
|
-
node.annotation = self.add_child(ast.Num(0), parent=node
|
|
131
|
+
node.annotation = self.add_child(ast.Num(0), parent=get_parent(node), namespace=node.namespace)
|
|
130
132
|
return node
|
|
@@ -26,7 +26,9 @@ class RemoveAnnotationsOptions(object):
|
|
|
26
26
|
self.remove_class_attribute_annotations = remove_class_attribute_annotations
|
|
27
27
|
|
|
28
28
|
def __repr__(self):
|
|
29
|
-
return 'RemoveAnnotationsOptions(remove_variable_annotations=%r, remove_return_annotations=%r, remove_argument_annotations=%r, remove_class_attribute_annotations=%r)' % (
|
|
29
|
+
return 'RemoveAnnotationsOptions(remove_variable_annotations=%r, remove_return_annotations=%r, remove_argument_annotations=%r, remove_class_attribute_annotations=%r)' % (
|
|
30
|
+
self.remove_variable_annotations, self.remove_return_annotations, self.remove_argument_annotations, self.remove_class_attribute_annotations
|
|
31
|
+
)
|
|
30
32
|
|
|
31
33
|
def __nonzero__(self):
|
|
32
34
|
return any((self.remove_variable_annotations, self.remove_return_annotations, self.remove_argument_annotations, self.remove_class_attribute_annotations))
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
class RemoveAnnotationsOptions:
|
|
2
|
-
|
|
3
2
|
remove_variable_annotations: bool
|
|
4
3
|
remove_return_annotations: bool
|
|
5
4
|
remove_argument_annotations: bool
|
|
6
5
|
remove_class_attribute_annotations: bool
|
|
7
6
|
|
|
8
|
-
def __init__(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
def __init__(
|
|
8
|
+
self,
|
|
9
|
+
remove_variable_annotations: bool = ...,
|
|
10
|
+
remove_return_annotations: bool = ...,
|
|
11
|
+
remove_argument_annotations: bool = ...,
|
|
12
|
+
remove_class_attribute_annotations: bool = ...
|
|
13
|
+
):
|
|
13
14
|
...
|
|
14
15
|
|
|
15
|
-
def __repr__(self) -> str: ...
|
|
16
16
|
def __nonzero__(self) -> bool: ...
|
|
17
|
+
|
|
17
18
|
def __bool__(self) -> bool: ...
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import python_minifier.ast_compat as ast
|
|
2
2
|
|
|
3
3
|
from python_minifier.transforms.suite_transformer import SuiteTransformer
|
|
4
|
-
from python_minifier.util import is_ast_node
|
|
5
4
|
|
|
6
5
|
|
|
7
6
|
class RemoveAsserts(SuiteTransformer):
|
|
@@ -15,7 +14,7 @@ class RemoveAsserts(SuiteTransformer):
|
|
|
15
14
|
return self.visit(node)
|
|
16
15
|
|
|
17
16
|
def suite(self, node_list, parent):
|
|
18
|
-
without_assert = [self.visit(a) for a in filter(lambda n: not
|
|
17
|
+
without_assert = [self.visit(a) for a in filter(lambda n: not isinstance(n, ast.Assert), node_list)]
|
|
19
18
|
|
|
20
19
|
if len(without_assert) == 0:
|
|
21
20
|
if isinstance(parent, ast.Module):
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import python_minifier.ast_compat as ast
|
|
2
1
|
import sys
|
|
3
2
|
|
|
3
|
+
import python_minifier.ast_compat as ast
|
|
4
|
+
|
|
4
5
|
from python_minifier.transforms.suite_transformer import SuiteTransformer
|
|
5
|
-
from python_minifier.util import
|
|
6
|
+
from python_minifier.util import is_constant_node
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class RemoveDebug(SuiteTransformer):
|
|
@@ -18,7 +19,7 @@ class RemoveDebug(SuiteTransformer):
|
|
|
18
19
|
def constant_value(self, node):
|
|
19
20
|
if sys.version_info < (3, 4):
|
|
20
21
|
return node.id == 'True'
|
|
21
|
-
elif
|
|
22
|
+
elif is_constant_node(node, ast.NameConstant):
|
|
22
23
|
return node.value
|
|
23
24
|
return None
|
|
24
25
|
|
|
@@ -8,11 +8,14 @@ When printed, this essentially removes the brackets from the exception name.
|
|
|
8
8
|
We can't generally know if a name refers to an exception, so we only do this for builtin exceptions
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
-
import python_minifier.ast_compat as ast
|
|
12
11
|
import sys
|
|
13
12
|
|
|
13
|
+
import python_minifier.ast_compat as ast
|
|
14
|
+
from python_minifier.ast_annotation import get_parent, set_parent
|
|
15
|
+
|
|
14
16
|
from python_minifier.rename.binding import BuiltinBinding
|
|
15
17
|
|
|
18
|
+
|
|
16
19
|
# These are always exceptions, in every version of python
|
|
17
20
|
builtin_exceptions = [
|
|
18
21
|
'SyntaxError', 'Exception', 'ValueError', 'BaseException', 'MemoryError', 'RuntimeError', 'DeprecationWarning', 'UnicodeEncodeError', 'KeyError', 'LookupError', 'TypeError', 'BufferError',
|
|
@@ -73,22 +76,24 @@ builtin_exceptions_3_11 = [
|
|
|
73
76
|
'BaseExceptionGroup',
|
|
74
77
|
]
|
|
75
78
|
|
|
79
|
+
|
|
76
80
|
def _remove_empty_call(binding):
|
|
77
81
|
assert isinstance(binding, BuiltinBinding)
|
|
78
82
|
|
|
79
83
|
for name_node in binding.references:
|
|
80
84
|
# For this to be a builtin, all references must be name nodes as it is not defined anywhere
|
|
81
|
-
assert isinstance(name_node, ast.Name)
|
|
85
|
+
assert isinstance(name_node, ast.Name)
|
|
86
|
+
assert isinstance(name_node.ctx, ast.Load)
|
|
82
87
|
|
|
83
|
-
if not isinstance(name_node
|
|
88
|
+
if not isinstance(get_parent(name_node), ast.Call):
|
|
84
89
|
# This is not a call
|
|
85
90
|
continue
|
|
86
|
-
call_node = name_node
|
|
91
|
+
call_node = get_parent(name_node)
|
|
87
92
|
|
|
88
|
-
if not isinstance(call_node
|
|
93
|
+
if not isinstance(get_parent(call_node), ast.Raise):
|
|
89
94
|
# This is not a raise statement
|
|
90
95
|
continue
|
|
91
|
-
raise_node = call_node
|
|
96
|
+
raise_node = get_parent(call_node)
|
|
92
97
|
|
|
93
98
|
if len(call_node.args) > 0 or len(call_node.keywords) > 0:
|
|
94
99
|
# This is a call with arguments
|
|
@@ -101,7 +106,7 @@ def _remove_empty_call(binding):
|
|
|
101
106
|
raise_node.exc = name_node
|
|
102
107
|
elif raise_node.cause is call_node:
|
|
103
108
|
raise_node.cause = name_node
|
|
104
|
-
name_node
|
|
109
|
+
set_parent(name_node, raise_node)
|
|
105
110
|
|
|
106
111
|
|
|
107
112
|
def remove_no_arg_exception_call(module):
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import python_minifier.ast_compat as ast
|
|
2
1
|
import sys
|
|
3
2
|
|
|
3
|
+
import python_minifier.ast_compat as ast
|
|
4
|
+
|
|
4
5
|
from python_minifier.transforms.suite_transformer import SuiteTransformer
|
|
5
|
-
from python_minifier.util import
|
|
6
|
+
from python_minifier.util import is_constant_node
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class RemoveExplicitReturnNone(SuiteTransformer):
|
|
@@ -17,13 +18,13 @@ class RemoveExplicitReturnNone(SuiteTransformer):
|
|
|
17
18
|
if sys.version_info < (3, 4) and isinstance(node.value, ast.Name) and node.value.id == 'None':
|
|
18
19
|
node.value = None
|
|
19
20
|
|
|
20
|
-
elif sys.version_info >= (3, 4) and
|
|
21
|
+
elif sys.version_info >= (3, 4) and is_constant_node(node.value, ast.NameConstant) and node.value.value is None:
|
|
21
22
|
node.value = None
|
|
22
23
|
|
|
23
24
|
return node
|
|
24
25
|
|
|
25
26
|
def visit_FunctionDef(self, node):
|
|
26
|
-
assert
|
|
27
|
+
assert isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef))
|
|
27
28
|
|
|
28
29
|
node.body = [self.visit(a) for a in node.body]
|
|
29
30
|
|