Skip to content

Commit dafebf1

Browse files
committed
refactor: no need for our own AST dump function
1 parent 1a04c58 commit dafebf1

File tree

3 files changed

+7
-120
lines changed

3 files changed

+7
-120
lines changed

coverage/parser.py

+4-72
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,10 @@ def __init__(
690690
# Dump the AST so that failing tests have helpful output.
691691
print(f"Statements: {self.statements}")
692692
print(f"Multiline map: {self.multiline}")
693-
ast_dump(self.root_node)
693+
dumpkw: Dict[str, Any] = {}
694+
if sys.version_info >= (3, 9):
695+
dumpkw["indent"] = 4
696+
print(ast.dump(self.root_node, include_attributes=True, **dumpkw))
694697

695698
self.arcs: Set[TArc] = set()
696699

@@ -1350,74 +1353,3 @@ def _code_object__ClassDef(self, node: ast.ClassDef) -> None:
13501353
_code_object__DictComp = _make_expression_code_method("dictionary comprehension")
13511354
_code_object__SetComp = _make_expression_code_method("set comprehension")
13521355
_code_object__ListComp = _make_expression_code_method("list comprehension")
1353-
1354-
1355-
# Code only used when dumping the AST for debugging.
1356-
1357-
SKIP_DUMP_FIELDS = ["ctx"]
1358-
1359-
def _is_simple_value(value: Any) -> bool:
1360-
"""Is `value` simple enough to be displayed on a single line?"""
1361-
return (
1362-
value in [None, [], (), {}, set(), frozenset(), Ellipsis] or
1363-
isinstance(value, (bytes, int, float, str))
1364-
)
1365-
1366-
def ast_dump(
1367-
node: ast.AST,
1368-
depth: int = 0,
1369-
print: Callable[[str], None] = print, # pylint: disable=redefined-builtin
1370-
) -> None:
1371-
"""Dump the AST for `node`.
1372-
1373-
This recursively walks the AST, printing a readable version.
1374-
1375-
"""
1376-
indent = " " * depth
1377-
lineno = getattr(node, "lineno", None)
1378-
if lineno is not None:
1379-
linemark = f" @ {node.lineno},{node.col_offset}"
1380-
if hasattr(node, "end_lineno"):
1381-
assert hasattr(node, "end_col_offset")
1382-
linemark += ":"
1383-
if node.end_lineno != node.lineno:
1384-
linemark += f"{node.end_lineno},"
1385-
linemark += f"{node.end_col_offset}"
1386-
else:
1387-
linemark = ""
1388-
head = f"{indent}<{node.__class__.__name__}{linemark}"
1389-
1390-
named_fields = [
1391-
(name, value)
1392-
for name, value in ast.iter_fields(node)
1393-
if name not in SKIP_DUMP_FIELDS
1394-
]
1395-
if not named_fields:
1396-
print(f"{head}>")
1397-
elif len(named_fields) == 1 and _is_simple_value(named_fields[0][1]):
1398-
field_name, value = named_fields[0]
1399-
print(f"{head} {field_name}: {value!r}>")
1400-
else:
1401-
print(head)
1402-
if 0:
1403-
print("{}# mro: {}".format( # type: ignore[unreachable]
1404-
indent, ", ".join(c.__name__ for c in node.__class__.__mro__[1:]),
1405-
))
1406-
next_indent = indent + " "
1407-
for field_name, value in named_fields:
1408-
prefix = f"{next_indent}{field_name}:"
1409-
if _is_simple_value(value):
1410-
print(f"{prefix} {value!r}")
1411-
elif isinstance(value, list):
1412-
print(f"{prefix} [")
1413-
for n in value:
1414-
if _is_simple_value(n):
1415-
print(f"{next_indent} {n!r}")
1416-
else:
1417-
ast_dump(n, depth + 8, print=print)
1418-
print(f"{next_indent}]")
1419-
else:
1420-
print(prefix)
1421-
ast_dump(value, depth + 8, print=print)
1422-
1423-
print(f"{indent}>")

lab/show_ast.py

-11
This file was deleted.

tests/test_parser.py

+3-37
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,16 @@
55

66
from __future__ import annotations
77

8-
import ast
9-
import os.path
108
import textwrap
11-
import warnings
12-
13-
from typing import List
149

1510
import pytest
1611

1712
from coverage import env
1813
from coverage.exceptions import NotPython
19-
from coverage.parser import ast_dump, PythonParser
14+
from coverage.parser import PythonParser
2015

21-
from tests.coveragetest import CoverageTest, TESTS_DIR
22-
from tests.helpers import arcz_to_arcs, re_lines, xfail_pypy38
16+
from tests.coveragetest import CoverageTest
17+
from tests.helpers import arcz_to_arcs, xfail_pypy38
2318

2419

2520
class PythonParserTest(CoverageTest):
@@ -517,32 +512,3 @@ def test_missing_line_ending(self) -> None:
517512

518513
parser = self.parse_file("abrupt.py")
519514
assert parser.statements == {1}
520-
521-
522-
def test_ast_dump() -> None:
523-
# Run the AST_DUMP code to make sure it doesn't fail, with some light
524-
# assertions. Use parser.py as the test code since it is the longest file,
525-
# and fitting, since it's the AST_DUMP code.
526-
import coverage.parser
527-
files = [
528-
coverage.parser.__file__,
529-
os.path.join(TESTS_DIR, "stress_phystoken.tok"),
530-
]
531-
for fname in files:
532-
with open(fname) as f:
533-
source = f.read()
534-
num_lines = len(source.splitlines())
535-
with warnings.catch_warnings():
536-
# stress_phystoken.tok has deprecation warnings, suppress them.
537-
warnings.filterwarnings("ignore", message=r".*invalid escape sequence")
538-
ast_root = ast.parse(source)
539-
result: List[str] = []
540-
ast_dump(ast_root, print=result.append)
541-
if num_lines < 100:
542-
continue
543-
assert len(result) > 5 * num_lines
544-
assert result[0] == "<Module"
545-
assert result[-1] == ">"
546-
result_text = "\n".join(result)
547-
assert len(re_lines(r"^\s+>", result_text)) > num_lines
548-
assert len(re_lines(r"<Name @ \d+,\d+(:\d+)? id: '\w+'>", result_text)) > num_lines // 2

0 commit comments

Comments
 (0)