Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Merged
Changes from 1 commit
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8d89bf4
Only allow KeyboardInterrupt at specific times
godlygeek Apr 30, 2025
f65f99f
Have _PdbClient work with the socket directly
godlygeek Apr 30, 2025
ec9d3bf
Allow interrupting socket reads on Windows
godlygeek Apr 30, 2025
ed664b8
Use a SIGINT to interrupt the remote on Unix
godlygeek Apr 30, 2025
aafa48c
Handle a ValueError for operations on a closed file
godlygeek May 1, 2025
42e7cec
Use a single complex signal handler for the PDB client
godlygeek May 1, 2025
02da647
Add a news entry
godlygeek May 1, 2025
5abd63a
Update the comment to explain why we catch two exception types
godlygeek May 2, 2025
c9c5bf2
Swap signal_read/signal_write resetting to the outer finally block
godlygeek May 2, 2025
8fa88a5
Use os.kill() on every platform but Windows
godlygeek May 2, 2025
4c0b431
Use `ExitStack` to reduce nesting in `attach`
godlygeek May 2, 2025
5993e06
Use a thread to manage interrupts on Windows
godlygeek May 2, 2025
dd7c9b1
Use the signal handling thread approach on all platforms
godlygeek May 4, 2025
e2391b0
Make all _connect arguments keyword-only
godlygeek May 4, 2025
edd7517
Merge remote-tracking branch 'upstream/main' into improve_remote_pdb_…
godlygeek May 4, 2025
14aa8e7
One line for contextlib imports
godlygeek May 4, 2025
b26ed5c
Add some tests for handling SIGINT in the PDB client
godlygeek May 4, 2025
a860087
Switch back to os.kill() on Unix
godlygeek May 4, 2025
e1bb1d3
Wrap input() calls in a function
godlygeek May 4, 2025
2a7807c
Merge branch 'main' into improve_remote_pdb_interrupt_handling
pablogsal May 5, 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 tests for handling SIGINT in the PDB client
  • Loading branch information
godlygeek committed May 4, 2025
commit b26ed5c039cb71422ffca70da91a4e2e051aa7ac
72 changes: 67 additions & 5 deletions 72 Lib/test/test_remote_pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ def do_test(
*,
incoming,
simulate_send_failure=False,
simulate_sigint_during_stdout_write=False,
expected_outgoing=None,
expected_outgoing_signals=None,
expected_completions=None,
expected_exception=None,
expected_stdout="",
Expand All @@ -96,6 +98,8 @@ def do_test(
):
if expected_outgoing is None:
expected_outgoing = []
if expected_outgoing_signals is None:
expected_outgoing_signals = []
if expected_completions is None:
expected_completions = []
if expected_state is None:
Expand Down Expand Up @@ -130,7 +134,9 @@ def mock_input(prompt):
reply = message["input"]
if isinstance(reply, BaseException):
raise reply
return reply
if isinstance(reply, str):
return reply
return reply()

with ExitStack() as stack:
client_sock, server_sock = socket.socketpair()
Expand All @@ -155,15 +161,25 @@ def mock_input(prompt):

stdout = io.StringIO()

if simulate_sigint_during_stdout_write:
orig_stdout_write = stdout.write

def sigint_stdout_write(s):
signal.raise_signal(signal.SIGINT)
return orig_stdout_write(s)

stdout.write = sigint_stdout_write

input_mock = stack.enter_context(
unittest.mock.patch("pdb.input", side_effect=mock_input)
)
stack.enter_context(redirect_stdout(stdout))

interrupt_sock = unittest.mock.Mock(spec=socket.socket)
client = _PdbClient(
pid=0,
server_socket=server_sock,
interrupt_sock=unittest.mock.Mock(spec=socket.socket),
interrupt_sock=interrupt_sock,
)

if expected_exception is not None:
Expand All @@ -188,6 +204,12 @@ def mock_input(prompt):
actual_state = {k: getattr(client, k) for k in expected_state}
self.assertEqual(actual_state, expected_state)

outgoing_signals = [
signal.Signals(int.from_bytes(call.args[0]))
for call in interrupt_sock.sendall.call_args_list
]
self.assertEqual(outgoing_signals, expected_outgoing_signals)

def test_remote_immediately_closing_the_connection(self):
"""Test the behavior when the remote closes the connection immediately."""
incoming = []
Expand Down Expand Up @@ -382,11 +404,17 @@ def test_handling_unrecognized_prompt_type(self):
expected_state={"state": "dumb"},
)

def test_keyboard_interrupt_at_prompt(self):
"""Test signaling when a prompt gets a KeyboardInterrupt."""
def test_sigint_at_prompt(self):
"""Test signaling when a prompt gets interrupted."""
incoming = [
("server", {"prompt": "(Pdb) ", "state": "pdb"}),
("user", {"prompt": "(Pdb) ", "input": KeyboardInterrupt()}),
(
"user",
{
"prompt": "(Pdb) ",
"input": lambda: signal.raise_signal(signal.SIGINT),
},
),
]
self.do_test(
incoming=incoming,
Expand All @@ -396,6 +424,40 @@ def test_keyboard_interrupt_at_prompt(self):
expected_state={"state": "pdb"},
)

def test_sigint_at_continuation_prompt(self):
"""Test signaling when a continuation prompt gets interrupted."""
incoming = [
("server", {"prompt": "(Pdb) ", "state": "pdb"}),
("user", {"prompt": "(Pdb) ", "input": "if True:"}),
(
"user",
{
"prompt": "... ",
"input": lambda: signal.raise_signal(signal.SIGINT),
},
),
]
self.do_test(
incoming=incoming,
expected_outgoing=[
{"signal": "INT"},
],
expected_state={"state": "pdb"},
)

def test_sigint_when_writing(self):
"""Test siginaling when sys.stdout.write() gets interrupted."""
incoming = [
("server", {"message": "Some message or other\n", "type": "info"}),
]
self.do_test(
incoming=incoming,
simulate_sigint_during_stdout_write=True,
expected_outgoing=[],
expected_outgoing_signals=[signal.SIGINT],
expected_stdout="Some message or other\n",
)

def test_eof_at_prompt(self):
"""Test signaling when a prompt gets an EOFError."""
incoming = [
Expand Down
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.