Skip to content

Commit

Permalink
Refactor pdb executable targets (#112570)
Browse files Browse the repository at this point in the history
Co-authored-by: Jason R. Coombs <jaraco@jaraco.com>
  • Loading branch information
gaogaotiantian and jaraco authored Mar 29, 2024
1 parent 54f7e14 commit 0fa571d
Showing 1 changed file with 36 additions and 41 deletions.
77 changes: 36 additions & 41 deletions Lib/pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,12 @@
import signal
import inspect
import tokenize
import functools
import traceback
import linecache

from contextlib import contextmanager
from rlcompleter import Completer
from typing import Union
from types import CodeType


class Restart(Exception):
Expand Down Expand Up @@ -156,77 +155,75 @@ 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)

def __repr__(self):
return self._target

@property
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
def namespace(self):
return dict(
__name__='__main__',
__file__=self,
__file__=self._target,
__builtins__=__builtins__,
__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):
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)
except Exception:
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):
Expand Down Expand Up @@ -2029,7 +2026,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
Expand Down Expand Up @@ -2281,8 +2278,6 @@ def main():
file = opts.args.pop(0)
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
Expand All @@ -2306,8 +2301,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")
Expand Down

0 comments on commit 0fa571d

Please sign in to comment.