python-minifier 2.11.2__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.
Files changed (44) hide show
  1. python_minifier/__init__.py +269 -0
  2. python_minifier/__init__.pyi +37 -0
  3. python_minifier/__main__.py +332 -0
  4. python_minifier/ast_compare.py +104 -0
  5. python_minifier/ast_compat.py +40 -0
  6. python_minifier/ast_printer.py +130 -0
  7. python_minifier/expression_printer.py +753 -0
  8. python_minifier/f_string.py +446 -0
  9. python_minifier/ministring.py +179 -0
  10. python_minifier/module_printer.py +862 -0
  11. python_minifier/py.typed +0 -0
  12. python_minifier/rename/__init__.py +6 -0
  13. python_minifier/rename/bind_names.py +192 -0
  14. python_minifier/rename/binding.py +495 -0
  15. python_minifier/rename/mapper.py +175 -0
  16. python_minifier/rename/name_generator.py +51 -0
  17. python_minifier/rename/rename_literals.py +249 -0
  18. python_minifier/rename/renamer.py +230 -0
  19. python_minifier/rename/resolve_names.py +106 -0
  20. python_minifier/rename/util.py +203 -0
  21. python_minifier/token_printer.py +299 -0
  22. python_minifier/transforms/__init__.py +0 -0
  23. python_minifier/transforms/combine_imports.py +76 -0
  24. python_minifier/transforms/constant_folding.py +114 -0
  25. python_minifier/transforms/remove_annotations.py +130 -0
  26. python_minifier/transforms/remove_annotations_options.py +35 -0
  27. python_minifier/transforms/remove_annotations_options.pyi +17 -0
  28. python_minifier/transforms/remove_asserts.py +26 -0
  29. python_minifier/transforms/remove_debug.py +53 -0
  30. python_minifier/transforms/remove_exception_brackets.py +124 -0
  31. python_minifier/transforms/remove_explicit_return_none.py +38 -0
  32. python_minifier/transforms/remove_literal_statements.py +61 -0
  33. python_minifier/transforms/remove_object_base.py +24 -0
  34. python_minifier/transforms/remove_pass.py +26 -0
  35. python_minifier/transforms/remove_posargs.py +13 -0
  36. python_minifier/transforms/suite_transformer.py +196 -0
  37. python_minifier/util.py +48 -0
  38. python_minifier-2.11.2.dist-info/LICENSE +21 -0
  39. python_minifier-2.11.2.dist-info/METADATA +177 -0
  40. python_minifier-2.11.2.dist-info/RECORD +44 -0
  41. python_minifier-2.11.2.dist-info/WHEEL +5 -0
  42. python_minifier-2.11.2.dist-info/entry_points.txt +3 -0
  43. python_minifier-2.11.2.dist-info/top_level.txt +1 -0
  44. python_minifier-2.11.2.dist-info/zip-safe +1 -0
@@ -0,0 +1,269 @@
1
+ """
2
+ This package transforms python source code strings or ast.Module Nodes into
3
+ a 'minified' representation of the same source code.
4
+
5
+ """
6
+
7
+ import python_minifier.ast_compat as ast
8
+ import re
9
+
10
+ from python_minifier.ast_compare import CompareError, compare_ast
11
+ from python_minifier.module_printer import ModulePrinter
12
+ from python_minifier.rename import (
13
+ rename_literals,
14
+ bind_names,
15
+ resolve_names,
16
+ rename,
17
+ allow_rename_globals,
18
+ allow_rename_locals,
19
+ add_namespace,
20
+ )
21
+
22
+ from python_minifier.transforms.combine_imports import CombineImports
23
+ from python_minifier.transforms.constant_folding import FoldConstants
24
+ from python_minifier.transforms.remove_annotations import RemoveAnnotations
25
+ from python_minifier.transforms.remove_annotations_options import RemoveAnnotationsOptions
26
+ from python_minifier.transforms.remove_asserts import RemoveAsserts
27
+ from python_minifier.transforms.remove_debug import RemoveDebug
28
+ from python_minifier.transforms.remove_explicit_return_none import RemoveExplicitReturnNone
29
+ from python_minifier.transforms.remove_exception_brackets import remove_no_arg_exception_call
30
+ from python_minifier.transforms.remove_literal_statements import RemoveLiteralStatements
31
+ from python_minifier.transforms.remove_object_base import RemoveObject
32
+ from python_minifier.transforms.remove_pass import RemovePass
33
+ from python_minifier.transforms.remove_posargs import remove_posargs
34
+
35
+
36
+ class UnstableMinification(RuntimeError):
37
+ """
38
+ Raised when a minified module differs from the original module in an unexpected way.
39
+
40
+ This is raised when the minifier generates source code that doesn't parse back into the
41
+ original module (after known transformations).
42
+ This should never occur and is a bug.
43
+
44
+ """
45
+
46
+ def __init__(self, exception, source, minified):
47
+ self.exception = exception
48
+ self.source = source
49
+ self.minified = minified
50
+
51
+ def __str__(self):
52
+ return 'Minification was unstable! Please create an issue at https://github.com/dflook/python-minifier/issues'
53
+
54
+
55
+ def minify(
56
+ source,
57
+ filename=None,
58
+ remove_annotations=RemoveAnnotationsOptions(),
59
+ remove_pass=True,
60
+ remove_literal_statements=False,
61
+ combine_imports=True,
62
+ hoist_literals=True,
63
+ rename_locals=True,
64
+ preserve_locals=None,
65
+ rename_globals=False,
66
+ preserve_globals=None,
67
+ remove_object_base=True,
68
+ convert_posargs_to_args=True,
69
+ preserve_shebang=True,
70
+ remove_asserts=False,
71
+ remove_debug=False,
72
+ remove_explicit_return_none=True,
73
+ remove_builtin_exception_brackets=True,
74
+ constant_folding=True
75
+ ):
76
+ """
77
+ Minify a python module
78
+
79
+ The module is transformed according the the arguments.
80
+ If all transformation arguments are False, no transformations are made to the AST, the returned string will
81
+ parse into exactly the same module.
82
+
83
+ Using the default arguments only transformations that are always or almost always safe are enabled.
84
+
85
+ :param str source: The python module source code
86
+ :param str filename: The original source filename if known
87
+
88
+ :param remove_annotations: Configures the removal of type annotations. True removes all annotations, False removes none. RemoveAnnotationsOptions can be used to configure the removal of specific annotations.
89
+ :type remove_annotations: bool or RemoveAnnotationsOptions
90
+ :param bool remove_pass: If Pass statements should be removed where possible
91
+ :param bool remove_literal_statements: If statements consisting of a single literal should be removed, including docstrings
92
+ :param bool combine_imports: Combine adjacent import statements where possible
93
+ :param bool hoist_literals: If str and byte literals may be hoisted to the module level where possible.
94
+ :param bool rename_locals: If local names may be shortened
95
+ :param preserve_locals: Locals names to leave unchanged when rename_locals is True
96
+ :type preserve_locals: list[str]
97
+ :param bool rename_globals: If global names may be shortened
98
+ :param preserve_globals: Global names to leave unchanged when rename_globals is True
99
+ :type preserve_globals: list[str]
100
+ :param bool remove_object_base: If object as a base class may be removed
101
+ :param bool convert_posargs_to_args: If positional-only arguments will be converted to normal arguments
102
+ :param bool preserve_shebang: Keep any shebang interpreter directive from the source in the minified output
103
+ :param bool remove_asserts: If assert statements should be removed
104
+ :param bool remove_debug: If conditional statements that test '__debug__ is True' should be removed
105
+ :param bool remove_explicit_return_none: If explicit return None statements should be replaced with a bare return
106
+ :param bool remove_builtin_exception_brackets: If brackets should be removed when raising exceptions with no arguments
107
+ :param bool constant_folding: If literal expressions should be evaluated
108
+
109
+ :rtype: str
110
+
111
+ """
112
+
113
+ filename = filename or 'python_minifier.minify source'
114
+
115
+ # This will raise if the source file can't be parsed
116
+ module = ast.parse(source, filename)
117
+
118
+ add_namespace(module)
119
+
120
+ if remove_literal_statements:
121
+ module = RemoveLiteralStatements()(module)
122
+
123
+ if combine_imports:
124
+ module = CombineImports()(module)
125
+
126
+ if isinstance(remove_annotations, bool):
127
+ remove_annotations_options = RemoveAnnotationsOptions(
128
+ remove_variable_annotations=remove_annotations,
129
+ remove_return_annotations=remove_annotations,
130
+ remove_argument_annotations=remove_annotations,
131
+ remove_class_attribute_annotations=remove_annotations,
132
+ )
133
+ elif isinstance(remove_annotations, RemoveAnnotationsOptions):
134
+ remove_annotations_options = remove_annotations
135
+ else:
136
+ raise TypeError('remove_annotations must be a bool or RemoveAnnotationsOptions')
137
+
138
+ if remove_annotations_options:
139
+ module = RemoveAnnotations(remove_annotations_options)(module)
140
+
141
+ if remove_pass:
142
+ module = RemovePass()(module)
143
+
144
+ if remove_object_base:
145
+ module = RemoveObject()(module)
146
+
147
+ if remove_asserts:
148
+ module = RemoveAsserts()(module)
149
+
150
+ if remove_debug:
151
+ module = RemoveDebug()(module)
152
+
153
+ if remove_explicit_return_none:
154
+ module = RemoveExplicitReturnNone()(module)
155
+
156
+ if constant_folding:
157
+ module = FoldConstants()(module)
158
+
159
+ bind_names(module)
160
+ resolve_names(module)
161
+
162
+ if remove_builtin_exception_brackets and not module.tainted:
163
+ remove_no_arg_exception_call(module)
164
+
165
+ if module.tainted:
166
+ rename_globals = False
167
+ rename_locals = False
168
+
169
+ if preserve_locals is None:
170
+ preserve_locals = []
171
+ elif isinstance(preserve_locals, str):
172
+ preserve_locals = [preserve_locals]
173
+ if preserve_globals is None:
174
+ preserve_globals = []
175
+ elif isinstance(preserve_globals, str):
176
+ preserve_globals = [preserve_globals]
177
+
178
+ preserve_locals.extend(module.preserved)
179
+ preserve_globals.extend(module.preserved)
180
+
181
+ allow_rename_locals(module, rename_locals, preserve_locals)
182
+ allow_rename_globals(module, rename_globals, preserve_globals)
183
+
184
+ if hoist_literals:
185
+ rename_literals(module)
186
+
187
+ rename(module, prefix_globals=not rename_globals, preserved_globals=preserve_globals)
188
+
189
+ if convert_posargs_to_args:
190
+ module = remove_posargs(module)
191
+
192
+ minified = unparse(module)
193
+
194
+ if preserve_shebang is True:
195
+ shebang_line = _find_shebang(source)
196
+ if shebang_line is not None:
197
+ return shebang_line + '\n' + minified
198
+
199
+ return minified
200
+
201
+ def _find_shebang(source):
202
+ """
203
+ Find a shebang line in source
204
+ """
205
+
206
+ if isinstance(source, bytes):
207
+ shebang = re.match(br'^#!.*', source)
208
+ if shebang:
209
+ return shebang.group().decode()
210
+ else:
211
+ shebang = re.match(r'^#!.*', source)
212
+ if shebang:
213
+ return shebang.group()
214
+
215
+ return None
216
+
217
+ def unparse(module):
218
+ """
219
+ Turn a module AST into python code
220
+
221
+ This returns an exact representation of the given module,
222
+ such that it can be parsed back into the same AST.
223
+
224
+ :param module: The module to turn into python code
225
+ :type: module: :class:`ast.Module`
226
+ :rtype: str
227
+
228
+ """
229
+
230
+ assert isinstance(module, ast.Module)
231
+
232
+ printer = ModulePrinter()
233
+ printer(module)
234
+
235
+ try:
236
+ minified_module = ast.parse(printer.code, 'python_minifier.unparse output')
237
+ except SyntaxError as syntax_error:
238
+ raise UnstableMinification(syntax_error, '', printer.code)
239
+
240
+ try:
241
+ compare_ast(module, minified_module)
242
+ except CompareError as compare_error:
243
+ raise UnstableMinification(compare_error, '', printer.code)
244
+
245
+ return printer.code
246
+
247
+
248
+ def awslambda(source, filename=None, entrypoint=None):
249
+ """
250
+ Minify a python module for use as an AWS Lambda function
251
+
252
+ This returns a string suitable for embedding in a cloudformation template.
253
+ When minifying, all transformations are enabled.
254
+
255
+ :param str source: The python module source code
256
+ :param str filename: The original source filename if known
257
+ :param entrypoint: The lambda entrypoint function
258
+ :type entrypoint: str or NoneType
259
+ :rtype: str
260
+
261
+ """
262
+
263
+ rename_globals = True
264
+ if entrypoint is None:
265
+ rename_globals = False
266
+
267
+ return minify(
268
+ source, filename, remove_literal_statements=True, rename_globals=rename_globals, preserve_globals=[entrypoint],
269
+ )
@@ -0,0 +1,37 @@
1
+ import ast
2
+ from typing import List, Text, AnyStr, Optional, Any, Union
3
+
4
+ from .transforms.remove_annotations_options import RemoveAnnotationsOptions as RemoveAnnotationsOptions
5
+
6
+ class UnstableMinification(RuntimeError):
7
+ def __init__(self, exception: Any, source: Any, minified: Any): ...
8
+
9
+ def minify(
10
+ source: AnyStr,
11
+ filename: Optional[str] = ...,
12
+ remove_annotations: Union[bool, RemoveAnnotationsOptions] = ...,
13
+ remove_pass: bool = ...,
14
+ remove_literal_statements: bool = ...,
15
+ combine_imports: bool = ...,
16
+ hoist_literals: bool = ...,
17
+ rename_locals: bool = ...,
18
+ preserve_locals: Optional[List[Text]] = ...,
19
+ rename_globals: bool = ...,
20
+ preserve_globals: Optional[List[Text]] = ...,
21
+ remove_object_base: bool = ...,
22
+ convert_posargs_to_args: bool = ...,
23
+ preserve_shebang: bool = ...,
24
+ remove_asserts: bool = ...,
25
+ remove_debug: bool = ...,
26
+ remove_explicit_return_none: bool = ...,
27
+ remove_builtin_exception_brackets: bool = ...,
28
+ constant_folding: bool = ...
29
+ ) -> Text: ...
30
+
31
+ def unparse(module: ast.Module) -> Text: ...
32
+
33
+ def awslambda(
34
+ source: AnyStr,
35
+ filename: Optional[Text] = ...,
36
+ entrypoint: Optional[Text] = ...
37
+ ) -> Text: ...
@@ -0,0 +1,332 @@
1
+ from __future__ import print_function
2
+
3
+ import argparse
4
+ import os
5
+ import sys
6
+
7
+ from python_minifier import minify
8
+ from python_minifier.transforms.remove_annotations_options import RemoveAnnotationsOptions
9
+
10
+ if sys.version_info >= (3, 8):
11
+ from importlib import metadata
12
+ try:
13
+ version = metadata.version('python-minifier')
14
+ except metadata.PackageNotFoundError:
15
+ version = '0.0.0'
16
+ else:
17
+ from pkg_resources import get_distribution, DistributionNotFound
18
+ try:
19
+ version = get_distribution('python_minifier').version
20
+ except DistributionNotFound:
21
+ version = '0.0.0'
22
+
23
+
24
+ def main():
25
+ """
26
+ examples:
27
+ # Minifying stdin to stdout
28
+ pyminify -
29
+
30
+ # Minifying a file to stdout
31
+ pyminify example.py
32
+
33
+ # Minifying a file and writing to a different file
34
+ pyminify example.py --output example.min.py
35
+
36
+ # Minifying a file in place
37
+ pyminify example.py --in-place
38
+
39
+ # Minifying all *.py files in a directory
40
+ pyminify src/ --in-place
41
+
42
+ # Minifying multiple paths in place
43
+ pyminify file1.py file2.py src/ --in-place
44
+ """
45
+
46
+ args = parse_args()
47
+
48
+ if len(args.path) == 1 and args.path[0] == '-':
49
+ # minify stdin
50
+ source = sys.stdin.buffer.read() if sys.version_info >= (3, 0) else sys.stdin.read()
51
+ minified = do_minify(source, 'stdin', args)
52
+ if args.output:
53
+ with open(args.output, 'w') as f:
54
+ f.write(minified)
55
+ else:
56
+ sys.stdout.write(minified)
57
+
58
+ else:
59
+ # minify source paths
60
+ for path in source_modules(args):
61
+ if args.output or args.in_place:
62
+ sys.stdout.write(path + '\n')
63
+
64
+ with open(path, 'rb') as f:
65
+ source = f.read()
66
+
67
+ minified = do_minify(source, path, args)
68
+
69
+ if args.in_place:
70
+ with open(path, 'w') as f:
71
+ f.write(minified)
72
+ elif args.output:
73
+ with open(args.output, 'w') as f:
74
+ f.write(minified)
75
+ else:
76
+ sys.stdout.write(minified)
77
+
78
+
79
+ def parse_args():
80
+ parser = argparse.ArgumentParser(prog='pyminify', description='Minify Python source code', formatter_class=argparse.RawDescriptionHelpFormatter, epilog=main.__doc__)
81
+
82
+ parser.add_argument(
83
+ 'path',
84
+ nargs='+',
85
+ type=str,
86
+ help='The source file or directory to minify. Use "-" to read from stdin. Directories are recursively searched for ".py" files to minify. May be used multiple times',
87
+ )
88
+
89
+ output_options = parser.add_mutually_exclusive_group()
90
+ output_options.add_argument(
91
+ '--output', '-o',
92
+ action='store',
93
+ help='Path to write minified output. Can only be used when the source is a single module. Outputs to stdout by default',
94
+ dest='output'
95
+ )
96
+ output_options.add_argument(
97
+ '--in-place', '-i',
98
+ action='store_true',
99
+ help='Overwrite existing files. Required when there is more than one source module',
100
+ dest='in_place'
101
+ )
102
+
103
+ # Minification arguments
104
+ minification_options = parser.add_argument_group('minification options', 'Options that affect how the source is minified')
105
+ minification_options.add_argument(
106
+ '--no-combine-imports',
107
+ action='store_false',
108
+ help='Disable combining adjacent import statements',
109
+ dest='combine_imports',
110
+ )
111
+ minification_options.add_argument(
112
+ '--no-remove-pass',
113
+ action='store_false',
114
+ default=True,
115
+ help='Disable removing Pass statements',
116
+ dest='remove_pass',
117
+ )
118
+ minification_options.add_argument(
119
+ '--remove-literal-statements',
120
+ action='store_true',
121
+ help='Enable removing statements that are just a literal (including docstrings)',
122
+ dest='remove_literal_statements',
123
+ )
124
+ minification_options.add_argument(
125
+ '--no-hoist-literals',
126
+ action='store_false',
127
+ help='Disable replacing string and bytes literals with variables',
128
+ dest='hoist_literals',
129
+ )
130
+ minification_options.add_argument(
131
+ '--no-rename-locals',
132
+ action='store_false',
133
+ help='Disable shortening of local names',
134
+ dest='rename_locals'
135
+ )
136
+ minification_options.add_argument(
137
+ '--preserve-locals',
138
+ type=str,
139
+ action='append',
140
+ help='Comma separated list of local names that will not be shortened',
141
+ dest='preserve_locals',
142
+ metavar='LOCAL_NAMES'
143
+ )
144
+ minification_options.add_argument(
145
+ '--rename-globals',
146
+ action='store_true',
147
+ help='Enable shortening of global names',
148
+ dest='rename_globals'
149
+ )
150
+ minification_options.add_argument(
151
+ '--preserve-globals',
152
+ type=str,
153
+ action='append',
154
+ help='Comma separated list of global names that will not be shortened',
155
+ dest='preserve_globals',
156
+ metavar='GLOBAL_NAMES'
157
+ )
158
+ minification_options.add_argument(
159
+ '--no-remove-object-base',
160
+ action='store_false',
161
+ help='Disable removing object from base class list',
162
+ dest='remove_object_base',
163
+ )
164
+ minification_options.add_argument(
165
+ '--no-convert-posargs-to-args',
166
+ action='store_false',
167
+ help='Disable converting positional only arguments to normal arguments',
168
+ dest='convert_posargs_to_args',
169
+ )
170
+ minification_options.add_argument(
171
+ '--no-preserve-shebang',
172
+ action='store_false',
173
+ help='Preserve any shebang line from the source',
174
+ dest='preserve_shebang',
175
+ )
176
+ minification_options.add_argument(
177
+ '--remove-asserts',
178
+ action='store_true',
179
+ help='Remove assert statements',
180
+ dest='remove_asserts',
181
+ )
182
+ minification_options.add_argument(
183
+ '--remove-debug',
184
+ action='store_true',
185
+ help='Remove conditional statements that test __debug__ is True',
186
+ dest='remove_debug',
187
+ )
188
+ minification_options.add_argument(
189
+ '--no-remove-explicit-return-none',
190
+ action='store_false',
191
+ help='Replace explicit return None with a bare return',
192
+ dest='remove_explicit_return_none',
193
+ )
194
+ minification_options.add_argument(
195
+ '--no-remove-builtin-exception-brackets',
196
+ action='store_false',
197
+ help='Disable removing brackets when raising builtin exceptions with no arguments',
198
+ dest='remove_exception_brackets',
199
+ )
200
+ minification_options.add_argument(
201
+ '--no-constant-folding',
202
+ action='store_false',
203
+ help='Disable evaluating literal expressions',
204
+ dest='constant_folding',
205
+ )
206
+
207
+ annotation_options = parser.add_argument_group('remove annotations options', 'Options that affect how annotations are removed')
208
+ annotation_options.add_argument(
209
+ '--no-remove-annotations',
210
+ action='store_false',
211
+ help='Disable removing all annotations',
212
+ dest='remove_annotations',
213
+ )
214
+ annotation_options.add_argument(
215
+ '--no-remove-variable-annotations',
216
+ action='store_false',
217
+ help='Disable removing variable annotations',
218
+ dest='remove_variable_annotations',
219
+ )
220
+ annotation_options.add_argument(
221
+ '--no-remove-return-annotations',
222
+ action='store_false',
223
+ help='Disable removing function return annotations',
224
+ dest='remove_return_annotations',
225
+ )
226
+ annotation_options.add_argument(
227
+ '--no-remove-argument-annotations',
228
+ action='store_false',
229
+ help='Disable removing function argument annotations',
230
+ dest='remove_argument_annotations',
231
+ )
232
+ annotation_options.add_argument(
233
+ '--remove-class-attribute-annotations',
234
+ action='store_true',
235
+ help='Enable removing class attribute annotations',
236
+ dest='remove_class_attribute_annotations',
237
+ )
238
+
239
+ parser.add_argument('--version', '-v', action='version', version=version)
240
+
241
+ args = parser.parse_args()
242
+
243
+ # Handle some invalid argument combinations
244
+ if '-' in args.path and len(args.path) != 1:
245
+ sys.stderr.write('error: multiple path arguments, reading from stdin not allowed\n')
246
+ sys.exit(1)
247
+ if '-' in args.path and args.in_place:
248
+ sys.stderr.write('error: reading from stdin, --in-place is not valid\n')
249
+ sys.exit(1)
250
+ if len(args.path) > 1 and not args.in_place:
251
+ sys.stderr.write('error: multiple path arguments, --in-place required\n')
252
+ sys.exit(1)
253
+ if len(args.path) == 1 and os.path.isdir(args.path[0]) and not args.in_place:
254
+ sys.stderr.write('error: path ' + args.path[0] + ' is a directory, --in-place required\n')
255
+ sys.exit(1)
256
+
257
+ if args.remove_class_attribute_annotations and not args.remove_annotations:
258
+ sys.stderr.write('error: --remove-class-attribute-annotations would do nothing when used with --no-remove-annotations\n')
259
+ sys.exit(1)
260
+
261
+ return args
262
+
263
+
264
+ def source_modules(args):
265
+
266
+ def error(os_error):
267
+ raise os_error
268
+
269
+ for path_arg in args.path:
270
+ if os.path.isdir(path_arg):
271
+ for root, dirs, files in os.walk(path_arg, onerror=error, followlinks=True):
272
+ for file in files:
273
+ if file.endswith('.py') or file.endswith('.pyw'):
274
+ yield os.path.join(root, file)
275
+ else:
276
+ yield path_arg
277
+
278
+
279
+ def do_minify(source, filename, minification_args):
280
+
281
+ preserve_globals = []
282
+ if minification_args.preserve_globals:
283
+ for arg in minification_args.preserve_globals:
284
+ names = [name.strip() for name in arg.split(',') if name]
285
+ preserve_globals.extend(names)
286
+
287
+ preserve_locals = []
288
+ if minification_args.preserve_locals:
289
+ for arg in minification_args.preserve_locals:
290
+ names = [name.strip() for name in arg.split(',') if name]
291
+ preserve_locals.extend(names)
292
+
293
+ if minification_args.remove_annotations is False:
294
+ remove_annotations = RemoveAnnotationsOptions(
295
+ remove_variable_annotations=False,
296
+ remove_return_annotations=False,
297
+ remove_argument_annotations=False,
298
+ remove_class_attribute_annotations=False,
299
+ )
300
+ else:
301
+ remove_annotations = RemoveAnnotationsOptions(
302
+ remove_variable_annotations=minification_args.remove_variable_annotations,
303
+ remove_return_annotations=minification_args.remove_return_annotations,
304
+ remove_argument_annotations=minification_args.remove_argument_annotations,
305
+ remove_class_attribute_annotations=minification_args.remove_class_attribute_annotations,
306
+ )
307
+
308
+ return minify(
309
+ source,
310
+ filename=filename,
311
+ combine_imports=minification_args.combine_imports,
312
+ remove_pass=minification_args.remove_pass,
313
+ remove_annotations=remove_annotations,
314
+ remove_literal_statements=minification_args.remove_literal_statements,
315
+ hoist_literals=minification_args.hoist_literals,
316
+ rename_locals=minification_args.rename_locals,
317
+ preserve_locals=preserve_locals,
318
+ rename_globals=minification_args.rename_globals,
319
+ preserve_globals=preserve_globals,
320
+ remove_object_base=minification_args.remove_object_base,
321
+ convert_posargs_to_args=minification_args.convert_posargs_to_args,
322
+ preserve_shebang=minification_args.preserve_shebang,
323
+ remove_asserts=minification_args.remove_asserts,
324
+ remove_debug=minification_args.remove_debug,
325
+ remove_explicit_return_none=minification_args.remove_explicit_return_none,
326
+ remove_builtin_exception_brackets=minification_args.remove_exception_brackets,
327
+ constant_folding=minification_args.constant_folding
328
+ )
329
+
330
+
331
+ if __name__ == '__main__':
332
+ main()