gh-132536: Do not disable PY_THROW event in bdb (#132537)

This commit is contained in:
Tian Gao 2025-04-15 15:31:52 -07:00 committed by GitHub
parent 4f10b93d1b
commit d19af00b90
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 44 additions and 12 deletions

View file

@ -58,7 +58,7 @@ class _MonitoringTracer:
E = sys.monitoring.events E = sys.monitoring.events
all_events = 0 all_events = 0
for event, cb_name in self.EVENT_CALLBACK_MAP.items(): for event, cb_name in self.EVENT_CALLBACK_MAP.items():
callback = getattr(self, f'{cb_name}_callback') callback = self.callback_wrapper(getattr(self, f'{cb_name}_callback'), event)
sys.monitoring.register_callback(self._tool_id, event, callback) sys.monitoring.register_callback(self._tool_id, event, callback)
if event != E.INSTRUCTION: if event != E.INSTRUCTION:
all_events |= event all_events |= event
@ -82,19 +82,22 @@ class _MonitoringTracer:
if sys.monitoring.get_tool(self._tool_id) == self._name: if sys.monitoring.get_tool(self._tool_id) == self._name:
sys.monitoring.restart_events() sys.monitoring.restart_events()
def callback_wrapper(func): def callback_wrapper(self, func, event):
import functools import functools
@functools.wraps(func) @functools.wraps(func)
def wrapper(self, *args): def wrapper(*args):
if self._tracing_thread != threading.current_thread(): if self._tracing_thread != threading.current_thread():
return return
try: try:
frame = sys._getframe().f_back frame = sys._getframe().f_back
ret = func(self, frame, *args) ret = func(frame, *args)
if self._enabled and frame.f_trace: if self._enabled and frame.f_trace:
self.update_local_events() self.update_local_events()
if self._disable_current_event: if (
self._disable_current_event
and event not in (E.PY_THROW, E.PY_UNWIND, E.RAISE)
):
return sys.monitoring.DISABLE return sys.monitoring.DISABLE
else: else:
return ret return ret
@ -107,7 +110,6 @@ class _MonitoringTracer:
return wrapper return wrapper
@callback_wrapper
def call_callback(self, frame, code, *args): def call_callback(self, frame, code, *args):
local_tracefunc = self._tracefunc(frame, 'call', None) local_tracefunc = self._tracefunc(frame, 'call', None)
if local_tracefunc is not None: if local_tracefunc is not None:
@ -115,22 +117,18 @@ class _MonitoringTracer:
if self._enabled: if self._enabled:
sys.monitoring.set_local_events(self._tool_id, code, self.LOCAL_EVENTS) sys.monitoring.set_local_events(self._tool_id, code, self.LOCAL_EVENTS)
@callback_wrapper
def return_callback(self, frame, code, offset, retval): def return_callback(self, frame, code, offset, retval):
if frame.f_trace: if frame.f_trace:
frame.f_trace(frame, 'return', retval) frame.f_trace(frame, 'return', retval)
@callback_wrapper
def unwind_callback(self, frame, code, *args): def unwind_callback(self, frame, code, *args):
if frame.f_trace: if frame.f_trace:
frame.f_trace(frame, 'return', None) frame.f_trace(frame, 'return', None)
@callback_wrapper
def line_callback(self, frame, code, *args): def line_callback(self, frame, code, *args):
if frame.f_trace and frame.f_trace_lines: if frame.f_trace and frame.f_trace_lines:
frame.f_trace(frame, 'line', None) frame.f_trace(frame, 'line', None)
@callback_wrapper
def jump_callback(self, frame, code, inst_offset, dest_offset): def jump_callback(self, frame, code, inst_offset, dest_offset):
if dest_offset > inst_offset: if dest_offset > inst_offset:
return sys.monitoring.DISABLE return sys.monitoring.DISABLE
@ -141,7 +139,6 @@ class _MonitoringTracer:
if frame.f_trace and frame.f_trace_lines: if frame.f_trace and frame.f_trace_lines:
frame.f_trace(frame, 'line', None) frame.f_trace(frame, 'line', None)
@callback_wrapper
def exception_callback(self, frame, code, offset, exc): def exception_callback(self, frame, code, offset, exc):
if frame.f_trace: if frame.f_trace:
if exc.__traceback__ and hasattr(exc.__traceback__, 'tb_frame'): if exc.__traceback__ and hasattr(exc.__traceback__, 'tb_frame'):
@ -152,7 +149,6 @@ class _MonitoringTracer:
tb = tb.tb_next tb = tb.tb_next
frame.f_trace(frame, 'exception', (type(exc), exc, exc.__traceback__)) frame.f_trace(frame, 'exception', (type(exc), exc, exc.__traceback__))
@callback_wrapper
def opcode_callback(self, frame, code, offset): def opcode_callback(self, frame, code, offset):
if frame.f_trace and frame.f_trace_opcodes: if frame.f_trace and frame.f_trace_opcodes:
frame.f_trace(frame, 'opcode', None) frame.f_trace(frame, 'opcode', None)

View file

@ -2581,6 +2581,41 @@ def test_pdb_next_command_subiterator():
(Pdb) continue (Pdb) continue
""" """
def test_pdb_breakpoint_with_throw():
"""GH-132536: PY_THROW event should not be turned off
>>> reset_Breakpoint()
>>> def gen():
... yield 0
>>> def test_function():
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
... g = gen()
... try:
... g.throw(TypeError)
... except TypeError:
... pass
>>> with PdbTestInput([
... 'b 7',
... 'continue',
... 'clear 1',
... 'continue',
... ]):
... test_function()
> <doctest test.test_pdb.test_pdb_breakpoint_with_throw[2]>(2)test_function()
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
(Pdb) b 7
Breakpoint 1 at <doctest test.test_pdb.test_pdb_breakpoint_with_throw[2]>:7
(Pdb) continue
> <doctest test.test_pdb.test_pdb_breakpoint_with_throw[2]>(7)test_function()
-> pass
(Pdb) clear 1
Deleted breakpoint 1 at <doctest test.test_pdb.test_pdb_breakpoint_with_throw[2]>:7
(Pdb) continue
"""
def test_pdb_multiline_statement(): def test_pdb_multiline_statement():
"""Test for multiline statement """Test for multiline statement

View file

@ -0,0 +1 @@
Do not disable :monitoring-event:`PY_THROW` event in :mod:`bdb` because it can't be disabled.