-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
gh-133953: Add attach
command to pdb
#133954
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
Open
gaogaotiantian
wants to merge
13
commits into
python:main
Choose a base branch
from
gaogaotiantian:pdb-attach-command
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
3fef8c7
Add attach command to pdb
gaogaotiantian 9ddd100
📜🤖 Added by blurb_it.
blurb-it[bot] 2a9887f
Unify process to pid
gaogaotiantian f48a1c6
Add docs
gaogaotiantian 93e5f58
Polish the whatsnew entry a bit
gaogaotiantian 5297666
Fix lint
gaogaotiantian ae9669c
Merge branch 'main' into pdb-attach-command
gaogaotiantian 1e774a0
Fix docs
gaogaotiantian b3ffe8c
Add a sync mechanism
gaogaotiantian 13d77ad
Skip the test if env does not support it
gaogaotiantian 9c83026
Address comments and add a test
gaogaotiantian 455d9bb
Remove space
gaogaotiantian 77fb481
Update pdb.rst
gaogaotiantian File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -709,6 +709,24 @@ def _get_asyncio_task(self): | |||||||
task = None | ||||||||
return task | ||||||||
|
||||||||
def _get_pid_from_process(self, process): | ||||||||
"""process could evaluate to any object with a `process` attribute or an integer | ||||||||
""" | ||||||||
|
||||||||
try: | ||||||||
process = self._getval(process) | ||||||||
except: | ||||||||
# Error message is already displayed | ||||||||
return None | ||||||||
|
||||||||
pid = getattr(process, "pid", process) | ||||||||
|
||||||||
if not isinstance(pid, int): | ||||||||
self.error(f"Invalid process {process!r}") | ||||||||
return None | ||||||||
|
||||||||
return pid | ||||||||
|
||||||||
def interaction(self, frame, tb_or_exc): | ||||||||
# Restore the previous signal handler at the Pdb prompt. | ||||||||
if Pdb._previous_sigint_handler: | ||||||||
|
@@ -1961,6 +1979,23 @@ def do_debug(self, arg): | |||||||
|
||||||||
complete_debug = _complete_expression | ||||||||
|
||||||||
def do_attach(self, arg): | ||||||||
"""attach process | ||||||||
|
||||||||
Attach to process, which can be any object that has a pid | ||||||||
attribute or a process ID. | ||||||||
""" | ||||||||
pid = self._get_pid_from_process(arg) | ||||||||
|
||||||||
if pid is not None: | ||||||||
self.message(f"Attaching to process {pid}") | ||||||||
try: | ||||||||
attach(pid) | ||||||||
except Exception as e: | ||||||||
self._error_exc() | ||||||||
return | ||||||||
self.message(f"Detached from process {pid}") | ||||||||
|
||||||||
def do_quit(self, arg): | ||||||||
"""q(uit) | exit | ||||||||
|
||||||||
|
@@ -2741,6 +2776,9 @@ def _ensure_valid_message(self, msg): | |||||||
# Due to aliases this list is not static, but the client | ||||||||
# needs to know it for multi-line editing. | ||||||||
pass | ||||||||
case {"attach": int()}: | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably worth adding a comment explaining what this message type is used for, if only for consistency with the other message types.
Suggested change
|
||||||||
# Ask the client to attach to the given process ID. | ||||||||
pass | ||||||||
case _: | ||||||||
raise AssertionError( | ||||||||
f"PDB message doesn't follow the schema! {msg}" | ||||||||
|
@@ -2925,6 +2963,11 @@ def detach(self): | |||||||
# close() can fail if the connection was broken unexpectedly. | ||||||||
pass | ||||||||
|
||||||||
def do_attach(self, process): | ||||||||
pid = self._get_pid_from_process(process) | ||||||||
if pid is not None: | ||||||||
self._send(attach=pid) | ||||||||
|
||||||||
def do_debug(self, arg): | ||||||||
# Clear our cached list of valid commands; the recursive debugger might | ||||||||
# send its own differing list, and so ours needs to be re-sent. | ||||||||
|
@@ -3277,6 +3320,14 @@ def process_payload(self, payload): | |||||||
state = "dumb" | ||||||||
self.state = state | ||||||||
self.prompt_for_reply(prompt) | ||||||||
case {"attach": int(pid)}: | ||||||||
print(f"Attaching to process {pid}") | ||||||||
try: | ||||||||
attach(pid) | ||||||||
print(f"Detached from process {pid}") | ||||||||
except Exception as exc: | ||||||||
msg = traceback.format_exception_only(exc)[-1].strip() | ||||||||
print("***", msg, flush=True) | ||||||||
case _: | ||||||||
raise RuntimeError(f"Unrecognized payload {payload}") | ||||||||
|
||||||||
|
@@ -3388,6 +3439,12 @@ def _connect( | |||||||
|
||||||||
def attach(pid, commands=()): | ||||||||
"""Attach to a running process with the given PID.""" | ||||||||
|
||||||||
if threading.current_thread() is not threading.main_thread(): | ||||||||
raise RuntimeError( | ||||||||
"pdb.attach() must be called from the main thread" | ||||||||
) | ||||||||
|
||||||||
with ExitStack() as stack: | ||||||||
server = stack.enter_context( | ||||||||
closing(socket.create_server(("localhost", 0))) | ||||||||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
Misc/NEWS.d/next/Library/2025-05-12-20-58-11.gh-issue-133953.1dswu9.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
``attach`` command is added to :mod:`pdb` to attach to a running process. |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some assumptions in
attach
that the_PdbClient
is being run from the main thread - the entire signal handling approach relies upon it, at the very least - I think it'll just wind up failing with an exception if run from a non-main thread, at the point where it tries to install the signal handler.I think we should check if we're in the main thread explicitly and
self.error()
if not.Or, thinking outside of the box, we could spawn a new process to do the attaching from its main thread, and return control back to the parent process after it finishes.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The great thing about attaching directly from the process is that there's the automatic parent-child relation. So even with the tracing restriction, you can still attach to your child processes - spawning a new process won't let you do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's true, and that's a nice advantage - but certainly not one big enough to live with Ctrl+C not working! And you only get that advantage when starting off in non-remote PDB - if you started off in remote PDB, the child process won't be a child of the client (which means it also won't work when you
attach
to a child process and thenattach
again to a grandchild process).The most reasonable choice might just be to make it so that the
pdb.attach
module level function raises an exception if it's called from any thread but the main thread. Then theattach
PDB command will work from any thread when running remote PDB, and from the main thread when running normal PDB, but will fail when when called on a non-main thread in non-remote PDB.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that true? I thought the trace_scope applies to descendants, not only direct children. So grandchildren should work? (I have a test that does that, if our linux buildbot has the restriction, it should prove the theory)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems a reasonable option. It won't work when
_PdbClient
is not in the main thread. We can explore other options in the future, but for now, making what works work seems to be the way to go.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, yes, you're right.