Files
RustPython/extra_tests/snippets/stdlib_ast.py
T
youknowdot 519370bece Adapt essential snippet contracts to Python 3.15 final
Preserve existing coverage while following verified final behavior for script metadata, builtin signatures and loading, AST fixture construction, memoryview diagnostics, mmap search bounds, and struct format errors. The unchanged final comparator exposes the earlier expectations; focused native baseline failures establish the required implementation changes.

Assisted-by: OpenAI Codex:model identifier unavailable
2026-10-10 00:53:45 +09:00

112 lines
2.8 KiB
Python

import ast
import copy
print(ast)
source = """
def foo():
print('bar')
pass
"""
n = ast.parse(source)
print(n)
print(n.body)
print(n.body[0].name)
assert n.body[0].name == "foo"
foo = n.body[0]
assert foo.lineno == 2
print(foo.body)
assert len(foo.body) == 2
print(foo.body[0])
print(foo.body[0].value.func.id)
assert foo.body[0].value.func.id == "print"
assert foo.body[0].lineno == 3
assert foo.body[1].lineno == 4
n = ast.parse("3 < 4 > 5\n")
assert n.body[0].value.left.value == 3
assert "Lt" in str(n.body[0].value.ops[0])
assert "Gt" in str(n.body[0].value.ops[1])
assert n.body[0].value.comparators[0].value == 4
assert n.body[0].value.comparators[1].value == 5
n = ast.parse("from ... import a\n")
print(n)
i = n.body[0]
assert i.level == 3
assert i.module is None
assert i.names[0].name == "a"
assert i.names[0].asname is None
# Regression: parsed AST identifier fields are interned, matching CPython.
name_literal = "x"
name = ast.parse("x").body[0].value
assert name.id is name_literal
name.extra = object()
replacement = copy.replace(name)
assert replacement.id is name.id
assert replacement.ctx is name.ctx
assert not hasattr(replacement, "extra")
function_name = "f"
function = ast.parse("def f(): pass").body[0]
assert function.name is function_name
async_function = ast.parse("async def f(): pass").body[0]
assert async_function.name is function_name
# Regression test for issue #4862:
# A cyclic AST fed to compile() used to overflow the Rust stack and SIGSEGV.
# After the fix, the recursion guard in ast_from_object raises RecursionError,
# matching CPython's behavior. Covers both Box<T> descents (UnaryOp, BinOp,
# Call, Attribute) and Vec<T> descents (List, Tuple).
import warnings
def _cyclic_cases():
# Box<Expr> descents
u = ast.UnaryOp(op=ast.Not(), operand=None, lineno=0, col_offset=0)
u.operand = u
yield "UnaryOp", u
b = ast.BinOp(
op=ast.Add(),
left=None,
right=ast.Constant(value=0, lineno=0, col_offset=0),
lineno=0,
col_offset=0,
)
b.left = b
yield "BinOp", b
c = ast.Call(func=None, args=[], keywords=[], lineno=0, col_offset=0)
c.func = c
yield "Call", c
a = ast.Attribute(value=None, attr="x", ctx=ast.Load(), lineno=0, col_offset=0)
a.value = a
yield "Attribute", a
# Vec<Expr> descents
lst = ast.List(ctx=ast.Load(), lineno=0, col_offset=0)
lst.elts = [lst]
yield "List", lst
tup = ast.Tuple(ctx=ast.Load(), lineno=0, col_offset=0)
tup.elts = [tup]
yield "Tuple", tup
with warnings.catch_warnings():
warnings.simplefilter("ignore")
for name, node in _cyclic_cases():
try:
compile(ast.Expression(node), "<cyclic>", "eval")
raise AssertionError(f"cyclic {name} should raise RecursionError")
except RecursionError:
pass # expected; matches CPython