Skip to content

Commit

Permalink
Make sure combined imports maintain the same namespace
Browse files Browse the repository at this point in the history
  • Loading branch information
dflook committed Aug 30, 2024
1 parent ff618da commit a61bbbd
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 192 deletions.
11 changes: 7 additions & 4 deletions src/python_minifier/transforms/combine_imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,22 @@ class CombineImports(SuiteTransformer):
def _combine_import(self, node_list, parent):

alias = []
namespace = None

for statement in node_list:
namespace = statement.namespace
if isinstance(statement, ast.Import):
alias += statement.names
else:
if alias:
yield self.add_child(ast.Import(names=alias), parent=parent)
yield self.add_child(ast.Import(names=alias), parent=parent, namespace=namespace)
alias = []

yield statement

if alias:
yield self.add_child(ast.Import(names=alias), parent=parent)
yield self.add_child(ast.Import(names=alias), parent=parent, namespace=namespace)


def _combine_import_from(self, node_list, parent):

Expand Down Expand Up @@ -55,15 +58,15 @@ def combine(statement):
else:
if alias:
yield self.add_child(
ast.ImportFrom(module=prev_import.module, names=alias, level=prev_import.level), parent=parent
ast.ImportFrom(module=prev_import.module, names=alias, level=prev_import.level), parent=parent, namespace=prev_import.namespace
)
alias = []

yield statement

if alias:
yield self.add_child(
ast.ImportFrom(module=prev_import.module, names=alias, level=prev_import.level), parent=parent
ast.ImportFrom(module=prev_import.module, names=alias, level=prev_import.level), parent=parent, namespace=prev_import.namespace
)

def suite(self, node_list, parent):
Expand Down
50 changes: 50 additions & 0 deletions test/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import ast

from python_minifier.rename import add_namespace, resolve_names
from python_minifier.rename.bind_names import bind_names
from python_minifier.rename.util import iter_child_namespaces
from python_minifier.util import is_ast_node


def assert_namespace_tree(source, expected_tree):
tree = ast.parse(source)

add_namespace(tree)
bind_names(tree)
resolve_names(tree)

actual = print_namespace(tree)

print(actual)
assert actual.strip() == expected_tree.strip()


def print_namespace(namespace, indent=''):
s = ''

if not indent:
s += '\n'

def namespace_name(node):
if is_ast_node(node, (ast.FunctionDef, 'AsyncFunctionDef')):
return 'Function ' + node.name
elif isinstance(node, ast.ClassDef):
return 'Class ' + node.name
else:
return namespace.__class__.__name__

s += indent + '+ ' + namespace_name(namespace) + '\n'

for name in sorted(namespace.global_names):
s += indent + ' - global ' + name + '\n'

for name in sorted(namespace.nonlocal_names):
s += indent + ' - nonlocal ' + name + '\n'

for binding in sorted(namespace.bindings, key=lambda b: b.name):
s += indent + ' - ' + repr(binding) + '\n'

for child in iter_child_namespaces(namespace):
s += print_namespace(child, indent=indent + ' ')

return s
Loading

0 comments on commit a61bbbd

Please sign in to comment.