diff options
Diffstat (limited to 'Lib/test/test_peg_generator/ast_dump.py')
-rw-r--r-- | Lib/test/test_peg_generator/ast_dump.py | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/Lib/test/test_peg_generator/ast_dump.py b/Lib/test/test_peg_generator/ast_dump.py new file mode 100644 index 00000000000..22d2dde7755 --- /dev/null +++ b/Lib/test/test_peg_generator/ast_dump.py @@ -0,0 +1,62 @@ +""" +Copy-parse of ast.dump, removing the `isinstance` checks. This is needed, +because testing pegen requires generating a C extension module, which contains +a copy of the symbols defined in Python-ast.c. Thus, the isinstance check would +always fail. We rely on string comparison of the base classes instead. +TODO: Remove the above-described hack. +""" + +def ast_dump(node, annotate_fields=True, include_attributes=False, *, indent=None): + def _format(node, level=0): + if indent is not None: + level += 1 + prefix = '\n' + indent * level + sep = ',\n' + indent * level + else: + prefix = '' + sep = ', ' + if any(cls.__name__ == 'AST' for cls in node.__class__.__mro__): + cls = type(node) + args = [] + allsimple = True + keywords = annotate_fields + for name in node._fields: + try: + value = getattr(node, name) + except AttributeError: + keywords = True + continue + if value is None and getattr(cls, name, ...) is None: + keywords = True + continue + value, simple = _format(value, level) + allsimple = allsimple and simple + if keywords: + args.append('%s=%s' % (name, value)) + else: + args.append(value) + if include_attributes and node._attributes: + for name in node._attributes: + try: + value = getattr(node, name) + except AttributeError: + continue + if value is None and getattr(cls, name, ...) is None: + continue + value, simple = _format(value, level) + allsimple = allsimple and simple + args.append('%s=%s' % (name, value)) + if allsimple and len(args) <= 3: + return '%s(%s)' % (node.__class__.__name__, ', '.join(args)), not args + return '%s(%s%s)' % (node.__class__.__name__, prefix, sep.join(args)), False + elif isinstance(node, list): + if not node: + return '[]', True + return '[%s%s]' % (prefix, sep.join(_format(x, level)[0] for x in node)), False + return repr(node), True + + if all(cls.__name__ != 'AST' for cls in node.__class__.__mro__): + raise TypeError('expected AST, got %r' % node.__class__.__name__) + if indent is not None and not isinstance(indent, str): + indent = ' ' * indent + return _format(node)[0] |