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,175 @@
1
+ """
2
+ For each node in an AST set the namespace to use for name binding and resolution
3
+ """
4
+
5
+ import python_minifier.ast_compat as ast
6
+
7
+ from python_minifier.rename.util import is_namespace
8
+ from python_minifier.util import is_ast_node
9
+
10
+
11
+ def add_parent_to_arguments(arguments, func):
12
+ arguments.parent = func
13
+ arguments.namespace = func
14
+
15
+ for arg in getattr(arguments, 'posonlyargs', []) + arguments.args:
16
+ add_parent(arg, arguments, func)
17
+ if hasattr(arg, 'annotation') and arg.annotation is not None:
18
+ add_parent(arg.annotation, arguments, func.namespace)
19
+
20
+ if hasattr(arguments, 'kwonlyargs'):
21
+ for arg in arguments.kwonlyargs:
22
+ add_parent(arg, arguments, func)
23
+ if arg.annotation is not None:
24
+ add_parent(arg.annotation, arguments, func.namespace)
25
+
26
+ for node in arguments.kw_defaults:
27
+ if node is not None:
28
+ add_parent(node, arguments, func.namespace)
29
+
30
+ for node in arguments.defaults:
31
+ add_parent(node, arguments, func.namespace)
32
+
33
+ if arguments.vararg:
34
+ if hasattr(arguments, 'varargannotation') and arguments.varargannotation is not None:
35
+ add_parent(arguments.varargannotation, arguments, func.namespace)
36
+ elif isinstance(arguments.vararg, str):
37
+ pass
38
+ else:
39
+ add_parent(arguments.vararg, arguments, func)
40
+
41
+ if arguments.kwarg:
42
+ if hasattr(arguments, 'kwargannotation') and arguments.kwargannotation is not None:
43
+ add_parent(arguments.kwargannotation, arguments, func.namespace)
44
+ elif isinstance(arguments.kwarg, str):
45
+ pass
46
+ else:
47
+ add_parent(arguments.kwarg, arguments, func)
48
+
49
+
50
+ def add_parent_to_functiondef(functiondef):
51
+ """
52
+ Add correct parent and namespace attributes to functiondef nodes
53
+ """
54
+
55
+ if functiondef.args is not None:
56
+ add_parent_to_arguments(functiondef.args, func=functiondef)
57
+
58
+ for node in functiondef.body:
59
+ add_parent(node, parent=functiondef, namespace=functiondef)
60
+
61
+ for node in functiondef.decorator_list:
62
+ add_parent(node, parent=functiondef, namespace=functiondef.namespace)
63
+
64
+ if hasattr(functiondef, 'type_params') and functiondef.type_params is not None:
65
+ for node in functiondef.type_params:
66
+ add_parent(node, parent=functiondef, namespace=functiondef.namespace)
67
+
68
+ if hasattr(functiondef, 'returns') and functiondef.returns is not None:
69
+ add_parent(functiondef.returns, parent=functiondef, namespace=functiondef.namespace)
70
+
71
+
72
+ def add_parent_to_classdef(classdef):
73
+ """
74
+ Add correct parent and namespace attributes to classdef nodes
75
+ """
76
+
77
+ for node in classdef.bases:
78
+ add_parent(node, parent=classdef, namespace=classdef.namespace)
79
+
80
+ if hasattr(classdef, 'keywords'):
81
+ for node in classdef.keywords:
82
+ add_parent(node, parent=classdef, namespace=classdef.namespace)
83
+
84
+ if hasattr(classdef, 'starargs') and classdef.starargs is not None:
85
+ add_parent(classdef.starargs, parent=classdef, namespace=classdef.namespace)
86
+
87
+ if hasattr(classdef, 'kwargs') and classdef.kwargs is not None:
88
+ add_parent(classdef.kwargs, parent=classdef, namespace=classdef.namespace)
89
+
90
+ for node in classdef.body:
91
+ add_parent(node, parent=classdef, namespace=classdef)
92
+
93
+ for node in classdef.decorator_list:
94
+ add_parent(node, parent=classdef, namespace=classdef.namespace)
95
+
96
+ if hasattr(classdef, 'type_params') and classdef.type_params is not None:
97
+ for node in classdef.type_params:
98
+ add_parent(node, parent=classdef, namespace=classdef.namespace)
99
+
100
+ def add_parent_to_comprehension(node, namespace):
101
+ assert is_ast_node(node, (ast.GeneratorExp, 'SetComp', 'DictComp', 'ListComp'))
102
+
103
+ if hasattr(node, 'elt'):
104
+ add_parent(node.elt, parent=node, namespace=node)
105
+ elif hasattr(node, 'key'):
106
+ add_parent(node.key, parent=node, namespace=node)
107
+ add_parent(node.value, parent=node, namespace=node)
108
+
109
+ iter_namespace = namespace
110
+ for generator in node.generators:
111
+ generator.parent = node
112
+ generator.namespace = node
113
+
114
+ add_parent(generator.target, parent=generator, namespace=node)
115
+ add_parent(generator.iter, parent=generator, namespace=iter_namespace)
116
+ iter_namespace = node
117
+ for if_ in generator.ifs:
118
+ add_parent(if_, parent=generator, namespace=node)
119
+
120
+
121
+ def add_parent(node, parent=None, namespace=None):
122
+ """
123
+ Add a parent attribute to child nodes
124
+ Add a namespace attribute to child nodes
125
+
126
+ :param node: The tree to add parent and namespace properties to
127
+ :type node: :class:`ast.AST`
128
+ :param parent: The parent node of this node
129
+ :type parent: :class:`ast.AST`
130
+ :param namespace: The namespace Node that this node is in
131
+ :type namespace: ast.Lambda or ast.Module or ast.FunctionDef or ast.AsyncFunctionDef or ast.ClassDef or ast.DictComp or ast.SetComp or ast.ListComp or ast.Generator
132
+
133
+ """
134
+
135
+ node.parent = parent if parent is not None else node
136
+ node.namespace = namespace if namespace is not None else node
137
+
138
+ if is_namespace(node):
139
+ node.bindings = []
140
+ node.global_names = set()
141
+ node.nonlocal_names = set()
142
+
143
+ if is_ast_node(node, (ast.FunctionDef, 'AsyncFunctionDef')):
144
+ add_parent_to_functiondef(node)
145
+ elif is_ast_node(node, (ast.GeneratorExp, 'SetComp', 'DictComp', 'ListComp')):
146
+ add_parent_to_comprehension(node, namespace=namespace)
147
+ elif isinstance(node, ast.Lambda):
148
+ add_parent_to_arguments(node.args, func=node)
149
+ add_parent(node.body, parent=node, namespace=node)
150
+ elif isinstance(node, ast.ClassDef):
151
+ add_parent_to_classdef(node)
152
+ else:
153
+ for child in ast.iter_child_nodes(node):
154
+ add_parent(child, parent=node, namespace=node)
155
+
156
+ return
157
+
158
+ if isinstance(node, ast.Global):
159
+ namespace.global_names.update(node.names)
160
+ if is_ast_node(node, 'Nonlocal'):
161
+ namespace.nonlocal_names.update(node.names)
162
+
163
+ if isinstance(node, ast.Name):
164
+ if isinstance(namespace, ast.ClassDef):
165
+ if isinstance(node.ctx, ast.Load):
166
+ namespace.nonlocal_names.add(node.id)
167
+ elif isinstance(node.ctx, ast.Store) and isinstance(node.parent, ast.AugAssign):
168
+ namespace.nonlocal_names.add(node.id)
169
+
170
+ for child in ast.iter_child_nodes(node):
171
+ add_parent(child, parent=node, namespace=namespace)
172
+
173
+
174
+ def add_namespace(module):
175
+ add_parent(module)
@@ -0,0 +1,51 @@
1
+ import itertools
2
+ import keyword
3
+ import random
4
+ import string
5
+
6
+ from python_minifier.rename.util import builtins
7
+
8
+
9
+ def random_generator(length=40):
10
+ valid_first = string.ascii_uppercase + string.ascii_lowercase
11
+ valid_rest = string.digits + valid_first + '_'
12
+
13
+ while True:
14
+ first = [random.choice(valid_first)]
15
+ rest = [random.choice(valid_rest) for i in range(length - 1)]
16
+ yield ''.join(first + rest)
17
+
18
+
19
+ def name_generator():
20
+ valid_first = string.ascii_uppercase + string.ascii_lowercase
21
+ valid_rest = string.digits + valid_first + '_'
22
+
23
+ for c in valid_first:
24
+ yield c
25
+
26
+ for length in itertools.count(1):
27
+ for first in valid_first:
28
+ for rest in itertools.product(valid_rest, repeat=length):
29
+ name = first
30
+ name += ''.join(rest)
31
+ yield name
32
+
33
+
34
+ def name_filter():
35
+ """
36
+ Yield all valid python identifiers
37
+
38
+ Name are returned sorted by length, then string sort order.
39
+
40
+ Names that already have meaning in python (keywords and builtins)
41
+ will not be included in the output.
42
+
43
+ :rtype: Iterable[str]
44
+
45
+ """
46
+
47
+ reserved = keyword.kwlist + dir(builtins)
48
+
49
+ for name in name_generator():
50
+ if name not in reserved:
51
+ yield name
@@ -0,0 +1,249 @@
1
+ import python_minifier.ast_compat as ast
2
+
3
+ from python_minifier.rename.binding import Binding
4
+ from python_minifier.rename.util import insert
5
+ from python_minifier.transforms.suite_transformer import NodeVisitor
6
+ from python_minifier.util import is_ast_node
7
+
8
+
9
+ def replace(old_node, new_node):
10
+ parent = old_node.parent
11
+ new_node.parent = parent
12
+ new_node.namespace = old_node.namespace
13
+
14
+ for field, old_value in ast.iter_fields(parent):
15
+ if old_value is old_node:
16
+ setattr(parent, field, new_node)
17
+ return
18
+
19
+ if isinstance(old_value, list):
20
+ for i, value in enumerate(old_value):
21
+ if value is old_node:
22
+ old_value[i] = new_node
23
+ return
24
+
25
+
26
+ class HoistedBinding(Binding):
27
+ def __init__(self, value_node, *args, **kwargs):
28
+ super(HoistedBinding, self).__init__(*args, **kwargs)
29
+ self._value_node = value_node
30
+ self._local_namespace = None
31
+
32
+ def __eq__(self, other):
33
+ return type(self.value) is type(other.value) and self.value == other.value
34
+
35
+ def __ne__(self, other):
36
+ return not self == other
37
+
38
+ def __hash__(self):
39
+ return hash(repr(self.value))
40
+
41
+ def set_local_namespace(self, node):
42
+ self._local_namespace = node
43
+
44
+ @property
45
+ def value(self):
46
+ if is_ast_node(self._value_node, (ast.Str, 'Bytes')):
47
+ return self._value_node.s
48
+ else:
49
+ return self._value_node.value
50
+
51
+ def __repr__(self):
52
+ return self.__class__.__name__ + '(value=%r)' % self.value
53
+
54
+ def new_mention_count(self):
55
+ # All mentions must be literals, which would be replaced
56
+ # Plus an Assign with the new name
57
+ return len(self.references) + 1
58
+
59
+ def old_mention_count(self):
60
+ # For hoisted bindings, the old 'name' is the literal
61
+ # It would be mentioned once, in the Assign
62
+ return 1
63
+
64
+ def additional_byte_cost(self):
65
+ return 2 # '=' + '\n'
66
+
67
+ def rename(self, new_name):
68
+
69
+ for node in self.references:
70
+ replace(node, ast.Name(id=new_name, ctx=ast.Load()))
71
+
72
+ self._local_namespace.body = list(
73
+ insert(
74
+ self._local_namespace.body,
75
+ ast.Assign(targets=[ast.Name(id=new_name, ctx=ast.Store())], value=self._value_node),
76
+ )
77
+ )
78
+
79
+ self._name = new_name
80
+
81
+ def should_rename(self, new_name):
82
+ current_cost = len(self.references) * len(repr(self.value))
83
+ rename_cost = (self.old_mention_count() * len(repr(self.value))) + ((self.new_mention_count()) * len(new_name)) + self.additional_byte_cost()
84
+
85
+ return rename_cost <= current_cost
86
+
87
+ class HoistedValue(object):
88
+ """
89
+ HoistedValue comparator object
90
+
91
+ This is for wrapping a value in a set or dict key, and
92
+ ensures different types hash differently, even if they compare equal.
93
+
94
+ The problematic values are str/bytes/unicode and int/float.
95
+
96
+ """
97
+
98
+ def __init__(self, value):
99
+ self._value = value
100
+
101
+ def __hash__(self):
102
+ return hash(str(type(self._value)) + str(hash(self._value)))
103
+
104
+ def __eq__(self, other):
105
+ return type(self._value) == type(other._value) and self._value == other._value
106
+
107
+ def __ne__(self, other):
108
+ return not self == other
109
+
110
+
111
+ class HoistLiterals(NodeVisitor):
112
+ """
113
+ Hoist literal strings to module level variables
114
+ """
115
+
116
+ def __call__(self, module, ignore_slots=True):
117
+ self.module = module
118
+ self._ignore_slots = ignore_slots
119
+ self._hoisted = {}
120
+ self.visit(module)
121
+ self.place_bindings()
122
+
123
+ def nearest_function_namespace(self, node):
124
+ """
125
+ Return the namespace node for the nearest function scope.
126
+
127
+ This could be itself.
128
+
129
+ :param node: The node to get the function namespace of
130
+ :type node: ast.Node
131
+ :rtype: ast.Node
132
+
133
+ """
134
+
135
+ if is_ast_node(node.namespace, (ast.FunctionDef, ast.Module, 'AsyncFunctionDef')):
136
+ return node.namespace
137
+ return self.nearest_function_namespace(node.namespace)
138
+
139
+ def namespace_path(self, node):
140
+ """
141
+ Return the path of function namespace nodes from the module node down to the input node
142
+
143
+ With the source module:
144
+ >>> def a():
145
+ ... def b():
146
+ ... c
147
+
148
+ >>> namespace_path(c)
149
+ [a, b, c]
150
+
151
+ :param node:
152
+ :type node: ast.Node
153
+ :rtype: list[ast.AST]
154
+
155
+ """
156
+
157
+ l = []
158
+
159
+ while True:
160
+ namespace = self.nearest_function_namespace(node)
161
+ l.insert(0, namespace)
162
+
163
+ if isinstance(namespace, ast.Module):
164
+ break
165
+
166
+ node = namespace
167
+
168
+ return l
169
+
170
+ def common_path(self, n1_path, n2_path):
171
+
172
+ path = []
173
+ for n1_step, n2_step in zip(n1_path, n2_path):
174
+ if n1_step is not n2_step:
175
+ return path
176
+ path.append(n1_step)
177
+ return path
178
+
179
+ def place_bindings(self):
180
+ for binding in self._hoisted.values():
181
+
182
+ namespace_path = []
183
+
184
+ for node in binding.references:
185
+ if not namespace_path:
186
+ namespace_path = self.namespace_path(node)
187
+ else:
188
+ namespace_path = self.common_path(namespace_path, self.namespace_path(node))
189
+
190
+ namespace_path[-1].bindings.append(binding)
191
+ binding.set_local_namespace(namespace_path[-1])
192
+
193
+ def get_binding(self, value, node):
194
+ hoisted_value = HoistedValue(value)
195
+ if hoisted_value in self._hoisted:
196
+ return self._hoisted[hoisted_value]
197
+
198
+ binding = HoistedBinding(node)
199
+ self._hoisted[hoisted_value] = binding
200
+ return binding
201
+
202
+ def visit_Str(self, node):
203
+
204
+ if isinstance(node.parent, ast.Expr):
205
+ # This is literal statement
206
+ # The RemoveLiteralStatements transformer must have left it here, so ignore it.
207
+ return
208
+
209
+ self.get_binding(node.s, node).add_reference(node)
210
+
211
+ def visit_Bytes(self, node):
212
+ self.visit_Str(node)
213
+
214
+ def visit_JoinedStr(self, node):
215
+ for v in node.values:
216
+ if is_ast_node(v, ast.Str):
217
+ # Can't hoist this!
218
+ continue
219
+ else:
220
+ self.visit(v)
221
+
222
+ def visit_NameConstant(self, node):
223
+ self.get_binding(node.value, node).add_reference(node)
224
+
225
+ def visit_match_case(self, node):
226
+ # Can't hoist literals in a pattern
227
+
228
+ if node.guard is not None:
229
+ self.visit(node.guard)
230
+
231
+ for n in node.body:
232
+ self.visit(n)
233
+
234
+ def visit_Assign(self, node):
235
+ if not self._ignore_slots:
236
+ return self.generic_visit(node)
237
+
238
+ if not is_ast_node(node.namespace, ast.ClassDef):
239
+ return self.generic_visit(node)
240
+
241
+ for target in node.targets:
242
+ if is_ast_node(target, ast.Name) and target.id == '__slots__':
243
+ # This is a __slots__ assignment, don't hoist the literals
244
+ return
245
+
246
+ return self.generic_visit(node)
247
+
248
+ def rename_literals(module):
249
+ HoistLiterals()(module)
@@ -0,0 +1,230 @@
1
+ import python_minifier.ast_compat as ast
2
+
3
+ from python_minifier.rename.binding import NameBinding
4
+ from python_minifier.rename.name_generator import name_filter
5
+ from python_minifier.rename.util import is_namespace
6
+
7
+
8
+ def all_bindings(node):
9
+ """
10
+ All bindings in a module
11
+
12
+ :param node: The module to get bindings in
13
+ :type node: :class:`ast.AST`
14
+ :rtype: Iterable[ast.AST, Binding]
15
+
16
+ """
17
+
18
+ if is_namespace(node):
19
+ for binding in node.bindings:
20
+ yield node, binding
21
+
22
+ for child in ast.iter_child_nodes(node):
23
+ for namespace, binding in all_bindings(child):
24
+ yield namespace, binding
25
+
26
+
27
+ def sorted_bindings(module):
28
+ """
29
+ All bindings in a modules sorted by descending number of references
30
+
31
+ :param module: The module to get bindings in
32
+ :type module: :class:`ast.AST`
33
+ :rtype: Iterable[ast.AST, Binding]
34
+
35
+ """
36
+
37
+ def comp(tup):
38
+ namespace, binding = tup
39
+ return binding.new_mention_count()
40
+
41
+ return sorted(all_bindings(module), key=comp, reverse=True)
42
+
43
+
44
+ def reservation_scope(namespace, binding):
45
+ """
46
+ Get the namespaces that are in the bindings reservation scope
47
+
48
+ Returns the namespace nodes the binding name must be resolvable in
49
+
50
+ :param namespace: The local namespace of a binding
51
+ :type namespace: :class:`ast.AST`
52
+ :param binding: The binding to get the reservation scope for
53
+ :type binding: Binding
54
+ :rtype: set[ast.AST]
55
+
56
+ """
57
+
58
+ namespaces = set([namespace])
59
+
60
+ for node in binding.references:
61
+ while node is not namespace:
62
+ namespaces.add(node.namespace)
63
+ node = node.namespace
64
+
65
+ return namespaces
66
+
67
+
68
+ def add_assigned(node):
69
+ """
70
+ Add the assigned_names attribute to namespace nodes in a module
71
+
72
+ :param node: The module to add the assigned_names attribute to
73
+ :type node: :class:`ast.Module`
74
+
75
+ """
76
+
77
+ if is_namespace(node):
78
+ node.assigned_names = set()
79
+
80
+ for child in ast.iter_child_nodes(node):
81
+ add_assigned(child)
82
+
83
+
84
+ def reserve_name(name, reservation_scope):
85
+ """
86
+ Reserve a name in a reservation scope
87
+
88
+ :param str name: The name to reserve
89
+ :param reservation_scope:
90
+ :type reservation_scope: Iterable[:class:`ast.AST`]
91
+
92
+ """
93
+
94
+ for namespace in reservation_scope:
95
+ namespace.assigned_names.add(name)
96
+
97
+
98
+ class UniqueNameAssigner(object):
99
+ """
100
+ Assign new names to renamed bindings
101
+
102
+ Assigns a unique name to every binding
103
+ """
104
+
105
+ def __init__(self):
106
+ self.name_generator = name_filter()
107
+ self.names = []
108
+
109
+ def available_name(self):
110
+ return next(self.name_generator)
111
+
112
+ def __call__(self, module):
113
+ assert isinstance(module, ast.Module)
114
+
115
+ for namespace, binding in sorted_bindings(module):
116
+ if binding.allow_rename:
117
+ binding.new_name = self.available_name()
118
+
119
+ return module
120
+
121
+
122
+ class NameAssigner(object):
123
+ """
124
+ Assign new names to renamed bindings
125
+
126
+ This assigner creates a name 'reservation scope' containing each namespace a binding is referenced in, including
127
+ transitive namespaces. Bindings are then assigned the first available name that has no references in their
128
+ reservation scope. This means names will be reused in sibling namespaces, and shadowed where possible in child
129
+ namespaces.
130
+
131
+ Bindings are assigned names in order of most references, with names assigned shortest first.
132
+
133
+ """
134
+
135
+ def __init__(self, name_generator=None):
136
+ self.name_generator = name_generator if name_generator is not None else name_filter()
137
+ self.names = []
138
+
139
+ def iter_names(self):
140
+ for name in self.names:
141
+ yield name
142
+
143
+ while True:
144
+ name = next(self.name_generator)
145
+ self.names.append(name)
146
+ yield name
147
+
148
+ def available_name(self, reservation_scope, prefix=''):
149
+ """
150
+ Search for the first name that is not in reservation scope
151
+ """
152
+
153
+ for name in self.iter_names():
154
+ if self.is_available(prefix + name, reservation_scope):
155
+ return prefix + name
156
+
157
+ def is_available(self, name, reservation_scope):
158
+ """
159
+ Is a name unreserved in a reservation scope
160
+
161
+ :param str name: the name to check availability of
162
+ :param reservation_scope: The scope to check
163
+ :type reservation_scope: Iterable[:class:`ast.AST`]
164
+ :rtype: bool
165
+
166
+ """
167
+
168
+ for namespace in reservation_scope:
169
+ if name in namespace.assigned_names:
170
+ return False
171
+
172
+ return True
173
+
174
+ def __call__(self, module, prefix_globals, reserved_globals=None):
175
+ assert isinstance(module, ast.Module)
176
+ add_assigned(module)
177
+
178
+ for namespace, binding in all_bindings(module):
179
+ if binding.reserved is not None:
180
+ scope = reservation_scope(namespace, binding)
181
+ reserve_name(binding.reserved, scope)
182
+
183
+ if reserved_globals is not None:
184
+ for name in reserved_globals:
185
+ module.assigned_names.add(name)
186
+
187
+ for namespace, binding in sorted_bindings(module):
188
+ scope = reservation_scope(namespace, binding)
189
+
190
+ if binding.allow_rename:
191
+
192
+ if isinstance(namespace, ast.Module) and prefix_globals:
193
+ name = self.available_name(scope, prefix='_')
194
+ else:
195
+ name = self.available_name(scope)
196
+
197
+ def should_rename():
198
+ if binding.should_rename(name):
199
+ return True
200
+
201
+ # It's no longer efficient to do this rename
202
+
203
+ if isinstance(binding, NameBinding):
204
+ # Check that the original name is still available
205
+
206
+ if binding.reserved == binding.name:
207
+ # We already reserved it (this is probably an arg)
208
+ return False
209
+
210
+ if not self.is_available(binding.name, scope):
211
+ # The original name has already been assigned to another binding,
212
+ # so we need to rename this anyway.
213
+ return True
214
+
215
+ return False
216
+
217
+ if should_rename():
218
+ binding.rename(name)
219
+ else:
220
+ # Any existing name will become reserved
221
+ binding.disallow_rename()
222
+
223
+ if binding.name is not None:
224
+ reserve_name(binding.name, scope)
225
+
226
+ return module
227
+
228
+
229
+ def rename(module, prefix_globals=False, preserved_globals=None):
230
+ NameAssigner()(module, prefix_globals, preserved_globals)