PyDev.Debugger
PyDev.Debugger copied to clipboard
Breakpoints not respected when invoked using debugpy
Environment data
~ [ python3.9 -m debugpy --version ] 10:11 AM
Unable to load extension: pydevd_plugins.extensions.types.pydevd_plugin_pandas_types
1.5.1
~ [ python3.9 --version ] 10:11 AM
Python 3.9.12
~ [ uname -a ] 10:12 AM
Linux fedora 6.2.8-100.fc36.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Mar 22 19:14:19 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
~ [ emacs --version ] 10:12 AM
emacsclient 28.2
Using dap-mode with the following template:
(dap-register-debug-template
"Python :: Run file (buffer)"
(list :type "python"
:args ""
:cwd nil
:module nil
:program nil
:request "launch"
:name "Python :: Run file (buffer)"))
My python test script is defined as such (with breakpoint at line 10).
#!/usr/bin/env python3
from datetime import datetime
if __name__ == "__main__":
now = datetime.now()
now_str = now.strftime("%d-%m-%Y_%H-%M-%S")
print("Starting test script")
for i in range(10):
print(f"Printing {i} {now_str}")
print("Completed Start script")
Actual behavior
Debugger does not stop at the desired breakpoint, instead runs application until completion with the following error/output:
Unable to load extension: pydevd_plugins.extensions.types.pydevd_plugin_pandas_types
Starting test script
Traceback (most recent call last):
File "/home/reggiemarr/anaconda3/lib/python3.9/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_comm.py", line 267, in _on_run
self.process_net_command_json(self.py_db, json_contents)
File "/home/reggiemarr/anaconda3/lib/python3.9/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_process_net_command_json.py", line 193, in process_net_command_json
cmd = on_request(py_db, request)
File "/home/reggiemarr/anaconda3/lib/python3.9/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_process_net_command_json.py", line 926, in on_stacktrace_request
self.api.request_stack(py_db, request.seq, thread_id, fmt=fmt, start_frame=start_frame, levels=levels)
File "/home/reggiemarr/anaconda3/lib/python3.9/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_api.py", line 202, in request_stack
if internal_get_thread_stack.can_be_executed_by(get_current_thread_id(threading.current_thread())):
File "/home/reggiemarr/anaconda3/lib/python3.9/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_comm.py", line 672, in can_be_executed_by
self._cmd = py_db.cmd_factory.make_get_thread_stack_message(
File "/home/reggiemarr/anaconda3/lib/python3.9/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_net_command_factory_json.py", line 275, in make_get_thread_stack_message
end = min(start + levels, total_frames)
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
Printing 0 06-04-2023_09-59-42
Printing 1 06-04-2023_09-59-42
Printing 2 06-04-2023_09-59-42
Printing 3 06-04-2023_09-59-42
Printing 4 06-04-2023_09-59-42
Printing 5 06-04-2023_09-59-42
Printing 6 06-04-2023_09-59-42
Printing 7 06-04-2023_09-59-42
Printing 8 06-04-2023_09-59-42
Printing 9 06-04-2023_09-59-42
Completed Start script
Expected behavior
Run without error/stop at breakpoints (for example this stops at each iteration and was run until 3 occurred:
Unable to load extension: pydevd_plugins.extensions.types.pydevd_plugin_pandas_types
Starting test script
Printing 0 06-04-2023_09-56-37
Printing 1 06-04-2023_09-56-37
Printing 2 06-04-2023_09-56-37
Printing 3 06-04-2023_09-56-37
Steps to reproduce:
Create breakpoint at line 10, run debugger using dap mode/similar application.
Solution:
I managed to figure out what the problem is. For some reason when running the test program the start_frame is None. I found I was able to fix this with the following change to pydevd::pydevd_net_command_factory_json.py
@overrides(NetCommandFactory.make_get_thread_stack_message)
def make_get_thread_stack_message(self, py_db, seq, thread_id, topmost_frame, fmt, must_be_suspended=False, start_frame=0, levels=0):
frames = []
module_events = []
try:
# : :type suspended_frames_manager: SuspendedFramesManager
suspended_frames_manager = py_db.suspended_frames_manager
frames_list = suspended_frames_manager.get_frames_list(thread_id)
if frames_list is None:
# Could not find stack of suspended frame...
if must_be_suspended:
return None
else:
frames_list = pydevd_frame_utils.create_frames_list_from_frame(topmost_frame)
for frame_id, frame, method_name, original_filename, filename_in_utf8, lineno, applied_mapping, show_as_current_frame in self._iter_visible_frames_info(
py_db, frames_list
):
try:
module_name = str(frame.f_globals.get('__name__', ''))
except:
module_name = '<unknown>'
module_events.extend(self.modules_manager.track_module(filename_in_utf8, module_name, frame))
presentation_hint = None
if not getattr(frame, 'IS_PLUGIN_FRAME', False): # Never filter out plugin frames!
if py_db.is_files_filter_enabled and py_db.apply_files_filter(frame, original_filename, False):
continue
if not py_db.in_project_scope(frame):
presentation_hint = 'subtle'
formatted_name = self._format_frame_name(fmt, method_name, module_name, lineno, filename_in_utf8)
if show_as_current_frame:
formatted_name += ' (Current frame)'
source_reference = pydevd_file_utils.get_client_filename_source_reference(filename_in_utf8)
if not source_reference and not applied_mapping and not os.path.exists(original_filename):
if getattr(frame.f_code, 'co_lnotab', None):
# Create a source-reference to be used where we provide the source by decompiling the code.
# Note: When the time comes to retrieve the source reference in this case, we'll
# check the linecache first (see: get_decompiled_source_from_frame_id).
source_reference = pydevd_file_utils.create_source_reference_for_frame_id(frame_id, original_filename)
else:
# Check if someone added a source reference to the linecache (Python attrs does this).
if linecache.getline(original_filename, 1):
source_reference = pydevd_file_utils.create_source_reference_for_linecache(
original_filename)
frames.append(pydevd_schema.StackFrame(
frame_id, formatted_name, lineno, column=1, source={
'path': filename_in_utf8,
'sourceReference': source_reference,
},
presentationHint=presentation_hint).to_dict())
finally:
topmost_frame = None
for module_event in module_events:
py_db.writer.add_command(module_event)
total_frames = len(frames)
stack_frames = frames
if bool(levels):
start = start_frame
# This is my fix
if start is None:
start = 0
print("start:", start, "total_frames:", total_frames, " + levels:", levels)
end = min(start + levels, total_frames)
stack_frames = frames[start:end]
response = pydevd_schema.StackTraceResponse(
request_seq=seq,
success=True,
command='stackTrace',
body=pydevd_schema.StackTraceResponseBody(stackFrames=stack_frames, totalFrames=total_frames))
return NetCommand(CMD_RETURN, 0, response, is_json=True)
Note I've also made an issue in the debugpy repo here