From d5c51fcfd1613607863f19131396e7584b3d3476 Mon Sep 17 00:00:00 2001 From: gastonquirogaserrezuela Date: Mon, 6 Oct 2025 00:32:39 -0300 Subject: [PATCH 1/3] Support Module and other objects in ast.parse --- stdlib/@tests/test_cases/check_ast.py | 21 ++++++++++++++++++ stdlib/ast.pyi | 32 +++++++++++++-------------- 2 files changed, 37 insertions(+), 16 deletions(-) create mode 100644 stdlib/@tests/test_cases/check_ast.py diff --git a/stdlib/@tests/test_cases/check_ast.py b/stdlib/@tests/test_cases/check_ast.py new file mode 100644 index 000000000000..23bc79aec4de --- /dev/null +++ b/stdlib/@tests/test_cases/check_ast.py @@ -0,0 +1,21 @@ +import ast +from typing_extensions import assert_type + +# Test with Module input +mod1: ast.Module = ast.Module([], []) +assert_type(ast.parse(mod1), ast.Module) +assert_type(ast.parse(mod1, mode="exec"), ast.Module) +mod2: ast.Module = ast.Module(body=[ast.Expr(value=ast.Constant(value=42))], type_ignores=[]) +assert_type(ast.parse(mod2), ast.Module) + +# Test with Expression input +expr1: ast.Expression = ast.Expression(body=ast.Constant(value=42)) +assert_type(ast.parse(expr1, mode="eval"), ast.Expression) + +# Test with Interactive input +inter1: ast.Interactive = ast.Interactive(body=[]) +assert_type(ast.parse(inter1, mode="single"), ast.Interactive) + +# Test with FunctionType input +func1: ast.FunctionType = ast.FunctionType(argtypes=[], returns=ast.Constant(value=None)) +assert_type(ast.parse(func1, mode="func_type"), ast.FunctionType) diff --git a/stdlib/ast.pyi b/stdlib/ast.pyi index d360c2ed60e5..60677afa9855 100644 --- a/stdlib/ast.pyi +++ b/stdlib/ast.pyi @@ -1746,7 +1746,7 @@ _T = _TypeVar("_T", bound=AST) if sys.version_info >= (3, 13): @overload def parse( - source: str | ReadableBuffer, + source: str | ReadableBuffer | mod, filename: str | ReadableBuffer | os.PathLike[Any] = "", mode: Literal["exec"] = "exec", *, @@ -1756,7 +1756,7 @@ if sys.version_info >= (3, 13): ) -> Module: ... @overload def parse( - source: str | ReadableBuffer, + source: str | ReadableBuffer | mod, filename: str | ReadableBuffer | os.PathLike[Any], mode: Literal["eval"], *, @@ -1766,7 +1766,7 @@ if sys.version_info >= (3, 13): ) -> Expression: ... @overload def parse( - source: str | ReadableBuffer, + source: str | ReadableBuffer | mod, filename: str | ReadableBuffer | os.PathLike[Any], mode: Literal["func_type"], *, @@ -1776,7 +1776,7 @@ if sys.version_info >= (3, 13): ) -> FunctionType: ... @overload def parse( - source: str | ReadableBuffer, + source: str | ReadableBuffer | mod, filename: str | ReadableBuffer | os.PathLike[Any], mode: Literal["single"], *, @@ -1786,7 +1786,7 @@ if sys.version_info >= (3, 13): ) -> Interactive: ... @overload def parse( - source: str | ReadableBuffer, + source: str | ReadableBuffer | mod, *, mode: Literal["eval"], type_comments: bool = False, @@ -1795,7 +1795,7 @@ if sys.version_info >= (3, 13): ) -> Expression: ... @overload def parse( - source: str | ReadableBuffer, + source: str | ReadableBuffer | mod, *, mode: Literal["func_type"], type_comments: bool = False, @@ -1804,7 +1804,7 @@ if sys.version_info >= (3, 13): ) -> FunctionType: ... @overload def parse( - source: str | ReadableBuffer, + source: str | ReadableBuffer | mod, *, mode: Literal["single"], type_comments: bool = False, @@ -1813,7 +1813,7 @@ if sys.version_info >= (3, 13): ) -> Interactive: ... @overload def parse( - source: str | ReadableBuffer, + source: str | ReadableBuffer | mod, filename: str | ReadableBuffer | os.PathLike[Any] = "", mode: str = "exec", *, @@ -1825,7 +1825,7 @@ if sys.version_info >= (3, 13): else: @overload def parse( - source: str | ReadableBuffer, + source: str | ReadableBuffer | mod, filename: str | ReadableBuffer | os.PathLike[Any] = "", mode: Literal["exec"] = "exec", *, @@ -1834,7 +1834,7 @@ else: ) -> Module: ... @overload def parse( - source: str | ReadableBuffer, + source: str | ReadableBuffer | mod, filename: str | ReadableBuffer | os.PathLike[Any], mode: Literal["eval"], *, @@ -1843,7 +1843,7 @@ else: ) -> Expression: ... @overload def parse( - source: str | ReadableBuffer, + source: str | ReadableBuffer | mod, filename: str | ReadableBuffer | os.PathLike[Any], mode: Literal["func_type"], *, @@ -1852,7 +1852,7 @@ else: ) -> FunctionType: ... @overload def parse( - source: str | ReadableBuffer, + source: str | ReadableBuffer | mod, filename: str | ReadableBuffer | os.PathLike[Any], mode: Literal["single"], *, @@ -1861,7 +1861,7 @@ else: ) -> Interactive: ... @overload def parse( - source: str | ReadableBuffer, + source: str | ReadableBuffer | mod, *, mode: Literal["eval"], type_comments: bool = False, @@ -1869,7 +1869,7 @@ else: ) -> Expression: ... @overload def parse( - source: str | ReadableBuffer, + source: str | ReadableBuffer | mod, *, mode: Literal["func_type"], type_comments: bool = False, @@ -1877,7 +1877,7 @@ else: ) -> FunctionType: ... @overload def parse( - source: str | ReadableBuffer, + source: str | ReadableBuffer | mod, *, mode: Literal["single"], type_comments: bool = False, @@ -1885,7 +1885,7 @@ else: ) -> Interactive: ... @overload def parse( - source: str | ReadableBuffer, + source: str | ReadableBuffer | mod, filename: str | ReadableBuffer | os.PathLike[Any] = "", mode: str = "exec", *, From 2bf904769ecc44979ca2f3ba42effe588aef6938 Mon Sep 17 00:00:00 2001 From: gastonquirogaserrezuela Date: Mon, 6 Oct 2025 11:33:07 -0300 Subject: [PATCH 2/3] Receive any AST node in parse --- stdlib/@tests/test_cases/check_ast.py | 31 +++++++++++++--- stdlib/ast.pyi | 51 ++++++++++++++++++--------- 2 files changed, 62 insertions(+), 20 deletions(-) diff --git a/stdlib/@tests/test_cases/check_ast.py b/stdlib/@tests/test_cases/check_ast.py index 23bc79aec4de..0e348502fcba 100644 --- a/stdlib/@tests/test_cases/check_ast.py +++ b/stdlib/@tests/test_cases/check_ast.py @@ -1,21 +1,44 @@ import ast from typing_extensions import assert_type -# Test with Module input +# Test with source code strings +assert_type(ast.parse("x = 1"), ast.Module) +assert_type(ast.parse("x = 1", mode="exec"), ast.Module) +assert_type(ast.parse("1 + 1", mode="eval"), ast.Expression) +assert_type(ast.parse("x = 1", mode="single"), ast.Interactive) +assert_type(ast.parse("(int, str) -> None", mode="func_type"), ast.FunctionType) + +# Test with mod objects - Module mod1: ast.Module = ast.Module([], []) assert_type(ast.parse(mod1), ast.Module) assert_type(ast.parse(mod1, mode="exec"), ast.Module) mod2: ast.Module = ast.Module(body=[ast.Expr(value=ast.Constant(value=42))], type_ignores=[]) assert_type(ast.parse(mod2), ast.Module) -# Test with Expression input +# Test with mod objects - Expression expr1: ast.Expression = ast.Expression(body=ast.Constant(value=42)) assert_type(ast.parse(expr1, mode="eval"), ast.Expression) -# Test with Interactive input +# Test with mod objects - Interactive inter1: ast.Interactive = ast.Interactive(body=[]) assert_type(ast.parse(inter1, mode="single"), ast.Interactive) -# Test with FunctionType input +# Test with mod objects - FunctionType func1: ast.FunctionType = ast.FunctionType(argtypes=[], returns=ast.Constant(value=None)) assert_type(ast.parse(func1, mode="func_type"), ast.FunctionType) + +# Test any AST node can be passed and returns the same type +binop: ast.BinOp = ast.BinOp(left=ast.Constant(1), op=ast.Add(), right=ast.Constant(2)) +assert_type(ast.parse(binop), ast.BinOp) + +funcdef: ast.FunctionDef = ast.FunctionDef(name="foo", args=ast.arguments(), body=[], decorator_list=[]) +assert_type(ast.parse(funcdef), ast.FunctionDef) + +constant: ast.Constant = ast.Constant(value=42) +assert_type(ast.parse(constant), ast.Constant) + +# Test with additional parameters +assert_type(ast.parse(mod1, filename="test.py"), ast.Module) +assert_type(ast.parse(mod1, type_comments=True), ast.Module) +assert_type(ast.parse(mod1, feature_version=(3, 10)), ast.Module) +assert_type(ast.parse(binop, filename="test.py"), ast.BinOp) diff --git a/stdlib/ast.pyi b/stdlib/ast.pyi index 60677afa9855..5f11e7dcd434 100644 --- a/stdlib/ast.pyi +++ b/stdlib/ast.pyi @@ -1746,7 +1746,17 @@ _T = _TypeVar("_T", bound=AST) if sys.version_info >= (3, 13): @overload def parse( - source: str | ReadableBuffer | mod, + source: _T, + filename: str | ReadableBuffer | os.PathLike[Any] = "", + mode: Literal["exec", "eval", "func_type", "single"] = "exec", + *, + type_comments: bool = False, + feature_version: None | int | tuple[int, int] = None, + optimize: Literal[-1, 0, 1, 2] = -1, + ) -> _T: ... + @overload + def parse( + source: str | ReadableBuffer, filename: str | ReadableBuffer | os.PathLike[Any] = "", mode: Literal["exec"] = "exec", *, @@ -1756,7 +1766,7 @@ if sys.version_info >= (3, 13): ) -> Module: ... @overload def parse( - source: str | ReadableBuffer | mod, + source: str | ReadableBuffer, filename: str | ReadableBuffer | os.PathLike[Any], mode: Literal["eval"], *, @@ -1766,7 +1776,7 @@ if sys.version_info >= (3, 13): ) -> Expression: ... @overload def parse( - source: str | ReadableBuffer | mod, + source: str | ReadableBuffer, filename: str | ReadableBuffer | os.PathLike[Any], mode: Literal["func_type"], *, @@ -1776,7 +1786,7 @@ if sys.version_info >= (3, 13): ) -> FunctionType: ... @overload def parse( - source: str | ReadableBuffer | mod, + source: str | ReadableBuffer, filename: str | ReadableBuffer | os.PathLike[Any], mode: Literal["single"], *, @@ -1786,7 +1796,7 @@ if sys.version_info >= (3, 13): ) -> Interactive: ... @overload def parse( - source: str | ReadableBuffer | mod, + source: str | ReadableBuffer, *, mode: Literal["eval"], type_comments: bool = False, @@ -1795,7 +1805,7 @@ if sys.version_info >= (3, 13): ) -> Expression: ... @overload def parse( - source: str | ReadableBuffer | mod, + source: str | ReadableBuffer, *, mode: Literal["func_type"], type_comments: bool = False, @@ -1804,7 +1814,7 @@ if sys.version_info >= (3, 13): ) -> FunctionType: ... @overload def parse( - source: str | ReadableBuffer | mod, + source: str | ReadableBuffer, *, mode: Literal["single"], type_comments: bool = False, @@ -1813,7 +1823,7 @@ if sys.version_info >= (3, 13): ) -> Interactive: ... @overload def parse( - source: str | ReadableBuffer | mod, + source: str | ReadableBuffer, filename: str | ReadableBuffer | os.PathLike[Any] = "", mode: str = "exec", *, @@ -1825,7 +1835,16 @@ if sys.version_info >= (3, 13): else: @overload def parse( - source: str | ReadableBuffer | mod, + source: _T, + filename: str | ReadableBuffer | os.PathLike[Any] = "", + mode: Literal["exec", "eval", "func_type", "single"] = "exec", + *, + type_comments: bool = False, + feature_version: None | int | tuple[int, int] = None, + ) -> _T: ... + @overload + def parse( + source: str | ReadableBuffer, filename: str | ReadableBuffer | os.PathLike[Any] = "", mode: Literal["exec"] = "exec", *, @@ -1834,7 +1853,7 @@ else: ) -> Module: ... @overload def parse( - source: str | ReadableBuffer | mod, + source: str | ReadableBuffer, filename: str | ReadableBuffer | os.PathLike[Any], mode: Literal["eval"], *, @@ -1843,7 +1862,7 @@ else: ) -> Expression: ... @overload def parse( - source: str | ReadableBuffer | mod, + source: str | ReadableBuffer, filename: str | ReadableBuffer | os.PathLike[Any], mode: Literal["func_type"], *, @@ -1852,7 +1871,7 @@ else: ) -> FunctionType: ... @overload def parse( - source: str | ReadableBuffer | mod, + source: str | ReadableBuffer, filename: str | ReadableBuffer | os.PathLike[Any], mode: Literal["single"], *, @@ -1861,7 +1880,7 @@ else: ) -> Interactive: ... @overload def parse( - source: str | ReadableBuffer | mod, + source: str | ReadableBuffer, *, mode: Literal["eval"], type_comments: bool = False, @@ -1869,7 +1888,7 @@ else: ) -> Expression: ... @overload def parse( - source: str | ReadableBuffer | mod, + source: str | ReadableBuffer, *, mode: Literal["func_type"], type_comments: bool = False, @@ -1877,7 +1896,7 @@ else: ) -> FunctionType: ... @overload def parse( - source: str | ReadableBuffer | mod, + source: str | ReadableBuffer, *, mode: Literal["single"], type_comments: bool = False, @@ -1885,7 +1904,7 @@ else: ) -> Interactive: ... @overload def parse( - source: str | ReadableBuffer | mod, + source: str | ReadableBuffer, filename: str | ReadableBuffer | os.PathLike[Any] = "", mode: str = "exec", *, From 1102479801bd9816711ea41511c2ee381ab9832e Mon Sep 17 00:00:00 2001 From: gastonquirogaserrezuela Date: Mon, 6 Oct 2025 11:55:20 -0300 Subject: [PATCH 3/3] fix tests --- stdlib/@tests/test_cases/check_ast.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stdlib/@tests/test_cases/check_ast.py b/stdlib/@tests/test_cases/check_ast.py index 0e348502fcba..4e99d00d6ccb 100644 --- a/stdlib/@tests/test_cases/check_ast.py +++ b/stdlib/@tests/test_cases/check_ast.py @@ -27,16 +27,16 @@ func1: ast.FunctionType = ast.FunctionType(argtypes=[], returns=ast.Constant(value=None)) assert_type(ast.parse(func1, mode="func_type"), ast.FunctionType) -# Test any AST node can be passed and returns the same type +# Test that any AST node can be passed and returns the same type binop: ast.BinOp = ast.BinOp(left=ast.Constant(1), op=ast.Add(), right=ast.Constant(2)) assert_type(ast.parse(binop), ast.BinOp) -funcdef: ast.FunctionDef = ast.FunctionDef(name="foo", args=ast.arguments(), body=[], decorator_list=[]) -assert_type(ast.parse(funcdef), ast.FunctionDef) - constant: ast.Constant = ast.Constant(value=42) assert_type(ast.parse(constant), ast.Constant) +expr_stmt: ast.Expr = ast.Expr(value=ast.Constant(value=42)) +assert_type(ast.parse(expr_stmt), ast.Expr) + # Test with additional parameters assert_type(ast.parse(mod1, filename="test.py"), ast.Module) assert_type(ast.parse(mod1, type_comments=True), ast.Module)