mirror of
https://github.com/python/cpython.git
synced 2025-09-26 10:19:53 +00:00
Refactor pdb executable targets (#112570)
Co-authored-by: Jason R. Coombs <jaraco@jaraco.com>
This commit is contained in:
parent
54f7e14500
commit
0fa571dbcd
1 changed files with 36 additions and 41 deletions
77
Lib/pdb.py
77
Lib/pdb.py
|
@ -82,13 +82,12 @@ import pprint
|
||||||
import signal
|
import signal
|
||||||
import inspect
|
import inspect
|
||||||
import tokenize
|
import tokenize
|
||||||
import functools
|
|
||||||
import traceback
|
import traceback
|
||||||
import linecache
|
import linecache
|
||||||
|
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from rlcompleter import Completer
|
from rlcompleter import Completer
|
||||||
from typing import Union
|
from types import CodeType
|
||||||
|
|
||||||
|
|
||||||
class Restart(Exception):
|
class Restart(Exception):
|
||||||
|
@ -156,52 +155,58 @@ class _rstr(str):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
class _ScriptTarget(str):
|
class _ExecutableTarget:
|
||||||
def __new__(cls, val):
|
filename: str
|
||||||
# Mutate self to be the "real path".
|
code: CodeType | str
|
||||||
res = super().__new__(cls, os.path.realpath(val))
|
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._target):
|
||||||
if not os.path.exists(self):
|
print(f'Error: {target} does not exist')
|
||||||
print('Error:', self.orig, 'does not exist')
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if os.path.isdir(self):
|
if os.path.isdir(self._target):
|
||||||
print('Error:', self.orig, 'is a directory')
|
print(f'Error: {target} is a directory')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# If safe_path(-P) is not set, sys.path[0] is the directory
|
# 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
|
# of pdb, and we should replace it with the directory of the script
|
||||||
if not sys.flags.safe_path:
|
if not sys.flags.safe_path:
|
||||||
sys.path[0] = os.path.dirname(self)
|
sys.path[0] = os.path.dirname(self._target)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return self._target
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def filename(self):
|
def filename(self):
|
||||||
return self
|
return self._target
|
||||||
|
|
||||||
|
@property
|
||||||
|
def code(self):
|
||||||
|
# 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'))"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def namespace(self):
|
def namespace(self):
|
||||||
return dict(
|
return dict(
|
||||||
__name__='__main__',
|
__name__='__main__',
|
||||||
__file__=self,
|
__file__=self._target,
|
||||||
__builtins__=__builtins__,
|
__builtins__=__builtins__,
|
||||||
__spec__=None,
|
__spec__=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
@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):
|
import runpy
|
||||||
def check(self):
|
|
||||||
try:
|
try:
|
||||||
self._details
|
_, self._spec, self._code = runpy._get_module_details(self._target)
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
print(f"ImportError: {e}")
|
print(f"ImportError: {e}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
@ -209,24 +214,16 @@ class _ModuleTarget(str):
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
@functools.cached_property
|
def __repr__(self):
|
||||||
def _details(self):
|
return self._target
|
||||||
import runpy
|
|
||||||
return runpy._get_module_details(self)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def filename(self):
|
def filename(self):
|
||||||
return self.code.co_filename
|
return self._code.co_filename
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def code(self):
|
def code(self):
|
||||||
name, spec, code = self._details
|
return self._code
|
||||||
return code
|
|
||||||
|
|
||||||
@property
|
|
||||||
def _spec(self):
|
|
||||||
name, spec, code = self._details
|
|
||||||
return spec
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def namespace(self):
|
def namespace(self):
|
||||||
|
@ -2029,7 +2026,7 @@ class Pdb(bdb.Bdb, cmd.Cmd):
|
||||||
return fullname
|
return fullname
|
||||||
return None
|
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
|
# When bdb sets tracing, a number of call and line events happen
|
||||||
# BEFORE debugger even reaches user's code (and the exact sequence of
|
# BEFORE debugger even reaches user's code (and the exact sequence of
|
||||||
# events depends on python version). Take special measures to
|
# events depends on python version). Take special measures to
|
||||||
|
@ -2281,8 +2278,6 @@ def main():
|
||||||
file = opts.args.pop(0)
|
file = opts.args.pop(0)
|
||||||
target = _ScriptTarget(file)
|
target = _ScriptTarget(file)
|
||||||
|
|
||||||
target.check()
|
|
||||||
|
|
||||||
sys.argv[:] = [file] + opts.args # Hide "pdb.py" and pdb options from argument list
|
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
|
# Note on saving/restoring sys.argv: it's a good idea when sys.argv was
|
||||||
|
@ -2306,8 +2301,8 @@ def main():
|
||||||
print("Uncaught exception. Entering post mortem debugging")
|
print("Uncaught exception. Entering post mortem debugging")
|
||||||
print("Running 'cont' or 'step' will restart the program")
|
print("Running 'cont' or 'step' will restart the program")
|
||||||
pdb.interaction(None, e)
|
pdb.interaction(None, e)
|
||||||
print("Post mortem debugger finished. The " + target +
|
print(f"Post mortem debugger finished. The {target} will "
|
||||||
" will be restarted")
|
"be restarted")
|
||||||
if pdb._user_requested_quit:
|
if pdb._user_requested_quit:
|
||||||
break
|
break
|
||||||
print("The program finished and will be restarted")
|
print("The program finished and will be restarted")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue