1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
|
"""Test pure Python parser against cpython parser."""
import ast
import difflib
import io
import sys
import textwrap
import tokenize
from pathlib import Path
import pytest
@pytest.mark.parametrize(
"filename",
[
pytest.param(
"advanced_decorators.py",
marks=pytest.mark.skipif(
sys.version_info < (3, 9), reason="Valid only in Python 3.9+"
),
),
"assignment.py",
"async.py",
"call.py",
"comprehensions.py",
"expressions.py",
"fstrings.py",
"function_def.py",
"imports.py",
"lambdas.py",
pytest.param(
"multi_statement_per_line.py",
marks=pytest.mark.skipif(
sys.version_info < (3, 9), reason="Col offset match only on Python 3.9+"
),
),
"no_newline_at_end_of_file.py",
"no_newline_at_end_of_file_with_comment.py",
pytest.param(
"pattern_matching.py",
marks=pytest.mark.skipif(
sys.version_info < (3, 10), reason="Valid only in Python 3.10+"
),
),
"simple_decorators.py",
"statements.py",
pytest.param(
"try_except_group.py",
marks=pytest.mark.skipif(
sys.version_info <= (3, 11), reason="except* allowed only in Python 3.11+"
),
),
pytest.param(
"type_params.py",
marks=pytest.mark.skipif(
sys.version_info <= (3, 12),
reason="type declarations allowed only in Python 3.12+",
),
),
pytest.param(
"with_statement_multi_items.py",
marks=pytest.mark.skipif(
sys.version_info < (3, 9),
reason="Parenthesized with items allowed only in Python 3.9+",
),
),
],
)
def test_parser(python_parse_file, python_parse_str, filename):
path = Path(__file__).parent / "data" / filename
with open(path) as f:
source = f.read()
for part in source.split("\n\n\n"):
original = ast.parse(part)
kwargs = dict(include_attributes=True)
if sys.version_info >= (3, 9):
kwargs["indent"] = " "
try:
pp_ast = python_parse_str(part, "exec")
except Exception:
temp = io.StringIO(part)
print("Parsing failed:")
print("Source is:")
print(textwrap.indent(part, " "))
temp = io.StringIO(part)
print("Token stream is:")
for t in tokenize.generate_tokens(temp.readline):
print(t)
print()
print("CPython ast is:")
print(ast.dump(original, **kwargs))
raise
o = ast.dump(original, **kwargs)
p = ast.dump(pp_ast, **kwargs)
diff = "\n".join(
difflib.unified_diff(o.split("\n"), p.split("\n"), "cpython", "python-pegen")
)
if diff:
print(part)
print(diff)
assert not diff
o = ast.dump(ast.parse(source), **kwargs)
p = ast.dump(python_parse_file(path), **kwargs)
diff = "\n".join(difflib.unified_diff(o.split("\n"), p.split("\n"), "cpython", "python-pegen"))
assert not diff
|