summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2021-10-27 08:51:43 -0400
committerNed Batchelder <ned@nedbatchelder.com>2021-10-27 09:12:30 -0400
commit055a9f4b38aebdabc8cb80dcc40a5b29b8f71781 (patch)
tree2ef5112132ccebdb9bb0e9553fddd8de8d20c93f
parent15aff0ad7d6c92851bc21fc39863a3949edbb9c6 (diff)
downloadpython-coveragepy-git-055a9f4b38aebdabc8cb80dcc40a5b29b8f71781.tar.gz
fix(debug): ast_dump failed on a few things
-rw-r--r--coverage/parser.py7
-rw-r--r--tests/stress_phystoken.tok10
-rw-r--r--tests/test_parser.py37
-rw-r--r--tests/test_phystokens.py6
4 files changed, 42 insertions, 18 deletions
diff --git a/coverage/parser.py b/coverage/parser.py
index 80665b5a..ec788c06 100644
--- a/coverage/parser.py
+++ b/coverage/parser.py
@@ -1306,7 +1306,7 @@ def _is_simple_value(value):
"""Is `value` simple enough to be displayed on a single line?"""
return (
value in [None, [], (), {}, set()] or
- isinstance(value, (str, int, float))
+ isinstance(value, (bytes, int, float, str))
)
def ast_dump(node, depth=0, print=print): # pylint: disable=redefined-builtin
@@ -1352,7 +1352,10 @@ def ast_dump(node, depth=0, print=print): # pylint: disable=redefined-builtin
elif isinstance(value, list):
print(f"{prefix} [")
for n in value:
- ast_dump(n, depth + 8, print=print)
+ if _is_simple_value(n):
+ print(f"{next_indent} {n!r}")
+ else:
+ ast_dump(n, depth + 8, print=print)
print(f"{next_indent}]")
else:
print(prefix)
diff --git a/tests/stress_phystoken.tok b/tests/stress_phystoken.tok
index f2b190c3..65ba45db 100644
--- a/tests/stress_phystoken.tok
+++ b/tests/stress_phystoken.tok
@@ -4,6 +4,7 @@
# Here's some random Python so that test_tokenize_myself will have some
# stressful stuff to try. This file is .tok instead of .py so pylint won't
# complain about it, check_eol won't look at it, etc.
+# Some lines are here to reproduce fixed bugs in ast_dump also.
first_back = """\
hey there!
@@ -50,6 +51,15 @@ a_long_string = \
"3 is longer"
def hello():
+ global x # ast_dump bug
print("Hello world!")
hello()
+
+# ast dump bugs:
+weird = {
+ **d,
+ **{'c': 7},
+ 'd': 8,
+}
+self.hash.update(b'.')
diff --git a/tests/test_parser.py b/tests/test_parser.py
index ff7d9ef9..3197ffb4 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -4,7 +4,6 @@
"""Tests for coverage.py's code parsing."""
import os.path
-import re
import textwrap
import pytest
@@ -14,7 +13,7 @@ from coverage.exceptions import NotPython
from coverage.parser import ast_dump, ast_parse, PythonParser
from tests.coveragetest import CoverageTest, TESTS_DIR
-from tests.helpers import arcz_to_arcs
+from tests.helpers import arcz_to_arcs, re_lines
class PythonParserTest(CoverageTest):
@@ -485,17 +484,23 @@ def test_ast_dump():
# Run the AST_DUMP code to make sure it doesn't fail, with some light
# assertions. Use parser.py as the test code since it is the longest file,
# and fitting, since it's the AST_DUMP code.
- parser_py = os.path.join(TESTS_DIR, "../coverage/parser.py")
- with open(parser_py) as f:
- ast_root = ast_parse(f.read())
- result = []
- ast_dump(ast_root, print=result.append)
- assert len(result) > 10000
- assert result[0] == "<Module"
- assert result[-1] == ">"
-
- def count(pat):
- return sum(1 for line in result if re.search(pat, line))
-
- assert count(r"^\s+>") > 2000
- assert count(r"<Name @ \d+,\d+(:\d+)? id: '\w+'>") > 1000
+ files = [
+ os.path.join(TESTS_DIR, "../coverage/parser.py"),
+ os.path.join(TESTS_DIR, "stress_phystoken.tok"),
+ ]
+ for fname in files:
+ with open(fname) as f:
+ source = f.read()
+ num_lines = len(source.splitlines())
+ print(f"file {fname} has {num_lines} lines")
+ ast_root = ast_parse(source)
+ result = []
+ ast_dump(ast_root, print=result.append)
+ if num_lines < 100:
+ continue
+ assert len(result) > 5 * num_lines
+ assert result[0] == "<Module"
+ assert result[-1] == ">"
+ result_text = "\n".join(result)
+ assert len(re_lines(result_text, r"^\s+>")) > num_lines
+ assert len(re_lines(result_text, r"<Name @ \d+,\d+(:\d+)? id: '\w+'>")) > num_lines // 2
diff --git a/tests/test_phystokens.py b/tests/test_phystokens.py
index 3c214c63..fea581a5 100644
--- a/tests/test_phystokens.py
+++ b/tests/test_phystokens.py
@@ -15,6 +15,7 @@ from coverage.phystokens import neuter_encoding_declaration, compile_unicode
from coverage.python import get_python_source
from tests.coveragetest import CoverageTest, TESTS_DIR
+from tests.helpers import re_lines
# A simple program and its token stream.
@@ -97,10 +98,15 @@ class PhysTokensTest(CoverageTest):
def test_stress(self):
# Check the tokenization of a stress-test file.
+ # And check that those files haven't been incorrectly "fixed".
stress = os.path.join(TESTS_DIR, "stress_phystoken.tok")
self.check_file_tokenization(stress)
+ with open(stress) as fstress:
+ assert re_lines(fstress.read(), r"\s$"), f"{stress} needs a trailing space."
stress = os.path.join(TESTS_DIR, "stress_phystoken_dos.tok")
self.check_file_tokenization(stress)
+ with open(stress) as fstress:
+ assert re_lines(fstress.read(), r"\s$"), f"{stress} needs a trailing space."
@pytest.mark.skipif(not env.PYBEHAVIOR.soft_keywords, reason="Soft keywords are new in Python 3.10")