Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions Lib/test/test_ast/test_ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -1331,7 +1331,6 @@ class MyNode(ast.AST):
self.assertEqual(repl.x, 0)
self.assertEqual(repl.y, y)

@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 'x' is not 'x'
def test_replace_ignore_known_custom_instance_fields(self):
node = ast.parse('x').body[0].value
node.extra = extra = object() # add instance 'extra' field
Expand Down Expand Up @@ -1401,7 +1400,6 @@ def test_replace_accept_missing_field_with_default(self):
self.assertIs(node2.returns, None)
self.assertEqual(node2.decorator_list, [])

@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: "Name\.__replace__\ got\ an\ unexpected\ keyword\ argument\ 'extra'\." does not match "replace() does not support Name objects"
def test_replace_reject_known_custom_instance_fields_commits(self):
node = ast.parse('x').body[0].value
node.extra = extra = object() # add instance 'extra' field
Expand All @@ -1417,7 +1415,6 @@ def test_replace_reject_known_custom_instance_fields_commits(self):
self.assertIs(node.ctx, context)
self.assertIs(node.extra, extra)

@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: "Name\.__replace__\ got\ an\ unexpected\ keyword\ argument\ 'unknown'\." does not match "replace() does not support Name objects"
def test_replace_reject_unknown_instance_fields(self):
node = ast.parse('x').body[0].value
context = node.ctx
Expand Down
3 changes: 2 additions & 1 deletion crates/vm/src/stdlib/_ast/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1376,7 +1376,8 @@ impl Node for ast::ExprName {
.into_ref_with_type(vm, pyast::NodeExprName::static_type().to_owned())
.unwrap();
let dict = node.as_object().dict().unwrap();
dict.set_item("id", id.to_pyobject(vm), vm).unwrap();
dict.set_item("id", id.ast_to_object(vm, source_file), vm)
.unwrap();
dict.set_item("ctx", ctx.ast_to_object(vm, source_file), vm)
.unwrap();
node_add_location(&dict, range, vm, source_file);
Expand Down
2 changes: 1 addition & 1 deletion crates/vm/src/stdlib/_ast/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ impl Node for ast::StmtFunctionDef {

let node = NodeAst.into_ref_with_type(vm, cls).unwrap();
let dict = node.as_object().dict().unwrap();
dict.set_item("name", vm.ctx.new_str(name.as_str()).to_pyobject(vm), vm)
dict.set_item("name", name.ast_to_object(vm, source_file), vm)
.unwrap();
dict.set_item("args", parameters.ast_to_object(vm, source_file), vm)
.unwrap();
Expand Down
20 changes: 20 additions & 0 deletions extra_tests/snippets/stdlib_ast.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import ast
import copy

print(ast)

Expand Down Expand Up @@ -39,6 +40,25 @@ def foo():
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,
Expand Down
Loading