Skip to content

Commit e1f614b

Browse files
authored
Merge pull request #116 from dflook/stub-missing-nodes
Create dummy AST nodes when they are not present
2 parents c8a4d66 + 947a777 commit e1f614b

22 files changed

Lines changed: 184 additions & 168 deletions

src/python_minifier/ast_compare.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import python_minifier.ast_compat as ast
22

3-
from python_minifier.util import is_ast_node
4-
53

64
class CompareError(RuntimeError):
75
"""
@@ -18,7 +16,7 @@ def __repr__(self):
1816

1917
def namespace(self, node):
2018
if hasattr(node, 'namespace'):
21-
if is_ast_node(node.namespace, (ast.FunctionDef, ast.ClassDef, 'AsyncFunctionDef')):
19+
if isinstance(node.namespace, (ast.FunctionDef, ast.ClassDef, ast.AsyncFunctionDef)):
2220
return self.namespace(node.namespace) + '.' + node.namespace.name
2321
elif isinstance(node.namespace, ast.Module):
2422
return ''

src/python_minifier/ast_compat.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,35 @@ def __new__(cls, *args, **kwargs):
4444
class Ellipsis(Constant): # type: ignore[no-redef]
4545
def __new__(cls, *args, **kwargs):
4646
return Constant(value=literal_eval('...'), *args, **kwargs)
47+
48+
49+
# Create a dummy class for missing AST nodes
50+
for _node_type in [
51+
'AnnAssign',
52+
'AsyncFor',
53+
'AsyncFunctionDef',
54+
'AsyncFunctionDef',
55+
'AsyncWith',
56+
'Bytes',
57+
'Constant',
58+
'DictComp',
59+
'Exec',
60+
'ListComp',
61+
'MatchAs',
62+
'MatchMapping',
63+
'MatchStar',
64+
'NameConstant',
65+
'NamedExpr',
66+
'Nonlocal',
67+
'ParamSpec',
68+
'SetComp',
69+
'Starred',
70+
'TryStar',
71+
'TypeVar',
72+
'TypeVarTuple',
73+
'YieldFrom',
74+
'arg',
75+
'withitem',
76+
]:
77+
if _node_type not in globals():
78+
globals()[_node_type] = type(_node_type, (AST,), {})

src/python_minifier/ast_printer.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
import python_minifier.ast_compat as ast
1414

15-
from python_minifier.util import is_ast_node
15+
from python_minifier.util import is_constant_node
1616

1717

1818
INDENT = ' '
@@ -69,16 +69,16 @@ def is_literal(node, field):
6969
if hasattr(ast, 'Constant') and isinstance(node, ast.Constant) and field == 'value':
7070
return True
7171

72-
if is_ast_node(node, ast.Num) and field == 'n':
72+
if is_constant_node(node, ast.Num) and field == 'n':
7373
return True
7474

75-
if is_ast_node(node, ast.Str) and field == 's':
75+
if is_constant_node(node, ast.Str) and field == 's':
7676
return True
7777

78-
if is_ast_node(node, 'Bytes') and field == 's':
78+
if is_constant_node(node, ast.Bytes) and field == 's':
7979
return True
8080

81-
if is_ast_node(node, 'NameConstant') and field == 'value':
81+
if is_constant_node(node, ast.NameConstant) and field == 'value':
8282
return True
8383

8484
return False

src/python_minifier/expression_printer.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import python_minifier.ast_compat as ast
44

55
from python_minifier.token_printer import Delimiter, TokenPrinter
6-
from python_minifier.util import is_ast_node
6+
from python_minifier.util import is_constant_node
77

88

99
class ExpressionPrinter(object):
@@ -69,7 +69,7 @@ def precedence(self, node):
6969

7070
# Python2 parses negative ints as an ast.Num with a negative value.
7171
# Make sure the Num get the precedence of the USub operator in this case.
72-
if sys.version_info < (3, 0) and is_ast_node(node, ast.Num):
72+
if sys.version_info < (3, 0) and is_constant_node(node, ast.Num):
7373
if str(node.n)[0] == '-':
7474
return self.precedences['USub']
7575

@@ -208,7 +208,7 @@ def visit_Starred(self, node):
208208
def visit_UnaryOp(self, node):
209209
self.visit(node.op)
210210

211-
if sys.version_info < (3, 0) and isinstance(node.op, ast.USub) and is_ast_node(node.operand, ast.Num):
211+
if sys.version_info < (3, 0) and isinstance(node.op, ast.USub) and is_constant_node(node.operand, ast.Num):
212212
# For: -(1), which is parsed as a UnaryOp(USub, Num(1)).
213213
# Without this special case it would be printed as -1
214214
# This is fine, but python 2 will then parse it at Num(-1) so the AST wouldn't round-trip.
@@ -428,7 +428,7 @@ def visit_Attribute(self, node):
428428
value_precedence = self.precedence(node.value)
429429
attr_precedence = self.precedence(node)
430430

431-
if (value_precedence != 0 and (attr_precedence > value_precedence)) or is_ast_node(node.value, ast.Num):
431+
if (value_precedence != 0 and (attr_precedence > value_precedence)) or is_constant_node(node.value, ast.Num):
432432
self.printer.delimiter('(')
433433
self._expression(node.value)
434434
self.printer.delimiter(')')
@@ -462,7 +462,7 @@ def visit_Subscript(self, node):
462462
self.visit_Slice(node.slice)
463463
elif isinstance(node.slice, ast.ExtSlice):
464464
self.visit_ExtSlice(node.slice)
465-
elif is_ast_node(node.slice, ast.Ellipsis):
465+
elif is_constant_node(node.slice, ast.Ellipsis):
466466
self.visit_Ellipsis(node)
467467
elif sys.version_info >= (3, 9) and isinstance(node.slice, ast.Tuple):
468468
self.visit_Tuple(node.slice)
@@ -649,27 +649,27 @@ def visit_Expression(self, node):
649649
self._expression(node.body)
650650

651651
def _expression(self, expression):
652-
if is_ast_node(expression, (ast.Yield, 'YieldFrom')):
652+
if isinstance(expression, (ast.Yield, ast.YieldFrom)):
653653
self.printer.delimiter('(')
654654
self._yield_expr(expression)
655655
self.printer.delimiter(')')
656656
elif isinstance(expression, ast.Tuple) and len(expression.elts) > 0:
657657
self.printer.delimiter('(')
658658
self.visit_Tuple(expression)
659659
self.printer.delimiter(')')
660-
elif is_ast_node(expression, 'NamedExpr'):
660+
elif isinstance(expression, ast.NamedExpr):
661661
self.printer.delimiter('(')
662662
self.visit_NamedExpr(expression)
663663
self.printer.delimiter(')')
664664
else:
665665
self.visit(expression)
666666

667667
def _testlist(self, test):
668-
if is_ast_node(test, (ast.Yield, 'YieldFrom')):
668+
if isinstance(test, (ast.Yield, ast.YieldFrom)):
669669
self.printer.delimiter('(')
670670
self._yield_expr(test)
671671
self.printer.delimiter(')')
672-
elif is_ast_node(test, 'NamedExpr'):
672+
elif isinstance(test, ast.NamedExpr):
673673
self.printer.delimiter('(')
674674
self.visit_NamedExpr(test)
675675
self.printer.delimiter(')')

src/python_minifier/f_string.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from python_minifier.expression_printer import ExpressionPrinter
1717
from python_minifier.ministring import MiniString
1818
from python_minifier.token_printer import TokenTypes
19-
from python_minifier.util import is_ast_node
19+
from python_minifier.util import is_constant_node
2020

2121

2222
class FString(object):
@@ -70,7 +70,7 @@ def candidates(self):
7070
nested_allowed.remove(quote)
7171

7272
for v in self.node.values:
73-
if is_ast_node(v, ast.Str):
73+
if is_constant_node(v, ast.Str):
7474

7575
# Could this be used as a debug specifier?
7676
if len(candidates) < 10:
@@ -348,7 +348,7 @@ def candidates(self):
348348

349349
candidates = ['']
350350
for v in self.node.values:
351-
if is_ast_node(v, ast.Str):
351+
if is_constant_node(v, ast.Str):
352352
candidates = [x + self.str_for(v.s) for x in candidates]
353353
elif isinstance(v, ast.FormattedValue):
354354
candidates = [

src/python_minifier/module_printer.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
from .expression_printer import ExpressionPrinter
66
from .token_printer import Delimiter
7-
from .util import is_ast_node
87

98

109
class ModulePrinter(ExpressionPrinter):
@@ -56,7 +55,7 @@ def visit_Exec(self, node):
5655
def visit_Expr(self, node):
5756
assert isinstance(node, ast.Expr)
5857

59-
if is_ast_node(node.value, (ast.Yield, 'YieldFrom')):
58+
if isinstance(node.value, (ast.Yield, ast.YieldFrom)):
6059
self._yield_expr(node.value)
6160
else:
6261
self._testlist(node.value)
@@ -83,7 +82,7 @@ def visit_Assign(self, node):
8382
self.printer.delimiter('=')
8483

8584
# Yield nodes that are the sole node on the right hand side of an assignment do not need parens
86-
if is_ast_node(node.value, (ast.Yield, 'YieldFrom')):
85+
if isinstance(node.value, (ast.Yield, ast.YieldFrom)):
8786
self._yield_expr(node.value)
8887
else:
8988
self._testlist(node.value)
@@ -98,7 +97,7 @@ def visit_AugAssign(self, node):
9897
self.printer.delimiter('=')
9998

10099
# Yield nodes that are the sole node on the right hand side of an assignment do not need parens
101-
if is_ast_node(node.value, (ast.Yield, 'YieldFrom')):
100+
if isinstance(node.value, (ast.Yield, ast.YieldFrom)):
102101
self._yield_expr(node.value)
103102
else:
104103
self._testlist(node.value)
@@ -144,7 +143,7 @@ def visit_Return(self, node):
144143

145144
self.printer.keyword('return')
146145
if isinstance(node.value, ast.Tuple):
147-
if sys.version_info < (3, 8) and [n for n in node.value.elts if is_ast_node(n, 'Starred')]:
146+
if sys.version_info < (3, 8) and [n for n in node.value.elts if isinstance(n, ast.Starred)]:
148147
self.printer.delimiter('(')
149148
self._testlist(node.value)
150149
self.printer.delimiter(')')
@@ -327,7 +326,7 @@ def visit_If(self, node, el=False):
327326
self._suite(node.orelse)
328327

329328
def visit_For(self, node, is_async=False):
330-
assert isinstance(node, ast.For) or (hasattr(ast, 'AsyncFor') and isinstance(node, ast.AsyncFor))
329+
assert isinstance(node, (ast.For, ast.AsyncFor))
331330

332331
self.printer.newline()
333332

@@ -363,7 +362,7 @@ def visit_While(self, node):
363362
self._suite(node.orelse)
364363

365364
def visit_Try(self, node, star=False):
366-
assert is_ast_node(node, (ast.Try, 'TryStar'))
365+
assert isinstance(node, (ast.Try, ast.TryStar))
367366

368367
self.printer.newline()
369368
self.printer.keyword('try')
@@ -441,7 +440,7 @@ def visit_ExceptHandler(self, node, star=False):
441440
self._suite(node.body)
442441

443442
def visit_With(self, node, is_async=False):
444-
assert is_ast_node(node, (ast.With, 'AsyncWith'))
443+
assert isinstance(node, (ast.With, ast.AsyncWith))
445444

446445
self.printer.newline()
447446

@@ -470,7 +469,7 @@ def visit_With(self, node, is_async=False):
470469
self._suite(node.body)
471470

472471
def visit_withitem(self, node):
473-
assert is_ast_node(node, ('withitem', ast.With))
472+
assert isinstance(node, (ast.withitem, ast.With))
474473

475474
self._expression(node.context_expr)
476475

@@ -479,7 +478,7 @@ def visit_withitem(self, node):
479478
self._expression(node.optional_vars)
480479

481480
def visit_FunctionDef(self, node, is_async=False):
482-
assert is_ast_node(node, (ast.FunctionDef, 'AsyncFunctionDef'))
481+
assert isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef))
483482

484483
self.printer.newline()
485484

0 commit comments

Comments
 (0)