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
File without changes
@@ -0,0 +1,6 @@
1
+ from python_minifier.rename.bind_names import bind_names
2
+ from python_minifier.rename.mapper import add_namespace
3
+ from python_minifier.rename.rename_literals import rename_literals
4
+ from python_minifier.rename.renamer import rename
5
+ from python_minifier.rename.resolve_names import resolve_names
6
+ from python_minifier.rename.util import allow_rename_locals, allow_rename_globals
@@ -0,0 +1,192 @@
1
+ import python_minifier.ast_compat as ast
2
+
3
+ from python_minifier.rename.binding import NameBinding
4
+ from python_minifier.rename.util import arg_rename_in_place, get_global_namespace, get_nonlocal_namespace, builtins
5
+ from python_minifier.transforms.suite_transformer import NodeVisitor
6
+
7
+
8
+ class NameBinder(NodeVisitor):
9
+ """
10
+ Create a NameBinding for each name that is bound
11
+
12
+ The NameBinding is added to the bindings dictionary in the namespace node the name is local to.
13
+ """
14
+
15
+ def __call__(self, module):
16
+ assert isinstance(module, ast.Module)
17
+ module.tainted = False
18
+ module.preserved = set()
19
+ return self.visit(module)
20
+
21
+ def get_binding(self, name, namespace):
22
+ if name in namespace.global_names and not isinstance(namespace, ast.Module):
23
+ return self.get_binding(name, get_global_namespace(namespace))
24
+
25
+ # nonlocal names should not create a binding in any context
26
+ assert name not in namespace.nonlocal_names
27
+
28
+ for binding in namespace.bindings:
29
+ if binding.name == name:
30
+ break
31
+ else: # weeee!
32
+ binding = NameBinding(name)
33
+ namespace.bindings.append(binding)
34
+
35
+ if name in dir(builtins):
36
+ binding.disallow_rename()
37
+
38
+ if name in namespace.nonlocal_names and isinstance(namespace, ast.Module):
39
+ # This is actually a syntax error - but we want the same syntax error after minifying!
40
+ binding.disallow_rename()
41
+
42
+ if isinstance(namespace, ast.ClassDef):
43
+ # This name will become an attribute of the class, so it can't be renamed
44
+ binding.disallow_rename()
45
+
46
+ return binding
47
+
48
+ def visit_Name(self, node):
49
+ if node.id in node.namespace.nonlocal_names:
50
+ # A nonlocal name does not create a binding.
51
+ # We will resolve the binding later
52
+ return
53
+
54
+ if isinstance(node.ctx, (ast.Store, ast.Del)):
55
+ self.get_binding(node.id, node.namespace).add_reference(node)
56
+
57
+ if isinstance(node.ctx, ast.Param):
58
+ binding = self.get_binding(node.id, node.namespace)
59
+
60
+ if arg_rename_in_place(node):
61
+ binding.add_reference(node)
62
+ else:
63
+ binding.add_reference(node, reserved=node.id)
64
+
65
+ if isinstance(node.namespace, ast.Lambda):
66
+ # Lambda function arguments can't be renamed without breaking keyword arguments
67
+ binding.disallow_rename()
68
+
69
+ def visit_ClassDef(self, node):
70
+ if node.name not in node.namespace.nonlocal_names:
71
+ self.get_binding(node.name, node.namespace).add_reference(node)
72
+ self.generic_visit(node)
73
+
74
+ def visit_FunctionDef(self, node):
75
+ if node.name not in node.namespace.nonlocal_names:
76
+ self.get_binding(node.name, node.namespace).add_reference(node)
77
+ self.generic_visit(node)
78
+
79
+ def visit_AsyncFunctionDef(self, node):
80
+ self.visit_FunctionDef(node)
81
+
82
+ def visit_alias(self, node):
83
+ if node.name == '*':
84
+ get_global_namespace(node).tainted = True
85
+
86
+ root_module = node.name.split('.')[0]
87
+
88
+ if root_module == 'timeit':
89
+ get_global_namespace(node).tainted = True
90
+
91
+ if node.asname is not None:
92
+ if node.asname not in node.namespace.nonlocal_names:
93
+ self.get_binding(node.asname, node.namespace).add_reference(node)
94
+ else:
95
+ # This binds the root module only for a dotted import
96
+
97
+ if root_module not in node.namespace.nonlocal_names:
98
+ binding = self.get_binding(root_module, node.namespace)
99
+ binding.add_reference(node)
100
+
101
+ if '.' in node.name:
102
+ binding.disallow_rename()
103
+
104
+ def visit_arguments(self, node):
105
+ # varargs, kwarg can't be nonlocal
106
+ if isinstance(node.vararg, str):
107
+ binding = self.get_binding(node.vararg, node.namespace)
108
+ binding.add_reference(node)
109
+
110
+ if isinstance(node.kwarg, str):
111
+ binding = self.get_binding(node.kwarg, node.namespace)
112
+ binding.add_reference(node)
113
+
114
+ self.generic_visit(node)
115
+
116
+ def visit_arg(self, node):
117
+ # Args can't be nonlocal
118
+ binding = self.get_binding(node.arg, node.namespace)
119
+
120
+ if arg_rename_in_place(node):
121
+ binding.add_reference(node)
122
+ else:
123
+ binding.add_reference(node, reserved=node.arg)
124
+
125
+ if isinstance(node.namespace, ast.Lambda):
126
+ # Lambda function arguments can't be renamed without breaking keyword arguments
127
+ binding.disallow_rename()
128
+
129
+ self.generic_visit(node)
130
+
131
+ def visit_ExceptHandler(self, node):
132
+ if node.name is not None:
133
+ if isinstance(node.name, str) and node.name not in node.namespace.nonlocal_names:
134
+ # python 3
135
+ self.get_binding(node.name, node.namespace).add_reference(node)
136
+ else:
137
+ # In python 2 the name is a Name node,
138
+ # which will be visited by generic_visit
139
+ pass
140
+
141
+ self.generic_visit(node)
142
+
143
+ def visit_Global(self, node):
144
+ for name in node.names:
145
+ self.get_binding(name, node.namespace).add_reference(node)
146
+
147
+ def visit_MatchAs(self, node):
148
+ if node.name is not None and node.name not in node.namespace.nonlocal_names:
149
+ self.get_binding(node.name, node.namespace).add_reference(node)
150
+
151
+ self.generic_visit(node)
152
+
153
+ def visit_MatchStar(self, node):
154
+ if node.name is not None and node.name not in node.namespace.nonlocal_names:
155
+ self.get_binding(node.name, node.namespace).add_reference(node)
156
+
157
+ self.generic_visit(node)
158
+
159
+ def visit_MatchMapping(self, node):
160
+ if node.rest is not None and node.rest not in node.namespace.nonlocal_names:
161
+ self.get_binding(node.rest, node.namespace).add_reference(node)
162
+
163
+ self.generic_visit(node)
164
+
165
+ def visit_TypeVar(self, node):
166
+ if node.name not in node.namespace.nonlocal_names:
167
+ self.get_binding(node.name, node.namespace).add_reference(node)
168
+
169
+ get_global_namespace(node.namespace).preserved.add(node.name)
170
+
171
+ def visit_TypeVarTuple(self, node):
172
+ if node.name not in node.namespace.nonlocal_names:
173
+ self.get_binding(node.name, node.namespace).add_reference(node)
174
+
175
+ get_global_namespace(node.namespace).preserved.add(node.name)
176
+
177
+ def visit_ParamSpec(self, node):
178
+ if node.name not in node.namespace.nonlocal_names:
179
+ self.get_binding(node.name, node.namespace).add_reference(node)
180
+
181
+ get_global_namespace(node.namespace).preserved.add(node.name)
182
+
183
+ def bind_names(module):
184
+ """
185
+ Bind names to their local namespace
186
+
187
+ :param module: The module to bind names in
188
+ :type: :class:`ast.Module`
189
+
190
+ """
191
+
192
+ NameBinder()(module)
@@ -0,0 +1,495 @@
1
+ import python_minifier.ast_compat as ast
2
+
3
+ from python_minifier.rename.util import arg_rename_in_place, insert
4
+ from python_minifier.util import is_ast_node
5
+
6
+
7
+ class Binding(object):
8
+ """
9
+ Represents the binding of a name
10
+
11
+ :param name: A name for this binding
12
+ :type name: str or None
13
+ :param bool allow_rename: If this binding may be renamed
14
+
15
+ """
16
+
17
+ def __init__(self, name=None, allow_rename=True):
18
+ self._references = []
19
+
20
+ self._allow_rename = allow_rename
21
+
22
+ self._name = name
23
+ self._reserved = None
24
+
25
+ def __repr__(self):
26
+ return self.__class__.__name__ + '()'
27
+
28
+ @property
29
+ def name(self):
30
+ """
31
+ The name for this binding
32
+
33
+ This may be changed using the rename() method.
34
+ If this binding doesn't currently have a name, this returns None.
35
+
36
+ :rtype: str or None
37
+
38
+ """
39
+
40
+ return self._name
41
+
42
+ @property
43
+ def allow_rename(self):
44
+ """
45
+ Is it allowed to rename this binding
46
+
47
+ :rtype: bool
48
+
49
+ """
50
+
51
+ return self._allow_rename
52
+
53
+ def disallow_rename(self):
54
+ """
55
+ Prevent this binding from being renamed
56
+ """
57
+
58
+ self._allow_rename = False
59
+
60
+ @property
61
+ def reserved(self):
62
+ """
63
+ A reserved name for this binding
64
+
65
+ This may be a name which this binding reserves in it's reservation scope,
66
+ regardless of if it is renamed.
67
+
68
+ :rtype: str or None
69
+
70
+ """
71
+
72
+ return self._reserved
73
+
74
+ @property
75
+ def references(self):
76
+ """
77
+ The ast Nodes that reference this binding
78
+
79
+ :rtype: list[ast.AST]
80
+
81
+ """
82
+
83
+ return self._references
84
+
85
+ @property
86
+ def name_references(self):
87
+ """
88
+ The number of times the name is used
89
+ """
90
+ return len(self._references)
91
+
92
+ def additional_byte_cost(self):
93
+ """
94
+ How many additional bytes would be used, if this was renamed
95
+ """
96
+
97
+ arg_rename = False
98
+ additional_bytes = 0
99
+
100
+ for node in self._references:
101
+ if isinstance(node, ast.Name):
102
+ if isinstance(node.ctx, (ast.Load, ast.Store, ast.Del)):
103
+ pass
104
+ else:
105
+ # Python 2 Param context
106
+ if not arg_rename_in_place(node):
107
+ arg_rename = True
108
+ elif is_ast_node(node, (ast.ClassDef, ast.FunctionDef, 'AsyncFunctionDef')):
109
+ pass
110
+ elif isinstance(node, ast.ExceptHandler):
111
+ pass
112
+ elif is_ast_node(node, (ast.Global, 'Nonlocal')):
113
+ pass
114
+ elif isinstance(node, ast.alias):
115
+ if node.asname is None:
116
+ additional_bytes += 4 # ' as '
117
+ elif isinstance(node, ast.arguments):
118
+ if node.vararg == self._name:
119
+ pass
120
+ if node.kwarg == self._name:
121
+ pass
122
+ elif is_ast_node(node, 'arg'):
123
+ if not arg_rename_in_place(node):
124
+ arg_rename = True
125
+
126
+ elif is_ast_node(node, 'MatchAs'):
127
+ if node.name is None:
128
+ additional_bytes += 4 # ' as '
129
+ elif is_ast_node(node, 'MatchStar'):
130
+ pass
131
+ elif is_ast_node(node, 'MatchMapping'):
132
+ pass
133
+ elif is_ast_node(node, 'TypeVar'):
134
+ pass
135
+ elif is_ast_node(node, 'TypeVarTuple'):
136
+ pass
137
+ elif is_ast_node(node, 'ParamSpec'):
138
+ pass
139
+
140
+ else:
141
+ raise AssertionError('Unknown reference node')
142
+
143
+ return additional_bytes + (2 if arg_rename else 0)
144
+
145
+ def old_mention_count(self):
146
+ """
147
+ The number of times the old name would be mentioned in the source code, if this binding was renamed
148
+ """
149
+
150
+ arg_rename = False
151
+ mentions = 0
152
+
153
+ for node in self._references:
154
+ if isinstance(node, ast.Name):
155
+ if isinstance(node.ctx, (ast.Load, ast.Store, ast.Del)):
156
+ pass
157
+ else:
158
+ # Python 2 Param context
159
+ if not arg_rename_in_place(node):
160
+ mentions += 1
161
+ arg_rename = True
162
+
163
+ elif is_ast_node(node, (ast.ClassDef, ast.FunctionDef, 'AsyncFunctionDef')):
164
+ pass
165
+ elif isinstance(node, ast.ExceptHandler):
166
+ pass
167
+ elif is_ast_node(node, (ast.Global, 'Nonlocal')):
168
+ pass
169
+ elif isinstance(node, ast.alias):
170
+ if node.asname is None:
171
+ # import foo -> import foo as bar
172
+ mentions += 1
173
+ elif isinstance(node, ast.arguments):
174
+ pass
175
+ elif is_ast_node(node, 'arg'):
176
+ if not arg_rename_in_place(node):
177
+ mentions += 1
178
+ arg_rename = True
179
+
180
+ elif is_ast_node(node, 'MatchAs'):
181
+ pass
182
+ elif is_ast_node(node, 'MatchStar'):
183
+ pass
184
+ elif is_ast_node(node, 'MatchMapping'):
185
+ pass
186
+ elif is_ast_node(node, 'TypeVar'):
187
+ pass
188
+ elif is_ast_node(node, 'TypeVarTuple'):
189
+ pass
190
+ elif is_ast_node(node, 'ParamSpec'):
191
+ pass
192
+
193
+ else:
194
+ raise AssertionError('Unknown reference node')
195
+
196
+ return mentions + (1 if arg_rename else 0)
197
+
198
+ def new_mention_count(self):
199
+ """
200
+ The number of times a new name would be mentioned in the source code
201
+ """
202
+
203
+ arg_rename = False
204
+ mentions = 0
205
+
206
+ for node in self._references:
207
+ if isinstance(node, ast.Name):
208
+ if isinstance(node.ctx, (ast.Load, ast.Store, ast.Del)):
209
+ mentions += 1
210
+ else:
211
+ # Python 2 Param context
212
+ arg_rename = True
213
+ elif is_ast_node(node, (ast.ClassDef, ast.FunctionDef, 'AsyncFunctionDef')):
214
+ mentions += 1
215
+ elif isinstance(node, ast.ExceptHandler):
216
+ mentions += 1
217
+ elif is_ast_node(node, (ast.Global, 'Nonlocal')):
218
+ mentions += len([n for n in node.names if n == self._name])
219
+ elif isinstance(node, ast.alias):
220
+ mentions += 1
221
+ elif isinstance(node, ast.arguments):
222
+ if node.vararg == self._name:
223
+ mentions += 1
224
+ if node.kwarg == self._name:
225
+ mentions += 1
226
+ elif is_ast_node(node, 'arg'):
227
+ arg_rename = True
228
+
229
+ elif is_ast_node(node, 'MatchAs'):
230
+ mentions += 1
231
+ elif is_ast_node(node, 'MatchStar'):
232
+ mentions += 1
233
+ elif is_ast_node(node, 'MatchMapping'):
234
+ mentions += 1
235
+ elif is_ast_node(node, 'TypeVar'):
236
+ mentions += 1
237
+ elif is_ast_node(node, 'TypeVarTuple'):
238
+ mentions += 1
239
+ elif is_ast_node(node, 'ParamSpec'):
240
+ mentions += 1
241
+
242
+ else:
243
+ raise AssertionError('Unknown reference node')
244
+
245
+ return mentions + (1 if arg_rename else 0)
246
+
247
+ def add_reference(self, node, allow_rename=True, reserved=None):
248
+ """
249
+ Add a new reference to this binding
250
+
251
+ :param node: The node that references this binding
252
+ :type node: :class:`ast.AST`
253
+ :param bool allow_rename: If this binding may be renamed
254
+ :param str reserved: A name used by the node, even if the binding is renamed.
255
+ :param int rename_cost: Additional cost of renaming the reference, in bytes
256
+
257
+ """
258
+
259
+ self.references.append(node)
260
+
261
+ if allow_rename is False:
262
+ self.disallow_rename()
263
+
264
+ if reserved is not None:
265
+ self._reserved = reserved
266
+
267
+ def should_rename(self, new_name):
268
+ """
269
+ Is it space efficient to rename this binding
270
+
271
+ :param str new_name: The candidate name
272
+ :rtype: bool
273
+
274
+ """
275
+
276
+ raise NotImplementedError()
277
+
278
+ def rename(self, new_name):
279
+ """
280
+ Rename this binding and all nodes that reference it
281
+
282
+ :param str new_name: The new name to use
283
+
284
+ """
285
+
286
+ raise NotImplementedError()
287
+
288
+
289
+ class NameBinding(Binding):
290
+ """
291
+ Represents the binding of a defined name
292
+
293
+ A NameBinding will be attached to the local namespace that defines it.
294
+
295
+ :param str name: The original bound name
296
+ :param bool allow_rename: If this binding may be renamed
297
+ :param int rename_cost: The cost of renaming this binding in bytes
298
+
299
+ """
300
+
301
+ def __init__(self, name, *args, **kwargs):
302
+ super(NameBinding, self).__init__(name, *args, **kwargs)
303
+
304
+ if name.startswith('__') and name.endswith('__'):
305
+ # System defined name
306
+ self.disallow_rename()
307
+
308
+ def __repr__(self):
309
+ return self.__class__.__name__ + '(name=%r, allow_rename=%r) <references=%r>' % (self._name, self._allow_rename, len(self._references))
310
+
311
+ def should_rename(self, new_name):
312
+ """
313
+ Is it space efficient to rename this binding
314
+
315
+ :param str new_name: The candidate name
316
+ :rtype: bool
317
+
318
+ """
319
+
320
+ current_cost = len(self.references) * len(self._name)
321
+
322
+ old_mentions = self.old_mention_count()
323
+ new_mentions = self.new_mention_count()
324
+ additional_bytes = self.additional_byte_cost()
325
+ rename_cost = (old_mentions * len(self._name)) + (new_mentions * len(new_name)) + additional_bytes
326
+
327
+ return rename_cost <= current_cost
328
+
329
+ def disallow_rename(self):
330
+ """
331
+ Prevent this binding from being renamed
332
+ """
333
+
334
+ super(NameBinding, self).disallow_rename()
335
+ self._reserved = self._name
336
+
337
+ def rename(self, new_name):
338
+ """
339
+ Rename this binding and all nodes that reference it
340
+
341
+ :param str new_name: The new name to use
342
+
343
+ """
344
+
345
+ func_namespace_binding = None
346
+
347
+ for node in self.references:
348
+
349
+ if isinstance(node, ast.Name):
350
+
351
+ if isinstance(node.ctx, (ast.Load, ast.Store, ast.Del)):
352
+ node.id = new_name
353
+ else:
354
+ # Python 2 Param context
355
+
356
+ if arg_rename_in_place(node):
357
+ node.id = new_name
358
+
359
+ else:
360
+ if func_namespace_binding is None:
361
+ func_namespace_binding = node.namespace
362
+ else:
363
+ assert func_namespace_binding is node.namespace
364
+
365
+ elif is_ast_node(node, (ast.FunctionDef, 'AsyncFunctionDef')):
366
+ node.name = new_name
367
+ elif isinstance(node, ast.ClassDef):
368
+ node.name = new_name
369
+ elif isinstance(node, ast.alias):
370
+ if new_name == node.name:
371
+ node.asname = None
372
+ else:
373
+ node.asname = new_name
374
+ elif is_ast_node(node, 'arg'):
375
+
376
+ if arg_rename_in_place(node):
377
+ node.arg = new_name
378
+
379
+ else:
380
+ if func_namespace_binding is None:
381
+ func_namespace_binding = node.namespace
382
+ else:
383
+ assert func_namespace_binding is node.namespace
384
+
385
+ elif isinstance(node, ast.ExceptHandler):
386
+ node.name = new_name
387
+ elif is_ast_node(node, (ast.Global, 'Nonlocal')):
388
+ node.names = [new_name if n == self._name else n for n in node.names]
389
+ elif isinstance(node, ast.arguments):
390
+
391
+ rename_vararg = (node.vararg == self._name) and not getattr(node, 'vararg_renamed', False)
392
+ rename_kwarg = (node.kwarg == self._name) and not getattr(node, 'kwarg_renamed', False)
393
+
394
+ if rename_vararg:
395
+ node.vararg = new_name
396
+ node.vararg_renamed = True
397
+ if rename_kwarg:
398
+ node.kwarg = new_name
399
+ node.kwarg_renamed = True
400
+
401
+ elif is_ast_node(node, 'MatchAs'):
402
+ node.name = new_name
403
+ elif is_ast_node(node, 'MatchStar'):
404
+ node.name = new_name
405
+ elif is_ast_node(node, 'MatchMapping'):
406
+ node.rest = new_name
407
+ elif is_ast_node(node, 'TypeVar'):
408
+ node.name = new_name
409
+ elif is_ast_node(node, 'TypeVarTuple'):
410
+ node.name = new_name
411
+ elif is_ast_node(node, 'ParamSpec'):
412
+ node.name = new_name
413
+
414
+ if func_namespace_binding is not None:
415
+ func_namespace_binding.body = list(
416
+ insert(
417
+ func_namespace_binding.body,
418
+ ast.Assign(
419
+ targets=[ast.Name(id=new_name, ctx=ast.Store())],
420
+ value=ast.Name(id=self._name, ctx=ast.Load()),
421
+ ),
422
+ )
423
+ )
424
+
425
+ self._name = new_name
426
+
427
+
428
+ class BuiltinBinding(NameBinding):
429
+ """
430
+ Represents the usage of a builtin
431
+
432
+ :param str name: The name of the builtin
433
+ :param namespace: The module the builtin is used in
434
+ :type namespace: :class:`ast.Module`
435
+
436
+ """
437
+
438
+ def __init__(self, name, namespace, *args, **kwargs):
439
+ super(BuiltinBinding, self).__init__(name, *args, **kwargs)
440
+ self.namespace = namespace
441
+
442
+ # These builtins actually act like keywords, so should not be changed
443
+ if name == 'super':
444
+ # If we replace 'super' with another name the compiler will neglect to create the
445
+ # __class__ implicit closure reference, breaking the zero argument super() call.
446
+ self.disallow_rename()
447
+ elif name == 'object':
448
+ # Classes must inherit from object to become a new-style class in python2
449
+ self.disallow_rename()
450
+
451
+ def new_mention_count(self):
452
+ # All mentions must be Names, which would be replaced
453
+ # Plus an Assign with the new name
454
+ return len(self.references) + 1
455
+
456
+ def old_mention_count(self):
457
+ # The old name would be mentioned in the Assign
458
+ return 1
459
+
460
+ def additional_byte_cost(self):
461
+ return 2 # '=' + '\n'
462
+
463
+ def rename(self, new_name):
464
+ builtin = self._name
465
+ super(BuiltinBinding, self).rename(new_name)
466
+ self.namespace.body = list(
467
+ insert(
468
+ self.namespace.body,
469
+ ast.Assign(
470
+ targets=[ast.Name(id=new_name, ctx=ast.Store())], value=ast.Name(id=builtin, ctx=ast.Load())
471
+ ),
472
+ )
473
+ )
474
+
475
+ def is_redefined(self):
476
+ """
477
+ Do one of the references to this builtin name redefine it?
478
+
479
+ Could some references actually not be references to the builtin?
480
+
481
+ This can happen with code like:
482
+
483
+ class MyClass:
484
+ IndexError = IndexError
485
+
486
+ """
487
+
488
+ for node in self.references:
489
+ if not isinstance(node, ast.Name):
490
+ return True
491
+
492
+ if not isinstance(node.ctx, ast.Load):
493
+ return True
494
+
495
+ return False