From ed7811e64fba9f4c352ba6c9d3e1057954e73c21 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Thu, 30 Nov 2023 20:17:54 -0800 Subject: [PATCH 1/2] Refactor pdb executable targets --- Lib/pdb.py | 77 ++++++++++++++++++++++++++---------------------------- 1 file changed, 37 insertions(+), 40 deletions(-) diff --git a/Lib/pdb.py b/Lib/pdb.py index 9d124189df11cf..9458747d4a64dd 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -81,11 +81,11 @@ import signal import inspect import tokenize -import functools import traceback import linecache from contextlib import contextmanager +from types import CodeType from typing import Union @@ -124,51 +124,58 @@ def __repr__(self): return self -class _ScriptTarget(str): - def __new__(cls, val): - # Mutate self to be the "real path". - res = super().__new__(cls, os.path.realpath(val)) +class _ExecutableTarget: + filename: str + code: CodeType | str + namespace: dict - # Store the original path for error reporting. - res.orig = val - return res +class _ScriptTarget(_ExecutableTarget): + def __init__(self, target): + self._target = os.path.realpath(target) - def check(self): - if not os.path.exists(self): - print('Error:', self.orig, 'does not exist') + if not os.path.exists(self._target): + print(f'Error: {target} does not exist') sys.exit(1) - if os.path.isdir(self): - print('Error:', self.orig, 'is a directory') + if os.path.isdir(self._target): + print(f'Error: {target} is a directory') sys.exit(1) # If safe_path(-P) is not set, sys.path[0] is the directory # of pdb, and we should replace it with the directory of the script if not sys.flags.safe_path: - sys.path[0] = os.path.dirname(self) + sys.path[0] = os.path.dirname(self._target) + + with io.open_code(self._target) as fp: + self._code = f"exec(compile({fp.read()!r}, {self._target!r}, 'exec'))" + + def __repr__(self): + return self._target @property def filename(self): - return self + return self._target + + @property + def code(self): + return self._code @property def namespace(self): return dict( __name__='__main__', - __file__=self, + __file__=self._target, __builtins__=__builtins__, ) - @property - def code(self): - with io.open_code(self) as fp: - return f"exec(compile({fp.read()!r}, {self!r}, 'exec'))" +class _ModuleTarget(_ExecutableTarget): + def __init__(self, target): + self._target = target -class _ModuleTarget(str): - def check(self): + import runpy try: - self._details + _, self._spec, self._code = runpy._get_module_details(self._target) except ImportError as e: print(f"ImportError: {e}") sys.exit(1) @@ -176,24 +183,16 @@ def check(self): traceback.print_exc() sys.exit(1) - @functools.cached_property - def _details(self): - import runpy - return runpy._get_module_details(self) + def __repr__(self): + return self._target @property def filename(self): - return self.code.co_filename + return self._code.co_filename @property def code(self): - name, spec, code = self._details - return code - - @property - def _spec(self): - name, spec, code = self._details - return spec + return self._code @property def namespace(self): @@ -1958,7 +1957,7 @@ def lookupmodule(self, filename): return fullname return None - def _run(self, target: Union[_ModuleTarget, _ScriptTarget]): + def _run(self, target: _ExecutableTarget): # When bdb sets tracing, a number of call and line events happen # BEFORE debugger even reaches user's code (and the exact sequence of # events depends on python version). Take special measures to @@ -2200,8 +2199,6 @@ def main(): file = opts.pyfile target = _ScriptTarget(file) - target.check() - sys.argv[:] = [file] + opts.args # Hide "pdb.py" and pdb options from argument list # Note on saving/restoring sys.argv: it's a good idea when sys.argv was @@ -2225,8 +2222,8 @@ def main(): print("Uncaught exception. Entering post mortem debugging") print("Running 'cont' or 'step' will restart the program") pdb.interaction(None, e) - print("Post mortem debugger finished. The " + target + - " will be restarted") + print(f"Post mortem debugger finished. The {target} will " + "be restarted") if pdb._user_requested_quit: break print("The program finished and will be restarted") From 2ad53187c7b942a0d4f70ca670c651c00193deaf Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Thu, 28 Mar 2024 14:17:31 -0700 Subject: [PATCH 2/2] Update Lib/pdb.py Co-authored-by: Jason R. Coombs --- Lib/pdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/pdb.py b/Lib/pdb.py index 0618ee17f44a0e..d4138b95d3c332 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -186,7 +186,7 @@ def filename(self): @property def code(self): - # We need to open the file each time because the file may be modified + # Open the file each time because the file may be modified with io.open_code(self._target) as fp: return f"exec(compile({fp.read()!r}, {self._target!r}, 'exec'))"