python-minifier 3.1.1__tar.gz → 3.2.0__tar.gz
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-3.1.1/src/python_minifier.egg-info → python_minifier-3.2.0}/PKG-INFO +1 -1
- {python_minifier-3.1.1 → python_minifier-3.2.0}/setup.py +1 -1
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/__init__.py +7 -4
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/__init__.pyi +6 -2
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/__main__.py +9 -1
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/expression_printer.py +2 -2
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/module_printer.py +2 -2
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/token_printer.py +1 -1
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/transforms/constant_folding.py +59 -22
- {python_minifier-3.1.1 → python_minifier-3.2.0/src/python_minifier.egg-info}/PKG-INFO +1 -1
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier.egg-info/SOURCES.txt +1 -0
- python_minifier-3.2.0/test/test_folding.py +560 -0
- python_minifier-3.2.0/test/test_prefer_single_line.py +217 -0
- python_minifier-3.1.1/test/test_folding.py +0 -151
- {python_minifier-3.1.1 → python_minifier-3.2.0}/LICENSE +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/MANIFEST.in +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/README.md +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/setup.cfg +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/ast_annotation/__init__.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/ast_compare.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/ast_compat.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/ast_printer.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/f_string.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/ministring.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/py.typed +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/rename/README.md +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/rename/__init__.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/rename/bind_names.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/rename/binding.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/rename/mapper.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/rename/name_generator.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/rename/rename_literals.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/rename/renamer.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/rename/resolve_names.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/rename/util.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/t_string.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/transforms/__init__.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/transforms/combine_imports.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/transforms/remove_annotations.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/transforms/remove_annotations_options.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/transforms/remove_annotations_options.pyi +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/transforms/remove_asserts.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/transforms/remove_debug.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/transforms/remove_exception_brackets.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/transforms/remove_explicit_return_none.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/transforms/remove_literal_statements.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/transforms/remove_object_base.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/transforms/remove_pass.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/transforms/remove_posargs.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/transforms/suite_transformer.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/util.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier.egg-info/dependency_links.txt +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier.egg-info/entry_points.txt +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier.egg-info/top_level.txt +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier.egg-info/zip-safe +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/ast_annotation/test_add_parent.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/conftest.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/helpers.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/requirements.txt +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/subprocess_compat.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_assignment_expressions.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_await_fstring.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_best_effort_cli.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_bind_names.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_bind_names_namedexpr.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_bind_names_python2.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_bind_names_python312.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_bind_names_python313.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_bind_names_python33.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_combine_imports.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_comprehension_rename.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_decorator_expressions.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_dict_expansion.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_fstring.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_generic_types.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_hoist_literals.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_import.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_is_constant_node.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_iterable_unpacking.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_match.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_match_rename.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_name_generator.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_nonlocal.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_posargs.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_preserve_shebang.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_raw_fstring_backslash.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_raw_tstring_backslash.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_remove_annotations.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_remove_assert.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_remove_debug.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_remove_exception_brackets.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_remove_explicit_return_none.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_remove_literal_statements.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_remove_object.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_remove_pass.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_rename_builtins.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_rename_locals.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_slice.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_template_strings.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_tuple_with_bug.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_type_param_defaults.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_unicode_cli.py +0 -0
- {python_minifier-3.1.1 → python_minifier-3.2.0}/test/test_utf8_encoding.py +0 -0
|
@@ -72,7 +72,8 @@ def minify(
|
|
|
72
72
|
remove_debug=False,
|
|
73
73
|
remove_explicit_return_none=True,
|
|
74
74
|
remove_builtin_exception_brackets=True,
|
|
75
|
-
constant_folding=True
|
|
75
|
+
constant_folding=True,
|
|
76
|
+
prefer_single_line=False,
|
|
76
77
|
):
|
|
77
78
|
"""
|
|
78
79
|
Minify a python module
|
|
@@ -107,6 +108,7 @@ def minify(
|
|
|
107
108
|
:param bool remove_explicit_return_none: If explicit return None statements should be replaced with a bare return
|
|
108
109
|
:param bool remove_builtin_exception_brackets: If brackets should be removed when raising exceptions with no arguments
|
|
109
110
|
:param bool constant_folding: If literal expressions should be evaluated
|
|
111
|
+
:param bool prefer_single_line: If semi-colons should be preferred over newlines where there is no difference in output size
|
|
110
112
|
|
|
111
113
|
:rtype: str
|
|
112
114
|
|
|
@@ -192,7 +194,7 @@ def minify(
|
|
|
192
194
|
if convert_posargs_to_args:
|
|
193
195
|
module = remove_posargs(module)
|
|
194
196
|
|
|
195
|
-
minified = unparse(module)
|
|
197
|
+
minified = unparse(module, prefer_single_line=prefer_single_line)
|
|
196
198
|
|
|
197
199
|
if preserve_shebang is True:
|
|
198
200
|
shebang_line = _find_shebang(source)
|
|
@@ -219,7 +221,7 @@ def _find_shebang(source):
|
|
|
219
221
|
return None
|
|
220
222
|
|
|
221
223
|
|
|
222
|
-
def unparse(module):
|
|
224
|
+
def unparse(module, prefer_single_line=False):
|
|
223
225
|
"""
|
|
224
226
|
Turn a module AST into python code
|
|
225
227
|
|
|
@@ -228,13 +230,14 @@ def unparse(module):
|
|
|
228
230
|
|
|
229
231
|
:param module: The module to turn into python code
|
|
230
232
|
:type: module: :class:`ast.Module`
|
|
233
|
+
:param bool prefer_single_line: If semi-colons should be preferred over newlines where there is no difference in output size
|
|
231
234
|
:rtype: str
|
|
232
235
|
|
|
233
236
|
"""
|
|
234
237
|
|
|
235
238
|
assert isinstance(module, ast.Module)
|
|
236
239
|
|
|
237
|
-
printer = ModulePrinter()
|
|
240
|
+
printer = ModulePrinter(prefer_single_line=prefer_single_line)
|
|
238
241
|
printer(module)
|
|
239
242
|
|
|
240
243
|
try:
|
|
@@ -28,11 +28,15 @@ def minify(
|
|
|
28
28
|
remove_debug: bool = ...,
|
|
29
29
|
remove_explicit_return_none: bool = ...,
|
|
30
30
|
remove_builtin_exception_brackets: bool = ...,
|
|
31
|
-
constant_folding: bool =
|
|
31
|
+
constant_folding: bool = ...,
|
|
32
|
+
prefer_single_line: bool = ...
|
|
32
33
|
) -> Text: ...
|
|
33
34
|
|
|
34
35
|
|
|
35
|
-
def unparse(
|
|
36
|
+
def unparse(
|
|
37
|
+
module: ast.Module,
|
|
38
|
+
prefer_single_line: bool = ...
|
|
39
|
+
) -> Text: ...
|
|
36
40
|
|
|
37
41
|
|
|
38
42
|
def awslambda(
|
|
@@ -140,6 +140,13 @@ def parse_args():
|
|
|
140
140
|
dest='in_place'
|
|
141
141
|
)
|
|
142
142
|
|
|
143
|
+
parser.add_argument(
|
|
144
|
+
'--prefer-single-line',
|
|
145
|
+
action='store_true',
|
|
146
|
+
help='Prefer multiple statements on a single line separated by semicolons, instead of newlines, where there is no difference in output size',
|
|
147
|
+
dest='prefer_single_line',
|
|
148
|
+
)
|
|
149
|
+
|
|
143
150
|
# Minification arguments
|
|
144
151
|
minification_options = parser.add_argument_group('minification options', 'Options that affect how the source is minified')
|
|
145
152
|
minification_options.add_argument(
|
|
@@ -373,7 +380,8 @@ def do_minify(source, filename, minification_args):
|
|
|
373
380
|
remove_debug=minification_args.remove_debug,
|
|
374
381
|
remove_explicit_return_none=minification_args.remove_explicit_return_none,
|
|
375
382
|
remove_builtin_exception_brackets=minification_args.remove_exception_brackets,
|
|
376
|
-
constant_folding=minification_args.constant_folding
|
|
383
|
+
constant_folding=minification_args.constant_folding,
|
|
384
|
+
prefer_single_line=minification_args.prefer_single_line,
|
|
377
385
|
)
|
|
378
386
|
|
|
379
387
|
# Encode minified result to bytes for comparison and output
|
|
@@ -11,7 +11,7 @@ class ExpressionPrinter(object):
|
|
|
11
11
|
Builds the smallest possible exact representation of an ast
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
|
-
def __init__(self):
|
|
14
|
+
def __init__(self, prefer_single_line=False):
|
|
15
15
|
|
|
16
16
|
self.precedences = {
|
|
17
17
|
'Lambda': 2, # Lambda
|
|
@@ -34,7 +34,7 @@ class ExpressionPrinter(object):
|
|
|
34
34
|
'Tuple': 18, 'Set': 18, 'List': 18, 'Dict': 18, 'ListComp': 18, 'SetComp': 18, 'DictComp': 18, 'GeneratorExp': 18, # Container
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
self.printer = TokenPrinter()
|
|
37
|
+
self.printer = TokenPrinter(prefer_single_line=prefer_single_line)
|
|
38
38
|
|
|
39
39
|
def __call__(self, module):
|
|
40
40
|
"""
|
|
@@ -11,8 +11,8 @@ class ModulePrinter(ExpressionPrinter):
|
|
|
11
11
|
Builds the smallest possible exact representation of an ast
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
|
-
def __init__(self, indent_char='\t'):
|
|
15
|
-
super(ModulePrinter, self).__init__()
|
|
14
|
+
def __init__(self, indent_char='\t', prefer_single_line=False):
|
|
15
|
+
super(ModulePrinter, self).__init__(prefer_single_line=prefer_single_line)
|
|
16
16
|
self.indent_char = indent_char
|
|
17
17
|
|
|
18
18
|
def __call__(self, module):
|
|
@@ -306,7 +306,7 @@ class TokenPrinter(object):
|
|
|
306
306
|
def end_statement(self):
|
|
307
307
|
""" End a statement with a newline, or a semi-colon if it saves characters. """
|
|
308
308
|
|
|
309
|
-
if self.indent == 0:
|
|
309
|
+
if self.indent == 0 and not self._prefer_single_line:
|
|
310
310
|
self.newline()
|
|
311
311
|
else:
|
|
312
312
|
if self._code[-1] != ';':
|
{python_minifier-3.1.1 → python_minifier-3.2.0}/src/python_minifier/transforms/constant_folding.py
RENAMED
|
@@ -10,36 +10,35 @@ from python_minifier.transforms.suite_transformer import SuiteTransformer
|
|
|
10
10
|
from python_minifier.util import is_constant_node
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
"""
|
|
15
|
-
Fold Constants if it would reduce the size of the source
|
|
13
|
+
def is_foldable_constant(node):
|
|
16
14
|
"""
|
|
15
|
+
Check if a node is a constant expression that can participate in folding.
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
We can asume that children have already been folded, so foldable constants are either:
|
|
18
|
+
- Simple literals (Num, NameConstant)
|
|
19
|
+
- UnaryOp(USub/Invert) on a Num - these don't fold to shorter forms,
|
|
20
|
+
so they remain after child visiting. UAdd and Not would have been
|
|
21
|
+
folded away since they always produce shorter results.
|
|
22
|
+
"""
|
|
23
|
+
if is_constant_node(node, (ast.Num, ast.NameConstant)):
|
|
24
|
+
return True
|
|
20
25
|
|
|
21
|
-
|
|
26
|
+
if isinstance(node, ast.UnaryOp):
|
|
27
|
+
if isinstance(node.op, (ast.USub, ast.Invert)):
|
|
28
|
+
return is_constant_node(node.operand, ast.Num)
|
|
22
29
|
|
|
23
|
-
|
|
24
|
-
node.right = self.visit(node.right)
|
|
30
|
+
return False
|
|
25
31
|
|
|
26
|
-
# Check this is a constant expression that could be folded
|
|
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
|
|
28
|
-
if not is_constant_node(node.left, (ast.Num, ast.NameConstant)):
|
|
29
|
-
return node
|
|
30
|
-
if not is_constant_node(node.right, (ast.Num, ast.NameConstant)):
|
|
31
|
-
return node
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
class FoldConstants(SuiteTransformer):
|
|
34
|
+
"""
|
|
35
|
+
Fold Constants if it would reduce the size of the source
|
|
36
|
+
"""
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
# It can also be slow to evaluate
|
|
41
|
-
return node
|
|
38
|
+
def __init__(self):
|
|
39
|
+
super(FoldConstants, self).__init__()
|
|
42
40
|
|
|
41
|
+
def fold(self, node):
|
|
43
42
|
# Evaluate the expression
|
|
44
43
|
try:
|
|
45
44
|
original_expression = unparse_expression(node)
|
|
@@ -96,6 +95,44 @@ class FoldConstants(SuiteTransformer):
|
|
|
96
95
|
# New representation is shorter and has the same value, so use it
|
|
97
96
|
return self.add_child(new_node, get_parent(node), node.namespace)
|
|
98
97
|
|
|
98
|
+
def visit_BinOp(self, node):
|
|
99
|
+
|
|
100
|
+
node.left = self.visit(node.left)
|
|
101
|
+
node.right = self.visit(node.right)
|
|
102
|
+
|
|
103
|
+
# Check this is a constant expression that could be folded
|
|
104
|
+
# 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
|
|
105
|
+
if not is_foldable_constant(node.left):
|
|
106
|
+
return node
|
|
107
|
+
if not is_foldable_constant(node.right):
|
|
108
|
+
return node
|
|
109
|
+
|
|
110
|
+
if isinstance(node.op, ast.Div):
|
|
111
|
+
# Folding div is subtle, since it can have different results in Python 2 and Python 3
|
|
112
|
+
# Do this once target version options have been implemented
|
|
113
|
+
return node
|
|
114
|
+
|
|
115
|
+
if isinstance(node.op, ast.Pow):
|
|
116
|
+
# This can be folded, but it is unlikely to reduce the size of the source
|
|
117
|
+
# It can also be slow to evaluate
|
|
118
|
+
return node
|
|
119
|
+
|
|
120
|
+
return self.fold(node)
|
|
121
|
+
|
|
122
|
+
def visit_UnaryOp(self, node):
|
|
123
|
+
|
|
124
|
+
node.operand = self.visit(node.operand)
|
|
125
|
+
|
|
126
|
+
# Only fold if the operand is a foldable constant
|
|
127
|
+
if not is_foldable_constant(node.operand):
|
|
128
|
+
return node
|
|
129
|
+
|
|
130
|
+
# Only fold these unary operators
|
|
131
|
+
if not isinstance(node.op, (ast.USub, ast.UAdd, ast.Invert, ast.Not)):
|
|
132
|
+
return node
|
|
133
|
+
|
|
134
|
+
return self.fold(node)
|
|
135
|
+
|
|
99
136
|
|
|
100
137
|
def equal_value_and_type(a, b):
|
|
101
138
|
if type(a) != type(b):
|