Skip to content

Commit 9c83026

Browse files
Address comments and add a test
1 parent 13d77ad commit 9c83026

File tree

2 files changed

+29
-14
lines changed

2 files changed

+29
-14
lines changed

Lib/pdb.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -710,25 +710,22 @@ def _get_asyncio_task(self):
710710
return task
711711

712712
def _get_pid_from_process(self, process):
713-
"""process could be a subprocess.Popen, multiprocessing.Process or a pid
713+
"""process could evaluate to any object with a `process` attribute or an integer
714714
"""
715-
# They are not used elsewhere so do a lazy import
716-
from multiprocessing import Process
717-
from subprocess import Popen
718715

719716
try:
720717
process = self._getval(process)
721718
except:
722719
# Error message is already displayed
723720
return None
724721

725-
if isinstance(process, (Process, Popen)):
726-
return process.pid
727-
elif isinstance(process, int):
728-
return process
722+
pid = getattr(process, "pid", process)
729723

730-
self.error(f"Invalid process {process}")
731-
return None
724+
if not isinstance(pid, int):
725+
self.error(f"Invalid process {process!r}")
726+
return None
727+
728+
return pid
732729

733730
def interaction(self, frame, tb_or_exc):
734731
# Restore the previous signal handler at the Pdb prompt.
@@ -1982,13 +1979,13 @@ def do_debug(self, arg):
19821979

19831980
complete_debug = _complete_expression
19841981

1985-
def do_attach(self, process):
1982+
def do_attach(self, arg):
19861983
"""attach process
19871984
1988-
Attach to process, which can be a subprocess.Popen,
1989-
multiprocessing.Process or a pid.
1985+
Attach to process, which can be any object that has a pid
1986+
attribute or a process ID.
19901987
"""
1991-
pid = self._get_pid_from_process(process)
1988+
pid = self._get_pid_from_process(arg)
19921989

19931990
if pid is not None:
19941991
self.message(f"Attaching to process {pid}")
@@ -2780,6 +2777,7 @@ def _ensure_valid_message(self, msg):
27802777
# needs to know it for multi-line editing.
27812778
pass
27822779
case {"attach": int()}:
2780+
# Ask the client to attach to the given process ID.
27832781
pass
27842782
case _:
27852783
raise AssertionError(
@@ -3441,6 +3439,12 @@ def _connect(
34413439

34423440
def attach(pid, commands=()):
34433441
"""Attach to a running process with the given PID."""
3442+
3443+
if threading.current_thread() is not threading.main_thread():
3444+
raise RuntimeError(
3445+
"pdb.attach() must be called from the main thread"
3446+
)
3447+
34443448
with ExitStack() as stack:
34453449
server = stack.enter_context(
34463450
closing(socket.create_server(("localhost", 0)))

Lib/test/test_remote_pdb.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1600,6 +1600,17 @@ def test_attach_to_process_with_colors(self):
16001600
self.assertNotIn("while x == 1", output["client"]["stdout"])
16011601
self.assertIn("while x == 1", re.sub("\x1b[^m]*m", "", output["client"]["stdout"]))
16021602

1603+
def test_attach_from_worker_thread(self):
1604+
# Test attaching from a worker thread
1605+
def worker():
1606+
with self.assertRaises(RuntimeError):
1607+
# We are not allowed to attach from a thread that's not main
1608+
pdb.attach(1234)
1609+
1610+
thread = threading.Thread(target=worker)
1611+
thread.start()
1612+
thread.join()
1613+
16031614

16041615
@unittest.skipIf(not sys.is_remote_debug_enabled(), "Remote debugging is not enabled")
16051616
@unittest.skipIf(sys.platform != "darwin" and sys.platform != "linux" and sys.platform != "win32",

0 commit comments

Comments
 (0)