Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
5225333
Allow pdb to attach to a running process
godlygeek Apr 12, 2025
78a3085
Remove 2 unused _RemotePdb instance attributes
godlygeek Apr 15, 2025
90e0a81
Reduce duplication for 'debug' command
godlygeek Apr 15, 2025
e44a670
End commands entry on 'end' and ^C and ^D
godlygeek Apr 15, 2025
e837246
Set the frame for remote pdb to stop in explicitly
godlygeek Apr 15, 2025
27efa97
Fix an unbound local in an error message
godlygeek Apr 15, 2025
557a725
Clean up remote PDB detaching
godlygeek Apr 15, 2025
7f7584a
Allow ctrl-c to interrupt a running process
godlygeek Apr 17, 2025
5666ffb
Automatically detach if the client dies unexpectedly
godlygeek Apr 17, 2025
325f166
Clear _last_pdb_instance on detach
godlygeek Apr 17, 2025
72830e2
Refuse to attach if another PDB instance is installed
godlygeek Apr 17, 2025
27c6780
Handle the confirmation prompt issued by 'clear'
godlygeek Apr 18, 2025
baaf28a
Make message and error handle non-string args
godlygeek Apr 18, 2025
e61cc31
Add some basic tests
pablogsal Apr 18, 2025
5d59ce1
Don't use deprecated method
pablogsal Apr 18, 2025
09adb2b
Try to prevent a PermissionError on Windows
godlygeek Apr 18, 2025
600aa05
Address review comments
godlygeek Apr 20, 2025
0601f10
Add protocol versioning and support -c commands
godlygeek Apr 20, 2025
5a1755b
Fix tests to match new _connect signature for protocol versioning/com…
godlygeek Apr 21, 2025
f184e4e
Add some comments describing our protocol
godlygeek Apr 21, 2025
82b71f8
Use the 'commands' state for '(com)' prompts
godlygeek Apr 22, 2025
3986c17
Remove choices parameter from _prompt_for_confirmation
godlygeek Apr 22, 2025
2e69667
Rename _RemotePdb to _PdbServer
godlygeek Apr 22, 2025
55adbcc
Avoid fallthrough in signal handling
godlygeek Apr 22, 2025
0bda5c2
Fix handling of a SystemExit raised in normal pdb mode
godlygeek Apr 22, 2025
5e93247
Address nit
godlygeek Apr 22, 2025
f799e83
Use textwrap.dedent for test readability
godlygeek Apr 22, 2025
46fb219
Drop dataclasses dependency
godlygeek Apr 22, 2025
1ec9475
Combine the two blocks for handling -p PID into one
godlygeek Apr 22, 2025
662c7eb
Add a news entry
godlygeek Apr 22, 2025
ac36d7d
Skip remote PDB integration test on WASI
godlygeek Apr 22, 2025
f06d9c2
Two small things missed in the previous fixes
godlygeek Apr 22, 2025
715af27
Remove call to set_step in interrupt handler
godlygeek Apr 22, 2025
c654fdf
More tests
pablogsal Apr 23, 2025
205bc55
More tests
pablogsal Apr 23, 2025
bbe784b
More tests
pablogsal Apr 23, 2025
30cb537
Add what's new entry
pablogsal Apr 23, 2025
659556f
use dedent
pablogsal Apr 23, 2025
6c2d970
Add synchronization to test_keyboard_interrupt
godlygeek Apr 24, 2025
100be44
Stop sending a "signal" message in test_keyboard_interrupt"
godlygeek Apr 24, 2025
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
Prev Previous commit
Next Next commit
Add some comments describing our protocol
Ensure all sent messages conform to the protocol. Tell future
maintainers what to update if the protocol changes.
  • Loading branch information
godlygeek committed Apr 21, 2025
commit f184e4e1a94f959a6c835708e2289fec856b4e8e
99 changes: 91 additions & 8 deletions Lib/pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -2539,7 +2539,48 @@ def protocol_version():
revision = 0
return int(f"{v.major:02X}{v.minor:02X}{revision:02X}F0", 16)
Comment thread
gaogaotiantian marked this conversation as resolved.

def _send(self, **kwargs) -> None:
def _ensure_valid_message(self, msg):
# Ensure the message conforms to our protocol.
# If anything needs to be changed here for a patch release of Python,
# the 'revision' in protocol_version() should be updated.
match msg:
case {"message": str(), "type": str()}:
# Have the client show a message. The client chooses how to
# format the message based on its type. The currently defined
# types are "info" and "error". If a message has a type the
# client doesn't recognize, it must be treated as "info".
pass
case {"help": str()}:
# Have the client show the help for a given argument.
pass
case {"prompt": str(), "state": str()}:
# Have the client display the given prompt and wait for a reply
# from the user. If the client recognizes the state it may
# enable mode-specific features like multi-line editing.
# If it doesn't recognize the state it must prompt for a single
# line only and send it directly to the server. A server won't
# progress until it gets a "reply" or "signal" message, but can
# process "complete" requests while waiting for the reply.
pass
case {
"completions": list(completions)
} if all(isinstance(c, str) for c in completions):
# Return valid completions for a client's "complete" request.
pass
case {
"command_list": list(command_list)
} if all(isinstance(c, str) for c in command_list):
# Report the list of legal PDB commands to the client.
# Due to aliases this list is not static, but the client
# needs to know it for multi-line editing.
pass
case _:
raise AssertionError(
f"PDB message doesn't follow the schema! {msg}"
)

def _send(self, **kwargs):
self._ensure_valid_message(kwargs)
json_payload = json.dumps(kwargs)
try:
self._sockfile.write(json_payload.encode() + b"\n")
Expand Down Expand Up @@ -2774,6 +2815,51 @@ def __init__(self, pid, sockfile, interrupt_script):
self.pdb_commands = set()
self.completion_matches = []
self.state = "dumb"
self.write_failed = False

def _ensure_valid_message(self, msg):
# Ensure the message conforms to our protocol.
# If anything needs to be changed here for a patch release of Python,
# the 'revision' in protocol_version() should be updated.
match msg:
case {"reply": str()}:
# Send input typed by a user at a prompt to the remote PDB.
pass
case {"signal": "EOF"}:
# Tell the remote PDB that the user pressed ^D at a prompt.
pass
case {"signal": "INT"}:
# Tell the remote PDB that the user pressed ^C at a prompt.
pass
case {
"complete": {
"text": str(),
"line": str(),
"begidx": int(),
"endidx": int(),
}
}:
# Ask the remote PDB what completions are valid for the given
# parameters, using readline's completion protocol.
pass
case _:
raise AssertionError(
f"PDB message doesn't follow the schema! {msg}"
)

def _send(self, **kwargs):
self._ensure_valid_message(kwargs)
json_payload = json.dumps(kwargs)
try:
self.sockfile.write(json_payload.encode() + b"\n")
self.sockfile.flush()
except OSError:
# This means that the client has abruptly disconnected, but we'll
# handle that the next time we try to read from the client instead
# of trying to handle it from everywhere _send() may be called.
# Track this with a flag rather than assuming readline() will ever
# return an empty string because the socket may be half-closed.
self.write_failed = True

def read_command(self, prompt):
reply = input(prompt)
Expand Down Expand Up @@ -2829,7 +2915,7 @@ def readline_completion(self, completer):

def cmdloop(self):
with self.readline_completion(self.complete):
while True:
while not self.write_failed:
try:
if not (payload_bytes := self.sockfile.readline()):
break
Expand Down Expand Up @@ -2889,8 +2975,7 @@ def prompt_for_reply(self, prompt):
print("***", msg, flush=True)
continue

self.sockfile.write((json.dumps(payload) + "\n").encode())
self.sockfile.flush()
self._send(**payload)
return

def complete(self, text, state):
Expand All @@ -2916,10 +3001,8 @@ def complete(self, text, state):
}
}

try:
self.sockfile.write((json.dumps(msg) + "\n").encode())
self.sockfile.flush()
except OSError:
self._send(**msg)
if self.write_failed:
return None

payload = self.sockfile.readline()
Expand Down
Loading