8000 Refactor pdb executable targets by gaogaotiantian · Pull Request #112570 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

Refactor pdb executable targets #112570

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 29, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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