From e1e4bc5f5e80f7d60e7116696036f1efb8bb6ae7 Mon Sep 17 00:00:00 2001 From: Shaurya Bisht <87357655+ShauryaDusht@users.noreply.github.com> Date: Tue, 20 May 2025 00:09:38 +0530 Subject: [PATCH 1/3] gh-131178: Add CLI tests for cProfile --- Lib/test/test_cprofile.py | 108 ++++++++++++++++++++++++++++++++++---- 1 file changed, 98 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_cprofile.py b/Lib/test/test_cprofile.py index 192c8eab26ebff..39220e7ffa293b 100644 --- a/Lib/test/test_cprofile.py +++ b/Lib/test/test_cprofile.py @@ -2,7 +2,7 @@ import sys import unittest - +import os # rip off all interesting stuff from test_profile import cProfile import tempfile @@ -151,23 +151,111 @@ def test_bad_descriptor(self): class TestCommandLine(unittest.TestCase): + def setUp(self): + self.test_script = tempfile.NamedTemporaryFile("w+", suffix=".py", delete=False) + self.test_script.write(textwrap.dedent(""" + def simple_function(): + sum(range(1000)) + + if __name__ == "__main__": + simple_function() + """)) + self.test_script.close() + + def tearDown(self): + os.unlink(self.test_script.name) + def test_sort(self): rc, out, err = assert_python_failure('-m', 'cProfile', '-s', 'demo') self.assertGreater(rc, 0) self.assertIn(b"option -s: invalid choice: 'demo'", err) - + + def test_valid_sort_options(self): + for sort_opt in ['calls', 'cumulative', 'cumtime', 'filename', + 'ncalls', 'pcalls', 'line', 'name', 'nfl', + 'stdname', 'time', 'tottime']: + rc, out, err = assert_python_ok('-m', 'cProfile', '-s', sort_opt, self.test_script.name) + self.assertEqual(rc, 0) + self.assertIn(b"function calls", out) + + def test_outfile(self): + with tempfile.NamedTemporaryFile(suffix='.prof', delete=False) as outfile: + outfile_name = outfile.name + + try: + rc, out, err = assert_python_ok('-m', 'cProfile', '-o', outfile_name, self.test_script.name) + self.assertEqual(rc, 0) + self.assertTrue(os.path.exists(outfile_name)) + self.assertGreater(os.path.getsize(outfile_name), 0) + finally: + if os.path.exists(outfile_name): + os.unlink(outfile_name) + + def test_no_arguments(self): + rc, out, err = assert_python_failure('-m', 'cProfile') + self.assertGreater(rc, 0) + + def test_help_option(self): + rc, out, err = assert_python_ok('-m', 'cProfile', '--help') + self.assertEqual(rc, 0) + self.assertIn(b"Usage:", out) + + def test_version_output(self): + rc, out, err = assert_python_ok('-m', 'cProfile', self.test_script.name) + self.assertEqual(rc, 0) + import os + self.assertIn(os.path.basename(self.test_script.name).encode(), out) + + def test_run_command_line_module(self): + rc, out, err = assert_python_ok('-m', 'cProfile', '-m', 'timeit', '-n', '1', 'pass') + self.assertEqual(rc, 0) + self.assertIn(b"function calls", out) + def test_profile_script_importing_main(self): - """Check that scripts that reference __main__ see their own namespace - when being profiled.""" - with tempfile.NamedTemporaryFile("w+", delete_on_close=False) as f: + with tempfile.NamedTemporaryFile("w+", suffix='.py', delete=False) as f: f.write(textwrap.dedent("""\ - class Foo: - pass - import __main__ - assert Foo == __main__.Foo + def test_func(): + x = 1 + 1 + return x + + if __name__ == "__main__": + test_func() """)) f.close() - assert_python_ok('-m', "cProfile", f.name) + try: + rc, out, err = assert_python_ok('-m', "cProfile", f.name) + self.assertEqual(rc, 0) + self.assertIn(b"function calls", out) + self.assertIn(b"test_func", out) + finally: + os.unlink(f.name) + + def test_output_format(self): + rc, out, err = assert_python_ok('-m', 'cProfile', self.test_script.name) + self.assertEqual(rc, 0) + + output = out.decode('utf-8') + + self.assertRegex(output, r'\d+ function calls in \d+\.\d+ seconds') + + self.assertIn('Ordered by:', output) + + self.assertIn('ncalls', output) + self.assertIn('tottime', output) + self.assertIn('percall', output) + self.assertIn('cumtime', output) + self.assertIn('filename:lineno(function)', output) + + self.assertIn('simple_function', output) + + def test_different_sort_outputs(self): + rc1, out1, _ = assert_python_ok('-m', 'cProfile', '-s', 'time', self.test_script.name) + rc2, out2, _ = assert_python_ok('-m', 'cProfile', '-s', 'cumulative', self.test_script.name) + + self.assertNotEqual(out1, out2) + + self.assertIn(b'simple_function', out1) + self.assertIn(b'simple_function', out2) def main(): From acbf1f8cf9d4cf139b5b36985aa543382326bdd9 Mon Sep 17 00:00:00 2001 From: Shaurya Bisht <87357655+ShauryaDusht@users.noreply.github.com> Date: Tue, 20 May 2025 00:25:19 +0530 Subject: [PATCH 2/3] lint fixes --- Lib/test/test_cprofile.py | 41 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/Lib/test/test_cprofile.py b/Lib/test/test_cprofile.py index 39220e7ffa293b..a242f8f91a32c1 100644 --- a/Lib/test/test_cprofile.py +++ b/Lib/test/test_cprofile.py @@ -156,20 +156,20 @@ def setUp(self): self.test_script.write(textwrap.dedent(""" def simple_function(): sum(range(1000)) - + if __name__ == "__main__": simple_function() """)) self.test_script.close() - + def tearDown(self): os.unlink(self.test_script.name) - + def test_sort(self): rc, out, err = assert_python_failure('-m', 'cProfile', '-s', 'demo') self.assertGreater(rc, 0) self.assertIn(b"option -s: invalid choice: 'demo'", err) - + def test_valid_sort_options(self): for sort_opt in ['calls', 'cumulative', 'cumtime', 'filename', 'ncalls', 'pcalls', 'line', 'name', 'nfl', @@ -177,11 +177,10 @@ def test_valid_sort_options(self): rc, out, err = assert_python_ok('-m', 'cProfile', '-s', sort_opt, self.test_script.name) self.assertEqual(rc, 0) self.assertIn(b"function calls", out) - + def test_outfile(self): with tempfile.NamedTemporaryFile(suffix='.prof', delete=False) as outfile: outfile_name = outfile.name - try: rc, out, err = assert_python_ok('-m', 'cProfile', '-o', outfile_name, self.test_script.name) self.assertEqual(rc, 0) @@ -190,34 +189,34 @@ def test_outfile(self): finally: if os.path.exists(outfile_name): os.unlink(outfile_name) - + def test_no_arguments(self): rc, out, err = assert_python_failure('-m', 'cProfile') self.assertGreater(rc, 0) - + def test_help_option(self): rc, out, err = assert_python_ok('-m', 'cProfile', '--help') self.assertEqual(rc, 0) self.assertIn(b"Usage:", out) - + def test_version_output(self): rc, out, err = assert_python_ok('-m', 'cProfile', self.test_script.name) self.assertEqual(rc, 0) import os self.assertIn(os.path.basename(self.test_script.name).encode(), out) - + def test_run_command_line_module(self): rc, out, err = assert_python_ok('-m', 'cProfile', '-m', 'timeit', '-n', '1', 'pass') self.assertEqual(rc, 0) self.assertIn(b"function calls", out) - + def test_profile_script_importing_main(self): with tempfile.NamedTemporaryFile("w+", suffix='.py', delete=False) as f: f.write(textwrap.dedent("""\ def test_func(): x = 1 + 1 return x - + if __name__ == "__main__": test_func() """)) @@ -229,31 +228,31 @@ def test_func(): self.assertIn(b"test_func", out) finally: os.unlink(f.name) - + def test_output_format(self): rc, out, err = assert_python_ok('-m', 'cProfile', self.test_script.name) self.assertEqual(rc, 0) - + output = out.decode('utf-8') - + self.assertRegex(output, r'\d+ function calls in \d+\.\d+ seconds') - + self.assertIn('Ordered by:', output) - + self.assertIn('ncalls', output) self.assertIn('tottime', output) self.assertIn('percall', output) self.assertIn('cumtime', output) self.assertIn('filename:lineno(function)', output) - + self.assertIn('simple_function', output) - + def test_different_sort_outputs(self): rc1, out1, _ = assert_python_ok('-m', 'cProfile', '-s', 'time', self.test_script.name) rc2, out2, _ = assert_python_ok('-m', 'cProfile', '-s', 'cumulative', self.test_script.name) - + self.assertNotEqual(out1, out2) - + self.assertIn(b'simple_function', out1) self.assertIn(b'simple_function', out2) From 7f55b9f8fcc02fa74664ec2d5cbe9e3c0bf396ef Mon Sep 17 00:00:00 2001 From: Shaurya Bisht <87357655+ShauryaDusht@users.noreply.github.com> Date: Tue, 20 May 2025 01:55:02 +0530 Subject: [PATCH 3/3] Fix suggested changes --- Lib/test/test_cprofile.py | 50 +++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/Lib/test/test_cprofile.py b/Lib/test/test_cprofile.py index a242f8f91a32c1..7606ec41cebaf3 100644 --- a/Lib/test/test_cprofile.py +++ b/Lib/test/test_cprofile.py @@ -166,15 +166,15 @@ def tearDown(self): os.unlink(self.test_script.name) def test_sort(self): - rc, out, err = assert_python_failure('-m', 'cProfile', '-s', 'demo') + rc, _, err = assert_python_failure('-m', 'cProfile', '-s', 'demo') self.assertGreater(rc, 0) self.assertIn(b"option -s: invalid choice: 'demo'", err) def test_valid_sort_options(self): - for sort_opt in ['calls', 'cumulative', 'cumtime', 'filename', + for sort_opt in ('calls', 'cumulative', 'cumtime', 'filename', 'ncalls', 'pcalls', 'line', 'name', 'nfl', - 'stdname', 'time', 'tottime']: - rc, out, err = assert_python_ok('-m', 'cProfile', '-s', sort_opt, self.test_script.name) + 'stdname', 'time', 'tottime'): + rc, out, _ = assert_python_ok('-m', 'cProfile', '-s', sort_opt, self.test_script.name) self.assertEqual(rc, 0) self.assertIn(b"function calls", out) @@ -182,7 +182,7 @@ def test_outfile(self): with tempfile.NamedTemporaryFile(suffix='.prof', delete=False) as outfile: outfile_name = outfile.name try: - rc, out, err = assert_python_ok('-m', 'cProfile', '-o', outfile_name, self.test_script.name) + rc, _, __ = assert_python_ok('-m', 'cProfile', '-o', outfile_name, self.test_script.name) self.assertEqual(rc, 0) self.assertTrue(os.path.exists(outfile_name)) self.assertGreater(os.path.getsize(outfile_name), 0) @@ -191,22 +191,22 @@ def test_outfile(self): os.unlink(outfile_name) def test_no_arguments(self): - rc, out, err = assert_python_failure('-m', 'cProfile') + rc, out, _ = assert_python_failure('-m', 'cProfile') self.assertGreater(rc, 0) + self.assertIn(b'Usage:', out) def test_help_option(self): - rc, out, err = assert_python_ok('-m', 'cProfile', '--help') + rc, out, _ = assert_python_ok('-m', 'cProfile', '--help') self.assertEqual(rc, 0) self.assertIn(b"Usage:", out) def test_version_output(self): - rc, out, err = assert_python_ok('-m', 'cProfile', self.test_script.name) + rc, out, _ = assert_python_ok('-m', 'cProfile', self.test_script.name) self.assertEqual(rc, 0) - import os self.assertIn(os.path.basename(self.test_script.name).encode(), out) def test_run_command_line_module(self): - rc, out, err = assert_python_ok('-m', 'cProfile', '-m', 'timeit', '-n', '1', 'pass') + rc, out, _ = assert_python_ok('-m', 'cProfile', '-m', 'timeit', '-n', '1', 'pass') self.assertEqual(rc, 0) self.assertIn(b"function calls", out) @@ -222,7 +222,7 @@ def test_func(): """)) f.close() try: - rc, out, err = assert_python_ok('-m', "cProfile", f.name) + rc, out, _ = assert_python_ok('-m', "cProfile", f.name) self.assertEqual(rc, 0) self.assertIn(b"function calls", out) self.assertIn(b"test_func", out) @@ -230,28 +230,28 @@ def test_func(): os.unlink(f.name) def test_output_format(self): - rc, out, err = assert_python_ok('-m', 'cProfile', self.test_script.name) + rc, out, _ = assert_python_ok('-m', 'cProfile', self.test_script.name) self.assertEqual(rc, 0) - output = out.decode('utf-8') + self.assertRegex(out, rb'\d+ function calls in \d+\.\d+ seconds') - self.assertRegex(output, r'\d+ function calls in \d+\.\d+ seconds') - - self.assertIn('Ordered by:', output) - - self.assertIn('ncalls', output) - self.assertIn('tottime', output) - self.assertIn('percall', output) - self.assertIn('cumtime', output) - self.assertIn('filename:lineno(function)', output) - - self.assertIn('simple_function', output) + self.assertIn(b'Ordered by:', out) + self.assertIn(b'ncalls', out) + self.assertIn(b'tottime', out) + self.assertIn(b'percall', out) + self.assertIn(b'cumtime', out) + self.assertIn(b'filename:lineno(function)', out) + self.assertIn(b'simple_function', out) def test_different_sort_outputs(self): rc1, out1, _ = assert_python_ok('-m', 'cProfile', '-s', 'time', self.test_script.name) rc2, out2, _ = assert_python_ok('-m', 'cProfile', '-s', 'cumulative', self.test_script.name) - self.assertNotEqual(out1, out2) + self.assertEqual(rc1, 0) + self.assertEqual(rc2, 0) + + self.assertRegex(out1.decode(), r'Ordered by: (?:internal )?time') + self.assertRegex(out2.decode(), r'Ordered by: cumulative') self.assertIn(b'simple_function', out1) self.assertIn(b'simple_function', out2)