Skip to content

gh-131178: Add tests for ast command-line interface #133329

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 4, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Accept suggestions
  • Loading branch information
donBarbos committed May 4, 2025
commit 6aa5cd7ec4d9148dcd45a3ede7054bb88e4547c5
4 changes: 2 additions & 2 deletions Lib/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ def unparse(ast_obj):
return unparser.visit(ast_obj)


def _main(args=None):
def main(args=None):
import argparse
import sys

Expand Down Expand Up @@ -656,4 +656,4 @@ def _main(args=None):
print(dump(tree, include_attributes=args.include_attributes, indent=args.indent))

if __name__ == '__main__':
_main()
main()
67 changes: 42 additions & 25 deletions Lib/test/test_ast/test_ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -3186,20 +3186,21 @@ def setUp(self):

@staticmethod
def text_normalize(string):
"""Dedent *string* and strip it from its surrounding whitespaces.
This method is used by the other utility functions so that any
string to write or to match against can be freely indented.
"""
return textwrap.dedent(string).strip()

def set_source(self, content):
Path(self.filename).write_text(self.text_normalize(content))

def invoke_ast(self, *flags):
output = StringIO()
with contextlib.redirect_stdout(output):
ast._main(args=[*flags, self.filename])
return self.text_normalize(output.getvalue())
stderr = StringIO()
stdout = StringIO()
with (
contextlib.redirect_stdout(stdout),
contextlib.redirect_stderr(stderr),
):
ast.main(args=[*flags, self.filename])
self.assertEqual(stderr.getvalue(), '')
return self.text_normalize(stdout.getvalue())

def check_output(self, source, expect, *flags):
with self.subTest(source=source, flags=flags):
Expand All @@ -3218,39 +3219,49 @@ def test_invocation(self):
)
self.set_source('''
print(1, 2, 3)
def f(x):
def f(x: int) -> int:
x -= 1
return x
''')

for r in range(1, len(base_flags) + 1):
for choices in itertools.combinations(base_flags, r=r):
for args in itertools.product(*choices):
with self.subTest(args=args[1:]):
with self.subTest(flags=args[1:]):
_ = self.invoke_ast(*args)

def test_unknown_flag(self):
with self.assertRaises(SystemExit):
# suppress argparse error message
with contextlib.redirect_stderr(StringIO()):
output = self.invoke_ast('--unknown')
self.assertStartsWith(output, 'usage: ')

def test_mode_flag(self):
# test 'python -m ast -m/--mode'
source = 'print(1, 2, 3)'
output = self.invoke_ast('--unknown')
self.assertStartsWith(output, 'usage: ')

def test_help_flag(self):
# test 'python -m ast -h/--help'
for flag in ('-h', '--help'):
with self.subTest(flags=flag):
with self.assertRaises(SystemExit):
output = self.invoke_ast(flag)
self.assertStartsWith(output, 'usage: ')

def test_exec_mode_flag(self):
# test 'python -m ast -m/--mode exec'
source = 'x: bool = 1 # type: ignore[assignment]'
expect = '''
Module(
body=[
Expr(
value=Call(
func=Name(id='print', ctx=Load()),
args=[
Constant(value=1),
Constant(value=2),
Constant(value=3)]))])
AnnAssign(
target=Name(id='x', ctx=Store()),
annotation=Name(id='bool', ctx=Load()),
value=Constant(value=1),
simple=1)],
type_ignores=[
TypeIgnore(lineno=1, tag='[assignment]')])
'''
for flag in ('-m=exec', '--mode=exec'):
self.check_output(source, expect, flag)

def test_single_mode_flag(self):
# test 'python -m ast -m/--mode single'
source = 'pass'
expect = '''
Interactive(
Expand All @@ -3259,6 +3270,9 @@ def test_mode_flag(self):
'''
for flag in ('-m=single', '--mode=single'):
self.check_output(source, expect, flag)

def test_eval_mode_flag(self):
# test 'python -m ast -m/--mode eval'
source = 'print(1, 2, 3)'
expect = '''
Expression(
Expand All @@ -3271,6 +3285,9 @@ def test_mode_flag(self):
'''
for flag in ('-m=eval', '--mode=eval'):
self.check_output(source, expect, flag)

def test_func_type_mode_flag(self):
# test 'python -m ast -m/--mode func_type'
source = '(int, str) -> list[int]'
expect = '''
FunctionType(
Expand Down
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy