From f47d1b779333657d7d87b21db841d5d3ad6cfa5c Mon Sep 17 00:00:00 2001 From: Mario Corchero Date: Sun, 3 Dec 2017 13:31:51 +0000 Subject: [PATCH 01/12] WIP: Run modules as script with pdb Since PEP 338 we can run python modules as a script via `python -m module_name` but there is no way to run pdb on those. The proposal is to add a new argument "-m" to the pdb module to allow users to run `python -m pdb -m my_module_name`. --- Lib/pdb.py | 24 ++++++++++-- Lib/test/test_pdb.py | 89 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 96 insertions(+), 17 deletions(-) diff --git a/Lib/pdb.py b/Lib/pdb.py index 8dd4dedb220766..86fa75a291a400 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1521,6 +1521,15 @@ def lookupmodule(self, filename): return fullname return None + def _runmodule(self, module_name): + self._wait_for_mainpyfile = True + self.mainpyfile = self.canonic(module_name) + self._user_requested_quit = False + #code = f'import runpy; runpy.run_module("{module_name}", run_name="__main__")' + code = f'import runpy; runpy._run_module_as_main("{module_name}")' + statement = f'exec(compile("""{code}""", "{self.mainpyfile}", "exec"))' + self.run(statement) + def _runscript(self, filename): # The script has to run in __main__ namespace (or imports from # __main__ will break). @@ -1635,29 +1644,33 @@ def help(): def main(): import getopt - opts, args = getopt.getopt(sys.argv[1:], 'hc:', ['--help', '--command=']) + opts, args = getopt.getopt(sys.argv[1:], 'mhc:', ['--help', '--command=']) if not args: print(_usage) sys.exit(2) commands = [] + run_as_module = False for opt, optarg in opts: if opt in ['-h', '--help']: print(_usage) sys.exit() elif opt in ['-c', '--command']: commands.append(optarg) + elif opt in ['-m']: + run_as_module = True mainpyfile = args[0] # Get script filename - if not os.path.exists(mainpyfile): + if not run_as_module and not os.path.exists(mainpyfile): print('Error:', mainpyfile, 'does not exist') sys.exit(1) sys.argv[:] = args # Hide "pdb.py" and pdb options from argument list # Replace pdb's dir with script's dir in front of module search path. - sys.path[0] = os.path.dirname(mainpyfile) + if not run_as_module: + sys.path[0] = os.path.dirname(mainpyfile) # Note on saving/restoring sys.argv: it's a good idea when sys.argv was # modified by the script being debugged. It's a bad idea when it was @@ -1667,7 +1680,10 @@ def main(): pdb.rcLines.extend(commands) while True: try: - pdb._runscript(mainpyfile) + if run_as_module: + pdb._runmodule(mainpyfile) + else: + pdb._runscript(mainpyfile) if pdb._user_requested_quit: break print("The program finished and will be restarted") diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 71d8203fc56a0a..6551549df20fd8 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -938,26 +938,26 @@ def test_pdb_issue_20766(): pdb 2: """ -class PdbTestCase(unittest.TestCase): - - def run_pdb(self, script, commands): +class PdbBaseTestCase(unittest.TestCase): + def _run_pdb(self, pdb_args, commands): """Run 'script' lines with pdb and the pdb 'commands'.""" - filename = 'main.py' - with open(filename, 'w') as f: - f.write(textwrap.dedent(script)) - self.addCleanup(support.unlink, filename) self.addCleanup(support.rmtree, '__pycache__') - cmd = [sys.executable, '-m', 'pdb', filename] + cmd = [sys.executable, '-m', 'pdb'] + pdb_args stdout = stderr = None - with subprocess.Popen(cmd, stdout=subprocess.PIPE, - stdin=subprocess.PIPE, - stderr=subprocess.STDOUT, - ) as proc: + with subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stdin=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) as proc: stdout, stderr = proc.communicate(str.encode(commands)) stdout = stdout and bytes.decode(stdout) stderr = stderr and bytes.decode(stderr) return stdout, stderr + +class PdbScriptTestCase(PdbBaseTestCase): + def _assert_find_function(self, file_content, func_name, expected): file_content = textwrap.dedent(file_content) @@ -969,6 +969,13 @@ def _assert_find_function(self, file_content, func_name, expected): self.assertEqual( expected, pdb.find_function(func_name, support.TESTFN)) + def run_pdb(self, script, commands): + filename = 'main.py' + with open(filename, 'w') as f: + f.write(textwrap.dedent(script)) + self.addCleanup(support.unlink, filename) + return self._run_pdb([filename], commands) + def test_find_function_empty_file(self): self._assert_find_function('', 'foo', None) @@ -1123,9 +1130,65 @@ def tearDown(self): support.unlink(support.TESTFN) +class PdbModuleTestCase(PdbBaseTestCase): + """Re-runs all tests used for a script but using a module""" + + def run_pdb(self, script, commands): + module_name = 't_main' + main_file = module_name + '/__main__.py' + init_file = module_name + '/__init__.py' + os.mkdir(module_name) + with open(init_file, 'w') as f: + pass + with open(main_file, 'w') as f: + f.write(textwrap.dedent(script)) + self.addCleanup(support.rmtree, module_name) + return self._run_pdb(['-m', module_name], commands) + + def test_run_module(self): + script = """print("SUCCESS")""" + commands = """ + continue + quit + """ + stdout, stderr = self.run_pdb(script, commands) + self.assertTrue(any("SUCCESS" in l for l in stdout.splitlines()), stdout) + + def test_module_is_run_as_main(self): + script = """ + if __name__ == '__main__': + print("SUCCESS") + """ + commands = """ + continue + quit + """ + stdout, stderr = self.run_pdb(script, commands) + self.assertTrue(any("SUCCESS" in l for l in stdout.splitlines()), stdout) + + def test_breakpoint(self): + script = """ + if __name__ == '__main__': + pass + print("SUCCESS") + pass + """ + commands = f""" + b t_main/__main__.py:3 + quit + """ + stdout, stderr = self.run_pdb(script, commands) + self.assertTrue(any("Breakpoint 1 at" in l for l in stdout.splitlines()), stdout) + self.assertTrue(all("SUCCESS" not in l for l in stdout.splitlines()), stdout) + + def load_tests(*args): from test import test_pdb - suites = [unittest.makeSuite(PdbTestCase), doctest.DocTestSuite(test_pdb)] + suites = [ + unittest.makeSuite(PdbScriptTestCase), + unittest.makeSuite(PdbModuleTestCase), + doctest.DocTestSuite(test_pdb) + ] return unittest.TestSuite(suites) From db73bf77214150584f10b1a44d3db20e102d37a7 Mon Sep 17 00:00:00 2001 From: Mario Corchero Date: Wed, 6 Dec 2017 20:00:55 +0000 Subject: [PATCH 02/12] Fix pdb starting in runpy --- Lib/pdb.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Lib/pdb.py b/Lib/pdb.py index 86fa75a291a400..91bc9175fb233c 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1525,10 +1525,16 @@ def _runmodule(self, module_name): self._wait_for_mainpyfile = True self.mainpyfile = self.canonic(module_name) self._user_requested_quit = False - #code = f'import runpy; runpy.run_module("{module_name}", run_name="__main__")' - code = f'import runpy; runpy._run_module_as_main("{module_name}")' - statement = f'exec(compile("""{code}""", "{self.mainpyfile}", "exec"))' - self.run(statement) + import runpy + mod_name, _, code = runpy._get_module_details(module_name) + import __main__ + __main__.__dict__.clear() + __main__.__dict__.update({ + "__name__": "__main__", + "__package__": module_name, + "__builtins__": __builtins__, + }) + self.run(code) def _runscript(self, filename): # The script has to run in __main__ namespace (or imports from From 1d59520313f19495eacbdea10deeb308ad903860 Mon Sep 17 00:00:00 2001 From: Mario Corchero Date: Thu, 7 Dec 2017 11:46:41 +0000 Subject: [PATCH 03/12] fix infinite loop --- Lib/pdb.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Lib/pdb.py b/Lib/pdb.py index 91bc9175fb233c..a9ff0ef7f4fbd5 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1523,15 +1523,18 @@ def lookupmodule(self, filename): def _runmodule(self, module_name): self._wait_for_mainpyfile = True - self.mainpyfile = self.canonic(module_name) + self.mainpyfile = os.path.join(self.canonic(module_name), "__main__.py") self._user_requested_quit = False import runpy - mod_name, _, code = runpy._get_module_details(module_name) + mod_name, mod_spec, code = runpy._get_module_details(module_name) import __main__ __main__.__dict__.clear() __main__.__dict__.update({ "__name__": "__main__", - "__package__": module_name, + "__file__": self.mainpyfile, +# "__package__": module_name, # Not needed, will rely on __spec__.parent + "__loader__": mod_spec.loader, + "__spec__": mod_spec, "__builtins__": __builtins__, }) self.run(code) From 57c4ea19aa31dc4cbecc1d559875d9cbfa52b410 Mon Sep 17 00:00:00 2001 From: Mario Corchero Date: Thu, 7 Dec 2017 13:15:25 +0000 Subject: [PATCH 04/12] Add news entry --- .../NEWS.d/next/Library/2017-12-07-13-14-40.bpo-32206.obm4OM.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2017-12-07-13-14-40.bpo-32206.obm4OM.rst diff --git a/Misc/NEWS.d/next/Library/2017-12-07-13-14-40.bpo-32206.obm4OM.rst b/Misc/NEWS.d/next/Library/2017-12-07-13-14-40.bpo-32206.obm4OM.rst new file mode 100644 index 00000000000000..20d7eeace87934 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2017-12-07-13-14-40.bpo-32206.obm4OM.rst @@ -0,0 +1 @@ +Add support to run modules with pdb From e8788cdbe4960f47f581d89af5ea61c32fcd3f8c Mon Sep 17 00:00:00 2001 From: Mario Corchero Date: Thu, 7 Dec 2017 17:11:10 +0000 Subject: [PATCH 05/12] Fix running modules out of path --- Lib/pdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/pdb.py b/Lib/pdb.py index a9ff0ef7f4fbd5..59f81403518d90 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1523,10 +1523,10 @@ def lookupmodule(self, filename): def _runmodule(self, module_name): self._wait_for_mainpyfile = True - self.mainpyfile = os.path.join(self.canonic(module_name), "__main__.py") self._user_requested_quit = False import runpy mod_name, mod_spec, code = runpy._get_module_details(module_name) + self.mainpyfile = self.canonic(code.co_filename) import __main__ __main__.__dict__.clear() __main__.__dict__.update({ From a0226bd625e746ef07984f9a8557d5baebe213e9 Mon Sep 17 00:00:00 2001 From: Mario Corchero Date: Thu, 7 Dec 2017 20:13:41 +0000 Subject: [PATCH 06/12] Add further tests --- Lib/test/test_pdb.py | 98 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 91 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 6551549df20fd8..819433c6167a9f 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1134,16 +1134,17 @@ class PdbModuleTestCase(PdbBaseTestCase): """Re-runs all tests used for a script but using a module""" def run_pdb(self, script, commands): - module_name = 't_main' - main_file = module_name + '/__main__.py' - init_file = module_name + '/__init__.py' - os.mkdir(module_name) + self.module_name = 't_main' + support.rmtree(self.module_name) + main_file = self.module_name + '/__main__.py' + init_file = self.module_name + '/__init__.py' + os.mkdir(self.module_name) with open(init_file, 'w') as f: pass with open(main_file, 'w') as f: f.write(textwrap.dedent(script)) - self.addCleanup(support.rmtree, module_name) - return self._run_pdb(['-m', module_name], commands) + self.addCleanup(support.rmtree, self.module_name) + return self._run_pdb(['-m', self.module_name], commands) def test_run_module(self): script = """print("SUCCESS")""" @@ -1174,13 +1175,96 @@ def test_breakpoint(self): pass """ commands = f""" - b t_main/__main__.py:3 + b 3 quit """ stdout, stderr = self.run_pdb(script, commands) self.assertTrue(any("Breakpoint 1 at" in l for l in stdout.splitlines()), stdout) self.assertTrue(all("SUCCESS" not in l for l in stdout.splitlines()), stdout) + def test_run_pdb(self): + commands = f""" + c + quit + """ + stdout, stderr = self._run_pdb(["-m", "pdb"], commands) + self.assertIn("Debug the Python program given by pyfile.", stdout.splitlines()) + + def test_blocks_at_first_code_line(self): + script = """ + #This is a comment, on line 2 + + print("SUCCESS") + """ + commands = f""" + quit + """ + stdout, stderr = self.run_pdb(script, commands) + self.assertTrue(any(f"/{self.module_name}/__main__.py(4)()" + in l for l in stdout.splitlines()), stdout) + + def test_module_without_a_main(self): + module_name = 't_main' + support.rmtree(module_name) + init_file = module_name + '/__init__.py' + os.mkdir(module_name) + with open(init_file, 'w') as f: + pass + self.addCleanup(support.rmtree, module_name) + stdout, stderr = self._run_pdb(['-m', module_name], "") + self.assertIn("ImportError: No module named t_main.__main__", + stdout.splitlines()) + + def test_blocks_at_first_code_line(self): + script = """ + #This is a comment, on line 2 + + print("SUCCESS") + """ + commands = f""" + quit + """ + stdout, stderr = self.run_pdb(script, commands) + self.assertTrue(any(f"/{self.module_name}/__main__.py(4)()" + in l for l in stdout.splitlines()), stdout) + + def test_relative_imports(self): + self.module_name = 't_main' + support.rmtree(self.module_name) + main_file = self.module_name + '/__main__.py' + init_file = self.module_name + '/__init__.py' + module_file = self.module_name + '/module.py' + self.addCleanup(support.rmtree, self.module_name) + os.mkdir(self.module_name) + with open(init_file, 'w') as f: + f.write(textwrap.dedent(""" + top_var = "VAR from top" + """)) + with open(main_file, 'w') as f: + f.write(textwrap.dedent(""" + from . import top_var + from .module import var + from . import module + pass # We'll stop here and print the vars + """)) + with open(module_file, 'w') as f: + f.write(textwrap.dedent(""" + var = "VAR from module" + var2 = "second var" + """)) + commands = f""" + b 5 + c + p top_var + p var + p module.var2 + quit + """ + stdout, _ = self._run_pdb(['-m', self.module_name], commands) + self.assertTrue(any(f"VAR from module" in l for l in stdout.splitlines())) + self.assertTrue(any(f"VAR from top" in l for l in stdout.splitlines())) + self.assertTrue(any(f"second var" in l for l in stdout.splitlines())) + def load_tests(*args): from test import test_pdb From 2d38a6e3ca28ee348533ee2fd4c1a044d66374bf Mon Sep 17 00:00:00 2001 From: Mario Corchero Date: Wed, 13 Dec 2017 09:35:17 +0000 Subject: [PATCH 07/12] Remove duplicated test --- Lib/test/test_pdb.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 819433c6167a9f..39390a274e19fb 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1190,19 +1190,6 @@ def test_run_pdb(self): stdout, stderr = self._run_pdb(["-m", "pdb"], commands) self.assertIn("Debug the Python program given by pyfile.", stdout.splitlines()) - def test_blocks_at_first_code_line(self): - script = """ - #This is a comment, on line 2 - - print("SUCCESS") - """ - commands = f""" - quit - """ - stdout, stderr = self.run_pdb(script, commands) - self.assertTrue(any(f"/{self.module_name}/__main__.py(4)()" - in l for l in stdout.splitlines()), stdout) - def test_module_without_a_main(self): module_name = 't_main' support.rmtree(module_name) From 15ff83931e33827b5676ca9c3f0be62fe664aeac Mon Sep 17 00:00:00 2001 From: Mario Corchero Date: Wed, 13 Dec 2017 09:37:13 +0000 Subject: [PATCH 08/12] Make test pass on windows The test is validating where pdb starts therefore the part that is failing (checking modulename "/" file) is not relevant on that test --- Lib/test/test_pdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 39390a274e19fb..418b234dc84de7 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1212,7 +1212,7 @@ def test_blocks_at_first_code_line(self): quit """ stdout, stderr = self.run_pdb(script, commands) - self.assertTrue(any(f"/{self.module_name}/__main__.py(4)()" + self.assertTrue(any(f"__main__.py(4)()" in l for l in stdout.splitlines()), stdout) def test_relative_imports(self): From 7a1494a32bf73867f0ed0ab38433ab63943b65f7 Mon Sep 17 00:00:00 2001 From: Mario Corchero Date: Wed, 13 Dec 2017 22:38:52 +0000 Subject: [PATCH 09/12] Add entry in Docs/Library/pdb --- Doc/library/pdb.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 4f3148fb5c3ede..619e0509abf0e3 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -61,6 +61,11 @@ useful than quitting the debugger upon program's exit. :file:`pdb.py` now accepts a ``-c`` option that executes commands as if given in a :file:`.pdbrc` file, see :ref:`debugger-commands`. +.. versionadded:: 3.7 + :file:`pdb.py` now accepts a ``-m`` option that execute modules similar to how + ``python3 -m`` does. The debugger will stop in the first line like with a script. + + The typical usage to break into the debugger from a running program is to insert :: From 8134c27f97ba05739b55a6a3c51921ac043bff22 Mon Sep 17 00:00:00 2001 From: Mario Corchero Date: Fri, 5 Jan 2018 19:15:36 +0000 Subject: [PATCH 10/12] Add entry in standard library docs section --- Doc/whatsnew/3.7.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index b6dad4eab6bf10..9d29ee6b856d41 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -357,6 +357,10 @@ pdb argument. If given, this is printed to the console just before debugging begins. (Contributed by Barry Warsaw in :issue:`31389`.) +pdb command line now accepts `-m module_name` as an alternative to +script file. (Contributed by Mario Corchero in :issue:`32206`.) + + re -- From 6c4eed5d446a4d4dcda119cea89d8a191b80c056 Mon Sep 17 00:00:00 2001 From: Mario Corchero Date: Fri, 5 Jan 2018 19:35:34 +0000 Subject: [PATCH 11/12] Rewording from Nick's review --- Doc/library/pdb.rst | 5 +++-- Lib/pdb.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 619e0509abf0e3..e81c195782d238 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -62,8 +62,9 @@ useful than quitting the debugger upon program's exit. in a :file:`.pdbrc` file, see :ref:`debugger-commands`. .. versionadded:: 3.7 - :file:`pdb.py` now accepts a ``-m`` option that execute modules similar to how - ``python3 -m`` does. The debugger will stop in the first line like with a script. + :file:`pdb.py` now accepts a ``-m`` option that execute modules similar to the way + ``python3 -m`` does. As with a script, the debugger will pause execution just + before the first line of the module. The typical usage to break into the debugger from a running program is to diff --git a/Lib/pdb.py b/Lib/pdb.py index 59f81403518d90..d1a74bb7d7be9d 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1532,7 +1532,7 @@ def _runmodule(self, module_name): __main__.__dict__.update({ "__name__": "__main__", "__file__": self.mainpyfile, -# "__package__": module_name, # Not needed, will rely on __spec__.parent + "__package__": module_name, "__loader__": mod_spec.loader, "__spec__": mod_spec, "__builtins__": __builtins__, From d77dc8768f5aa7ea7b00772d57a5ba2193c2a499 Mon Sep 17 00:00:00 2001 From: Mario Corchero Date: Fri, 5 Jan 2018 22:37:11 +0000 Subject: [PATCH 12/12] Restructure pdb tests --- Lib/test/test_pdb.py | 89 ++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 48 deletions(-) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 418b234dc84de7..0cd235e98ae191 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -938,12 +938,14 @@ def test_pdb_issue_20766(): pdb 2: """ -class PdbBaseTestCase(unittest.TestCase): + +class PdbTestCase(unittest.TestCase): + def tearDown(self): + support.unlink(support.TESTFN) + def _run_pdb(self, pdb_args, commands): - """Run 'script' lines with pdb and the pdb 'commands'.""" self.addCleanup(support.rmtree, '__pycache__') cmd = [sys.executable, '-m', 'pdb'] + pdb_args - stdout = stderr = None with subprocess.Popen( cmd, stdout=subprocess.PIPE, @@ -955,8 +957,27 @@ def _run_pdb(self, pdb_args, commands): stderr = stderr and bytes.decode(stderr) return stdout, stderr + def run_pdb_script(self, script, commands): + """Run 'script' lines with pdb and the pdb 'commands'.""" + filename = 'main.py' + with open(filename, 'w') as f: + f.write(textwrap.dedent(script)) + self.addCleanup(support.unlink, filename) + return self._run_pdb([filename], commands) -class PdbScriptTestCase(PdbBaseTestCase): + def run_pdb_module(self, script, commands): + """Runs the script code as part of a module""" + self.module_name = 't_main' + support.rmtree(self.module_name) + main_file = self.module_name + '/__main__.py' + init_file = self.module_name + '/__init__.py' + os.mkdir(self.module_name) + with open(init_file, 'w') as f: + pass + with open(main_file, 'w') as f: + f.write(textwrap.dedent(script)) + self.addCleanup(support.rmtree, self.module_name) + return self._run_pdb(['-m', self.module_name], commands) def _assert_find_function(self, file_content, func_name, expected): file_content = textwrap.dedent(file_content) @@ -969,13 +990,6 @@ def _assert_find_function(self, file_content, func_name, expected): self.assertEqual( expected, pdb.find_function(func_name, support.TESTFN)) - def run_pdb(self, script, commands): - filename = 'main.py' - with open(filename, 'w') as f: - f.write(textwrap.dedent(script)) - self.addCleanup(support.unlink, filename) - return self._run_pdb([filename], commands) - def test_find_function_empty_file(self): self._assert_find_function('', 'foo', None) @@ -1041,7 +1055,7 @@ def bar(): with open('bar.py', 'w') as f: f.write(textwrap.dedent(bar)) self.addCleanup(support.unlink, 'bar.py') - stdout, stderr = self.run_pdb(script, commands) + stdout, stderr = self.run_pdb_script(script, commands) self.assertTrue( any('main.py(5)foo()->None' in l for l in stdout.splitlines()), 'Fail to step into the caller after a return') @@ -1078,7 +1092,7 @@ def test_issue16180(self): script = "def f: pass\n" commands = '' expected = "SyntaxError:" - stdout, stderr = self.run_pdb(script, commands) + stdout, stderr = self.run_pdb_script(script, commands) self.assertIn(expected, stdout, '\n\nExpected:\n{}\nGot:\n{}\n' 'Fail to handle a syntax error in the debuggee.' @@ -1126,33 +1140,13 @@ def test_header(self): pdb.set_trace(header=header) self.assertEqual(stdout.getvalue(), header + '\n') - def tearDown(self): - support.unlink(support.TESTFN) - - -class PdbModuleTestCase(PdbBaseTestCase): - """Re-runs all tests used for a script but using a module""" - - def run_pdb(self, script, commands): - self.module_name = 't_main' - support.rmtree(self.module_name) - main_file = self.module_name + '/__main__.py' - init_file = self.module_name + '/__init__.py' - os.mkdir(self.module_name) - with open(init_file, 'w') as f: - pass - with open(main_file, 'w') as f: - f.write(textwrap.dedent(script)) - self.addCleanup(support.rmtree, self.module_name) - return self._run_pdb(['-m', self.module_name], commands) - def test_run_module(self): script = """print("SUCCESS")""" commands = """ continue quit """ - stdout, stderr = self.run_pdb(script, commands) + stdout, stderr = self.run_pdb_module(script, commands) self.assertTrue(any("SUCCESS" in l for l in stdout.splitlines()), stdout) def test_module_is_run_as_main(self): @@ -1164,7 +1158,7 @@ def test_module_is_run_as_main(self): continue quit """ - stdout, stderr = self.run_pdb(script, commands) + stdout, stderr = self.run_pdb_module(script, commands) self.assertTrue(any("SUCCESS" in l for l in stdout.splitlines()), stdout) def test_breakpoint(self): @@ -1174,16 +1168,16 @@ def test_breakpoint(self): print("SUCCESS") pass """ - commands = f""" + commands = """ b 3 quit """ - stdout, stderr = self.run_pdb(script, commands) + stdout, stderr = self.run_pdb_module(script, commands) self.assertTrue(any("Breakpoint 1 at" in l for l in stdout.splitlines()), stdout) self.assertTrue(all("SUCCESS" not in l for l in stdout.splitlines()), stdout) - def test_run_pdb(self): - commands = f""" + def test_run_pdb_with_pdb(self): + commands = """ c quit """ @@ -1208,11 +1202,11 @@ def test_blocks_at_first_code_line(self): print("SUCCESS") """ - commands = f""" + commands = """ quit """ - stdout, stderr = self.run_pdb(script, commands) - self.assertTrue(any(f"__main__.py(4)()" + stdout, stderr = self.run_pdb_module(script, commands) + self.assertTrue(any("__main__.py(4)()" in l for l in stdout.splitlines()), stdout) def test_relative_imports(self): @@ -1239,7 +1233,7 @@ def test_relative_imports(self): var = "VAR from module" var2 = "second var" """)) - commands = f""" + commands = """ b 5 c p top_var @@ -1248,16 +1242,15 @@ def test_relative_imports(self): quit """ stdout, _ = self._run_pdb(['-m', self.module_name], commands) - self.assertTrue(any(f"VAR from module" in l for l in stdout.splitlines())) - self.assertTrue(any(f"VAR from top" in l for l in stdout.splitlines())) - self.assertTrue(any(f"second var" in l for l in stdout.splitlines())) + self.assertTrue(any("VAR from module" in l for l in stdout.splitlines())) + self.assertTrue(any("VAR from top" in l for l in stdout.splitlines())) + self.assertTrue(any("second var" in l for l in stdout.splitlines())) def load_tests(*args): from test import test_pdb suites = [ - unittest.makeSuite(PdbScriptTestCase), - unittest.makeSuite(PdbModuleTestCase), + unittest.makeSuite(PdbTestCase), doctest.DocTestSuite(test_pdb) ] return unittest.TestSuite(suites)