From 07971e10b52bb83ac068b2156ccf322b42cdc06c Mon Sep 17 00:00:00 2001 From: Shaurya Bisht <87357655+ShauryaDusht@users.noreply.github.com> Date: Fri, 16 May 2025 23:27:07 +0530 Subject: [PATCH 1/5] gh-131178: Add CLI tests for profile module --- Lib/profile.py | 4 +- Lib/test/test_profile.py | 107 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 2 deletions(-) diff --git a/Lib/profile.py b/Lib/profile.py index a5afb12c9d121a..5dbb448aea6108 100644 --- a/Lib/profile.py +++ b/Lib/profile.py @@ -551,7 +551,7 @@ def f(m, f1=f1): #**************************************************************************** -def main(): +def main(args=None): import os from optparse import OptionParser @@ -570,7 +570,7 @@ def main(): parser.print_usage() sys.exit(2) - (options, args) = parser.parse_args() + (options, args) = parser.parse_args(args) sys.argv[:] = args # The script that we're profiling may chdir, so capture the absolute path diff --git a/Lib/test/test_profile.py b/Lib/test/test_profile.py index 0f16b92334999c..2c662abbc591c3 100644 --- a/Lib/test/test_profile.py +++ b/Lib/test/test_profile.py @@ -4,6 +4,7 @@ import pstats import unittest import os +import subprocess from difflib import unified_diff from io import StringIO from test.support.os_helper import TESTFN, unlink, temp_dir, change_cwd @@ -130,6 +131,112 @@ def test_output_file_when_changing_directory(self): self.assertTrue(os.path.exists('out.pstats')) +class ProfileCLITests(unittest.TestCase): + """Tests for the profile module's command line interface.""" + + def setUp(self): + # Create a simple Python script to profile + self.script_content = """\ +def factorial(n): + if n <= 1: + return 1 + return n * factorial(n-1) + +if __name__ == "__main__": + factorial(10) +""" + self.script_file = TESTFN + with open(self.script_file, "w") as f: + f.write(self.script_content) + self.addCleanup(unlink, self.script_file) + + def _run_profile_cli(self, *args): + """Helper to run the profile CLI with given arguments.""" + cmd = [sys.executable, '-m', 'profile'] + list(args) + proc = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True + ) + stdout, stderr = proc.communicate() + return proc.returncode, stdout, stderr + + def test_basic_profile(self): + """Test basic profiling of a script.""" + returncode, stdout, stderr = self._run_profile_cli(self.script_file) + self.assertEqual(returncode, 0) + self.assertIn("function calls", stdout) + self.assertIn("factorial", stdout) + + def test_sort_options(self): + """Test different sort options.""" + # List of sort options known to work + sort_options = ['calls', 'cumulative', 'cumtime', 'file', + 'filename', 'module', 'ncalls', 'pcalls', + 'line', 'stdname', 'time', 'tottime'] + + # Test each sort option individually + for option in sort_options: + with self.subTest(sort_option=option): + returncode, stdout, stderr = self._run_profile_cli( + '-s', option, self.script_file + ) + self.assertEqual(returncode, 0) + self.assertIn("function calls", stdout) + + def test_output_file(self): + """Test writing profile results to a file.""" + output_file = TESTFN + '.prof' + self.addCleanup(unlink, output_file) + + returncode, stdout, stderr = self._run_profile_cli( + '-o', output_file, self.script_file + ) + self.assertEqual(returncode, 0) + + # Check that the output file exists and contains profile data + self.assertTrue(os.path.exists(output_file)) + stats = pstats.Stats(output_file) + self.assertGreater(stats.total_calls, 0) + + def test_invalid_option(self): + """Test behavior with an invalid option.""" + returncode, stdout, stderr = self._run_profile_cli( + '--invalid-option', self.script_file + ) + self.assertNotEqual(returncode, 0) + self.assertIn("error", stderr.lower()) + + def test_no_arguments(self): + """Test behavior with no arguments.""" + returncode, stdout, stderr = self._run_profile_cli() + self.assertNotEqual(returncode, 0) + + # Check either stdout or stderr for usage information + combined_output = stdout.lower() + stderr.lower() + self.assertTrue("usage:" in combined_output or + "error:" in combined_output or + "no script filename specified" in combined_output, + "Expected usage information or error message not found") + + def test_run_module(self): + """Test profiling a module with -m option.""" + # Create a small module + module_name = "test_profile_module" + module_file = f"{module_name}.py" + + with open(module_file, "w") as f: + f.write("print('Module executed')\n") + + self.addCleanup(unlink, module_file) + + returncode, stdout, stderr = self._run_profile_cli( + '-m', module_name + ) + self.assertEqual(returncode, 0) + self.assertIn("Module executed", stdout) + self.assertIn("function calls", stdout) def regenerate_expected_output(filename, cls): filename = filename.rstrip('co') From fd894ec9928dccfde970a80d744ce734a4537290 Mon Sep 17 00:00:00 2001 From: Shaurya Bisht <87357655+ShauryaDusht@users.noreply.github.com> Date: Fri, 16 May 2025 23:46:37 +0530 Subject: [PATCH 2/5] Lint fixes --- Lib/test/test_profile.py | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_profile.py b/Lib/test/test_profile.py index 2c662abbc591c3..a92aaa6f98ada6 100644 --- a/Lib/test/test_profile.py +++ b/Lib/test/test_profile.py @@ -131,6 +131,7 @@ def test_output_file_when_changing_directory(self): self.assertTrue(os.path.exists('out.pstats')) + class ProfileCLITests(unittest.TestCase): """Tests for the profile module's command line interface.""" @@ -173,9 +174,9 @@ def test_sort_options(self): """Test different sort options.""" # List of sort options known to work sort_options = ['calls', 'cumulative', 'cumtime', 'file', - 'filename', 'module', 'ncalls', 'pcalls', - 'line', 'stdname', 'time', 'tottime'] - + 'filename', 'module', 'ncalls', 'pcalls', + 'line', 'stdname', 'time', 'tottime'] + # Test each sort option individually for option in sort_options: with self.subTest(sort_option=option): @@ -189,12 +190,12 @@ def test_output_file(self): """Test writing profile results to a file.""" output_file = TESTFN + '.prof' self.addCleanup(unlink, output_file) - + returncode, stdout, stderr = self._run_profile_cli( '-o', output_file, self.script_file ) self.assertEqual(returncode, 0) - + # Check that the output file exists and contains profile data self.assertTrue(os.path.exists(output_file)) stats = pstats.Stats(output_file) @@ -212,25 +213,27 @@ def test_no_arguments(self): """Test behavior with no arguments.""" returncode, stdout, stderr = self._run_profile_cli() self.assertNotEqual(returncode, 0) - + # Check either stdout or stderr for usage information combined_output = stdout.lower() + stderr.lower() - self.assertTrue("usage:" in combined_output or - "error:" in combined_output or - "no script filename specified" in combined_output, - "Expected usage information or error message not found") + self.assertTrue( + "usage:" in combined_output or + "error:" in combined_output or + "no script filename specified" in combined_output, + "Expected usage information or error message not found" + ) def test_run_module(self): """Test profiling a module with -m option.""" # Create a small module module_name = "test_profile_module" module_file = f"{module_name}.py" - + with open(module_file, "w") as f: f.write("print('Module executed')\n") - + self.addCleanup(unlink, module_file) - + returncode, stdout, stderr = self._run_profile_cli( '-m', module_name ) @@ -238,6 +241,7 @@ def test_run_module(self): self.assertIn("Module executed", stdout) self.assertIn("function calls", stdout) + def regenerate_expected_output(filename, cls): filename = filename.rstrip('co') print('Regenerating %s...' % filename) From 5501828500edac98b6a82606a9286d77dd24fa60 Mon Sep 17 00:00:00 2001 From: Shaurya Bisht <87357655+ShauryaDusht@users.noreply.github.com> Date: Sat, 17 May 2025 00:19:42 +0530 Subject: [PATCH 3/5] remove args --- Lib/profile.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/profile.py b/Lib/profile.py index 5dbb448aea6108..a5afb12c9d121a 100644 --- a/Lib/profile.py +++ b/Lib/profile.py @@ -551,7 +551,7 @@ def f(m, f1=f1): #**************************************************************************** -def main(args=None): +def main(): import os from optparse import OptionParser @@ -570,7 +570,7 @@ def main(args=None): parser.print_usage() sys.exit(2) - (options, args) = parser.parse_args(args) + (options, args) = parser.parse_args() sys.argv[:] = args # The script that we're profiling may chdir, so capture the absolute path From e7887f0b354d94e3888e03324b4b98180026f335 Mon Sep 17 00:00:00 2001 From: Shaurya Bisht <87357655+ShauryaDusht@users.noreply.github.com> Date: Sat, 17 May 2025 12:08:06 +0530 Subject: [PATCH 4/5] removed comments and minor fixes --- Lib/test/test_profile.py | 56 +++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/Lib/test/test_profile.py b/Lib/test/test_profile.py index a92aaa6f98ada6..a9c5adbb6406ef 100644 --- a/Lib/test/test_profile.py +++ b/Lib/test/test_profile.py @@ -5,6 +5,8 @@ import unittest import os import subprocess +import tempfile +import shutil from difflib import unified_diff from io import StringIO from test.support.os_helper import TESTFN, unlink, temp_dir, change_cwd @@ -136,7 +138,9 @@ class ProfileCLITests(unittest.TestCase): """Tests for the profile module's command line interface.""" def setUp(self): - # Create a simple Python script to profile + self.temp_dir = tempfile.mkdtemp() + self.addCleanup(shutil.rmtree, self.temp_dir) + self.script_content = """\ def factorial(n): if n <= 1: @@ -146,14 +150,12 @@ def factorial(n): if __name__ == "__main__": factorial(10) """ - self.script_file = TESTFN + self.script_file = os.path.join(self.temp_dir, "factorial_script.py") with open(self.script_file, "w") as f: f.write(self.script_content) - self.addCleanup(unlink, self.script_file) def _run_profile_cli(self, *args): - """Helper to run the profile CLI with given arguments.""" - cmd = [sys.executable, '-m', 'profile'] + list(args) + cmd = [sys.executable, '-m', 'profile', *args] proc = subprocess.Popen( cmd, stdout=subprocess.PIPE, @@ -164,20 +166,17 @@ def _run_profile_cli(self, *args): return proc.returncode, stdout, stderr def test_basic_profile(self): - """Test basic profiling of a script.""" returncode, stdout, stderr = self._run_profile_cli(self.script_file) self.assertEqual(returncode, 0) self.assertIn("function calls", stdout) self.assertIn("factorial", stdout) + self.assertIn("ncalls", stdout) def test_sort_options(self): - """Test different sort options.""" - # List of sort options known to work sort_options = ['calls', 'cumulative', 'cumtime', 'file', 'filename', 'module', 'ncalls', 'pcalls', 'line', 'stdname', 'time', 'tottime'] - # Test each sort option individually for option in sort_options: with self.subTest(sort_option=option): returncode, stdout, stderr = self._run_profile_cli( @@ -187,22 +186,18 @@ def test_sort_options(self): self.assertIn("function calls", stdout) def test_output_file(self): - """Test writing profile results to a file.""" - output_file = TESTFN + '.prof' - self.addCleanup(unlink, output_file) + output_file = os.path.join(self.temp_dir, "profile_output.prof") returncode, stdout, stderr = self._run_profile_cli( '-o', output_file, self.script_file ) self.assertEqual(returncode, 0) - # Check that the output file exists and contains profile data self.assertTrue(os.path.exists(output_file)) stats = pstats.Stats(output_file) self.assertGreater(stats.total_calls, 0) def test_invalid_option(self): - """Test behavior with an invalid option.""" returncode, stdout, stderr = self._run_profile_cli( '--invalid-option', self.script_file ) @@ -210,11 +205,9 @@ def test_invalid_option(self): self.assertIn("error", stderr.lower()) def test_no_arguments(self): - """Test behavior with no arguments.""" returncode, stdout, stderr = self._run_profile_cli() self.assertNotEqual(returncode, 0) - # Check either stdout or stderr for usage information combined_output = stdout.lower() + stderr.lower() self.assertTrue( "usage:" in combined_output or @@ -224,19 +217,30 @@ def test_no_arguments(self): ) def test_run_module(self): - """Test profiling a module with -m option.""" - # Create a small module - module_name = "test_profile_module" - module_file = f"{module_name}.py" - + module_name = "profilemod" + module_file = os.path.join(self.temp_dir, f"{module_name}.py") + with open(module_file, "w") as f: f.write("print('Module executed')\n") - - self.addCleanup(unlink, module_file) - - returncode, stdout, stderr = self._run_profile_cli( - '-m', module_name + + env = os.environ.copy() + + python_path = self.temp_dir + if 'PYTHONPATH' in env: + python_path = os.pathsep.join([python_path, env['PYTHONPATH']]) + env['PYTHONPATH'] = python_path + + cmd = [sys.executable, '-m', 'profile', '-m', module_name] + proc = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True, + env=env ) + stdout, stderr = proc.communicate() + returncode = proc.returncode + self.assertEqual(returncode, 0) self.assertIn("Module executed", stdout) self.assertIn("function calls", stdout) From 9d6e590371f1a75dbae6eefbc23cc344644886cd Mon Sep 17 00:00:00 2001 From: Shaurya Bisht <87357655+ShauryaDusht@users.noreply.github.com> Date: Sat, 17 May 2025 12:13:12 +0530 Subject: [PATCH 5/5] lint fixes --- Lib/test/test_profile.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_profile.py b/Lib/test/test_profile.py index a9c5adbb6406ef..581b120a9a88cb 100644 --- a/Lib/test/test_profile.py +++ b/Lib/test/test_profile.py @@ -140,7 +140,7 @@ class ProfileCLITests(unittest.TestCase): def setUp(self): self.temp_dir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, self.temp_dir) - + self.script_content = """\ def factorial(n): if n <= 1: @@ -219,17 +219,17 @@ def test_no_arguments(self): def test_run_module(self): module_name = "profilemod" module_file = os.path.join(self.temp_dir, f"{module_name}.py") - + with open(module_file, "w") as f: f.write("print('Module executed')\n") - + env = os.environ.copy() - + python_path = self.temp_dir if 'PYTHONPATH' in env: python_path = os.pathsep.join([python_path, env['PYTHONPATH']]) env['PYTHONPATH'] = python_path - + cmd = [sys.executable, '-m', 'profile', '-m', module_name] proc = subprocess.Popen( cmd, @@ -240,7 +240,7 @@ def test_run_module(self): ) stdout, stderr = proc.communicate() returncode = proc.returncode - + self.assertEqual(returncode, 0) self.assertIn("Module executed", stdout) self.assertIn("function calls", stdout) 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