python-minifier 2.4.2__py3-none-any.whl → 2.10.0__py3-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 (41) hide show
  1. python_minifier/__init__.py +88 -6
  2. python_minifier/__init__.pyi +37 -0
  3. python_minifier/__main__.py +255 -51
  4. python_minifier/ast_compare.py +4 -4
  5. python_minifier/ast_compat.py +40 -0
  6. python_minifier/ast_printer.py +130 -0
  7. python_minifier/expression_printer.py +224 -273
  8. python_minifier/f_string.py +92 -36
  9. python_minifier/module_printer.py +401 -235
  10. python_minifier/py.typed +0 -0
  11. python_minifier/rename/bind_names.py +64 -25
  12. python_minifier/rename/binding.py +237 -33
  13. python_minifier/rename/mapper.py +41 -12
  14. python_minifier/rename/rename_literals.py +45 -11
  15. python_minifier/rename/renamer.py +2 -2
  16. python_minifier/rename/resolve_names.py +57 -3
  17. python_minifier/rename/util.py +17 -16
  18. python_minifier/token_printer.py +299 -0
  19. python_minifier/transforms/combine_imports.py +8 -5
  20. python_minifier/transforms/constant_folding.py +114 -0
  21. python_minifier/transforms/remove_annotations.py +29 -5
  22. python_minifier/transforms/remove_annotations_options.py +35 -0
  23. python_minifier/transforms/remove_annotations_options.pyi +17 -0
  24. python_minifier/transforms/remove_asserts.py +26 -0
  25. python_minifier/transforms/remove_debug.py +53 -0
  26. python_minifier/transforms/remove_exception_brackets.py +124 -0
  27. python_minifier/transforms/remove_explicit_return_none.py +38 -0
  28. python_minifier/transforms/remove_literal_statements.py +3 -2
  29. python_minifier/transforms/remove_object_base.py +4 -1
  30. python_minifier/transforms/remove_pass.py +3 -2
  31. python_minifier/transforms/remove_posargs.py +1 -1
  32. python_minifier/transforms/suite_transformer.py +6 -51
  33. python_minifier/util.py +48 -0
  34. {python_minifier-2.4.2.dist-info → python_minifier-2.10.0.dist-info}/METADATA +9 -9
  35. python_minifier-2.10.0.dist-info/RECORD +44 -0
  36. {python_minifier-2.4.2.dist-info → python_minifier-2.10.0.dist-info}/WHEEL +1 -1
  37. {python_minifier-2.4.2.dist-info → python_minifier-2.10.0.dist-info}/entry_points.txt +0 -1
  38. python_minifier-2.4.2.dist-info/RECORD +0 -31
  39. {python_minifier-2.4.2.dist-info → python_minifier-2.10.0.dist-info}/LICENSE +0 -0
  40. {python_minifier-2.4.2.dist-info → python_minifier-2.10.0.dist-info}/top_level.txt +0 -0
  41. {python_minifier-2.4.2.dist-info → python_minifier-2.10.0.dist-info}/zip-safe +0 -0
@@ -4,7 +4,8 @@ a 'minified' representation of the same source code.
4
4
 
5
5
  """
6
6
 
7
- import ast
7
+ import python_minifier.ast_compat as ast
8
+ import re
8
9
 
9
10
  from python_minifier.ast_compare import CompareError, compare_ast
10
11
  from python_minifier.module_printer import ModulePrinter
@@ -17,8 +18,15 @@ from python_minifier.rename import (
17
18
  allow_rename_locals,
18
19
  add_namespace,
19
20
  )
21
+
20
22
  from python_minifier.transforms.combine_imports import CombineImports
23
+ from python_minifier.transforms.constant_folding import FoldConstants
21
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
22
30
  from python_minifier.transforms.remove_literal_statements import RemoveLiteralStatements
23
31
  from python_minifier.transforms.remove_object_base import RemoveObject
24
32
  from python_minifier.transforms.remove_pass import RemovePass
@@ -47,7 +55,7 @@ class UnstableMinification(RuntimeError):
47
55
  def minify(
48
56
  source,
49
57
  filename=None,
50
- remove_annotations=True,
58
+ remove_annotations=RemoveAnnotationsOptions(),
51
59
  remove_pass=True,
52
60
  remove_literal_statements=False,
53
61
  combine_imports=True,
@@ -58,6 +66,12 @@ def minify(
58
66
  preserve_globals=None,
59
67
  remove_object_base=True,
60
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
61
75
  ):
62
76
  """
63
77
  Minify a python module
@@ -71,7 +85,8 @@ def minify(
71
85
  :param str source: The python module source code
72
86
  :param str filename: The original source filename if known
73
87
 
74
- :param bool remove_annotations: If type annotations should be removed where possible
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
75
90
  :param bool remove_pass: If Pass statements should be removed where possible
76
91
  :param bool remove_literal_statements: If statements consisting of a single literal should be removed, including docstrings
77
92
  :param bool combine_imports: Combine adjacent import statements where possible
@@ -84,6 +99,12 @@ def minify(
84
99
  :type preserve_globals: list[str]
85
100
  :param bool remove_object_base: If object as a base class may be removed
86
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
87
108
 
88
109
  :rtype: str
89
110
 
@@ -102,8 +123,20 @@ def minify(
102
123
  if combine_imports:
103
124
  module = CombineImports()(module)
104
125
 
105
- if remove_annotations:
106
- module = RemoveAnnotations()(module)
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)
107
140
 
108
141
  if remove_pass:
109
142
  module = RemovePass()(module)
@@ -111,13 +144,40 @@ def minify(
111
144
  if remove_object_base:
112
145
  module = RemoveObject()(module)
113
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
+
114
159
  bind_names(module)
115
160
  resolve_names(module)
116
161
 
162
+ if remove_builtin_exception_brackets and not module.tainted:
163
+ remove_no_arg_exception_call(module)
164
+
117
165
  if module.tainted:
118
166
  rename_globals = False
119
167
  rename_locals = False
120
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
+
121
181
  allow_rename_locals(module, rename_locals, preserve_locals)
122
182
  allow_rename_globals(module, rename_globals, preserve_globals)
123
183
 
@@ -129,8 +189,30 @@ def minify(
129
189
  if convert_posargs_to_args:
130
190
  module = remove_posargs(module)
131
191
 
132
- return unparse(module)
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()
133
214
 
215
+ return None
134
216
 
135
217
  def unparse(module):
136
218
  """
@@ -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: ...
@@ -1,126 +1,330 @@
1
1
  from __future__ import print_function
2
2
 
3
- import sys
4
-
5
3
  import argparse
6
- from pkg_resources import get_distribution, DistributionNotFound
4
+ import os
5
+ import sys
7
6
 
8
7
  from python_minifier import minify
8
+ from python_minifier.transforms.remove_annotations_options import RemoveAnnotationsOptions
9
9
 
10
- try:
11
- version = get_distribution('python_minifier').version
12
- except DistributionNotFound:
13
- version = '0.0.0'
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'
14
22
 
15
23
 
16
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
17
35
 
18
- parser = argparse.ArgumentParser(prog='pyminify', description='Minify Python source')
36
+ # Minifying a file in place
37
+ pyminify example.py --in-place
19
38
 
20
- parser.add_argument('path', type=str, help='The source file to minify. Use "-" to read from stdin')
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__)
21
81
 
22
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(
23
106
  '--no-combine-imports',
24
107
  action='store_false',
25
108
  help='Disable combining adjacent import statements',
26
109
  dest='combine_imports',
27
110
  )
28
- parser.add_argument(
111
+ minification_options.add_argument(
29
112
  '--no-remove-pass',
30
113
  action='store_false',
31
114
  default=True,
32
115
  help='Disable removing Pass statements',
33
116
  dest='remove_pass',
34
117
  )
35
- parser.add_argument(
118
+ minification_options.add_argument(
36
119
  '--remove-literal-statements',
37
120
  action='store_true',
38
121
  help='Enable removing statements that are just a literal (including docstrings)',
39
122
  dest='remove_literal_statements',
40
123
  )
41
- parser.add_argument(
42
- '--no-remove-annotations',
43
- action='store_false',
44
- help='Disable removing function and variable annotations',
45
- dest='remove_annotations',
46
- )
47
- parser.add_argument(
124
+ minification_options.add_argument(
48
125
  '--no-hoist-literals',
49
126
  action='store_false',
50
127
  help='Disable replacing string and bytes literals with variables',
51
128
  dest='hoist_literals',
52
129
  )
53
- parser.add_argument(
54
- '--no-rename-locals', action='store_false', help='Disable shortening of local names', dest='rename_locals'
130
+ minification_options.add_argument(
131
+ '--no-rename-locals',
132
+ action='store_false',
133
+ help='Disable shortening of local names',
134
+ dest='rename_locals'
55
135
  )
56
- parser.add_argument(
136
+ minification_options.add_argument(
57
137
  '--preserve-locals',
58
138
  type=str,
59
139
  action='append',
60
140
  help='Comma separated list of local names that will not be shortened',
61
141
  dest='preserve_locals',
142
+ metavar='LOCAL_NAMES'
62
143
  )
63
- parser.add_argument(
64
- '--rename-globals', action='store_true', help='Enable shortening of global names', dest='rename_globals'
144
+ minification_options.add_argument(
145
+ '--rename-globals',
146
+ action='store_true',
147
+ help='Enable shortening of global names',
148
+ dest='rename_globals'
65
149
  )
66
- parser.add_argument(
150
+ minification_options.add_argument(
67
151
  '--preserve-globals',
68
152
  type=str,
69
153
  action='append',
70
154
  help='Comma separated list of global names that will not be shortened',
71
155
  dest='preserve_globals',
156
+ metavar='GLOBAL_NAMES'
72
157
  )
73
- parser.add_argument(
158
+ minification_options.add_argument(
74
159
  '--no-remove-object-base',
75
160
  action='store_false',
76
161
  help='Disable removing object from base class list',
77
162
  dest='remove_object_base',
78
163
  )
79
- parser.add_argument(
164
+ minification_options.add_argument(
80
165
  '--no-convert-posargs-to-args',
81
166
  action='store_false',
82
167
  help='Disable converting positional only arguments to normal arguments',
83
168
  dest='convert_posargs_to_args',
84
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
+ )
85
206
 
86
- parser.add_argument('-v', '--version', action='version', version=version)
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)
87
240
 
88
241
  args = parser.parse_args()
89
242
 
90
- if args.path == '-':
91
- source = sys.stdin.read()
92
- else:
93
- with open(args.path, 'rb') as f:
94
- source = f.read()
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):
95
280
 
96
281
  preserve_globals = []
97
- if args.preserve_globals:
98
- for arg in args.preserve_globals:
282
+ if minification_args.preserve_globals:
283
+ for arg in minification_args.preserve_globals:
99
284
  names = [name.strip() for name in arg.split(',') if name]
100
285
  preserve_globals.extend(names)
101
286
 
102
287
  preserve_locals = []
103
- if args.preserve_locals:
104
- for arg in args.preserve_locals:
288
+ if minification_args.preserve_locals:
289
+ for arg in minification_args.preserve_locals:
105
290
  names = [name.strip() for name in arg.split(',') if name]
106
291
  preserve_locals.extend(names)
107
292
 
108
- sys.stdout.write(
109
- minify(
110
- source,
111
- filename=args.path,
112
- combine_imports=args.combine_imports,
113
- remove_pass=args.remove_pass,
114
- remove_annotations=args.remove_annotations,
115
- remove_literal_statements=args.remove_literal_statements,
116
- hoist_literals=args.hoist_literals,
117
- rename_locals=args.rename_locals,
118
- preserve_locals=preserve_locals,
119
- rename_globals=args.rename_globals,
120
- preserve_globals=preserve_globals,
121
- remove_object_base=args.remove_object_base,
122
- convert_posargs_to_args=args.convert_posargs_to_args,
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,
123
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
124
328
  )
125
329
 
126
330
 
@@ -1,4 +1,6 @@
1
- import ast
1
+ import python_minifier.ast_compat as ast
2
+
3
+ from python_minifier.util import is_ast_node
2
4
 
3
5
 
4
6
  class CompareError(RuntimeError):
@@ -16,9 +18,7 @@ class CompareError(RuntimeError):
16
18
 
17
19
  def namespace(self, node):
18
20
  if hasattr(node, 'namespace'):
19
- if isinstance(node.namespace, (ast.FunctionDef, ast.ClassDef)) or (
20
- hasattr(ast, 'AsyncFunctionDef') and isinstance(node.namespace, ast.AsyncFunctionDef)
21
- ):
21
+ if is_ast_node(node.namespace, (ast.FunctionDef, ast.ClassDef, 'AsyncFunctionDef')):
22
22
  return self.namespace(node.namespace) + '.' + node.namespace.name
23
23
  elif isinstance(node.namespace, ast.Module):
24
24
  return ''
@@ -0,0 +1,40 @@
1
+ """
2
+ The is a backwards compatible shim for the ast module.
3
+
4
+ This is the best way to make the ast module work the same in both python 2 and 3.
5
+ This is essentially what the ast module was doing until 3.12, when it started throwing
6
+ deprecation warnings.
7
+ """
8
+
9
+ from ast import *
10
+
11
+ # Ideally we don't import anything else
12
+
13
+ if 'TypeAlias' in globals():
14
+
15
+ # Add n and s properties to Constant so it can stand in for Num, Str and Bytes
16
+ Constant.n = property(lambda self: self.value, lambda self, value: setattr(self, 'value', value)) # type: ignore[assignment]
17
+ Constant.s = property(lambda self: self.value, lambda self, value: setattr(self, 'value', value)) # type: ignore[assignment]
18
+
19
+ # These classes are redefined from the ones in ast that complain about deprecation
20
+ # They will continue to work once they are removed from ast
21
+
22
+ class Str(Constant): # type: ignore[no-redef]
23
+ def __new__(cls, s, *args, **kwargs):
24
+ return Constant(value=s, *args, **kwargs)
25
+
26
+ class Bytes(Constant): # type: ignore[no-redef]
27
+ def __new__(cls, s, *args, **kwargs):
28
+ return Constant(value=s, *args, **kwargs)
29
+
30
+ class Num(Constant): # type: ignore[no-redef]
31
+ def __new__(cls, n, *args, **kwargs):
32
+ return Constant(value=n, *args, **kwargs)
33
+
34
+ class NameConstant(Constant): # type: ignore[no-redef]
35
+ def __new__(cls, *args, **kwargs):
36
+ return Constant(*args, **kwargs)
37
+
38
+ class Ellipsis(Constant): # type: ignore[no-redef]
39
+ def __new__(cls, *args, **kwargs):
40
+ return Constant(value=literal_eval('...'), *args, **kwargs)