Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 9 additions & 3 deletions azure-pipelines/pipelines.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,9 @@ stages:
py313:
python.version: 3.13
py314:
python.version: 3.14.0-rc.2
python.version: 3.14
py315:
python.version: 3.15.0-rc.1

steps:

Expand Down Expand Up @@ -177,7 +179,9 @@ stages:
py313:
python.version: 3.13
py314:
python.version: 3.14.0-rc.2
python.version: 3.14
py315:
python.version: 3.15.0-rc.1

steps:

Expand Down Expand Up @@ -220,7 +224,9 @@ stages:
py313:
python.version: 3.13
py314:
python.version: 3.14.0-rc.2
python.version: 3.14
py315:
python.version: 3.15.0-rc.1

steps:

Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ def tail_is(*suffixes):
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3.15",
"Topic :: Software Development :: Debuggers",
"Operating System :: Microsoft :: Windows",
"Operating System :: MacOS",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,12 @@ def _get_unhandled_exception_frame(exc, depth: int) -> Optional[FrameType]:
except:
tag = exc

try:
if _thread_local_info.f_reported_unhandled_exc_tag is tag:
return None
except AttributeError:
pass

try:
if _thread_local_info.f_unhandled_exc_tag is tag:
return _thread_local_info.f_unhandled_frame
Expand Down Expand Up @@ -961,6 +967,9 @@ def _unwind_event(code, instruction, exc):
break_on_uncaught_exceptions = py_db.break_on_uncaught_exceptions
if break_on_uncaught_exceptions:
if frame is _get_unhandled_exception_frame(exc, 1):
_thread_local_info.f_reported_unhandled_exc_tag = _thread_local_info.f_unhandled_exc_tag
del _thread_local_info.f_unhandled_exc_tag
del _thread_local_info.f_unhandled_frame
stop_on_unhandled_exception(py_db, thread_info.thread, thread_info.additional_info, arg)
return

Expand Down
6,399 changes: 3,278 additions & 3,121 deletions src/debugpy/_vendored/pydevd/_pydevd_sys_monitoring/_pydevd_sys_monitoring_cython.c

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,12 @@ cdef _get_unhandled_exception_frame(exc, int depth):
except:
tag = exc

try:
if _thread_local_info.f_reported_unhandled_exc_tag is tag:
return None
except AttributeError:
pass

try:
if _thread_local_info.f_unhandled_exc_tag is tag:
return _thread_local_info.f_unhandled_frame
Expand Down Expand Up @@ -953,6 +959,9 @@ cdef _unwind_event(code, instruction, exc):
break_on_uncaught_exceptions = py_db.break_on_uncaught_exceptions
if break_on_uncaught_exceptions:
if frame is _get_unhandled_exception_frame(exc, 1):
_thread_local_info.f_reported_unhandled_exc_tag = _thread_local_info.f_unhandled_exc_tag
del _thread_local_info.f_unhandled_exc_tag
del _thread_local_info.f_unhandled_frame
stop_on_unhandled_exception(py_db, thread_info.thread, thread_info.additional_info, arg)
return

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ enum PythonVersion {
PythonVersion_312 = 0x030C,
PythonVersion_313 = 0x030D,
PythonVersion_314 = 0x030E,
PythonVersion_315 = 0x030F,
};


Expand Down Expand Up @@ -82,6 +83,9 @@ static PythonVersion GetPythonVersion(void *module) {
if(version[3] == '4'){
return PythonVersion_314;
}
if(version[3] == '5'){
return PythonVersion_315;
}
}
return PythonVersion_Unknown; // we don't care about 3.1 anymore...

Expand All @@ -99,4 +103,4 @@ static PythonVersion GetPythonVersion(void *module) {
return PythonVersion_Unknown;
}

#endif
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,49 @@ def method():
]


def test_nested_exception_does_not_reset_reported_unhandled_exception():
from _pydevd_sys_monitoring import _pydevd_sys_monitoring

thread_local_info = _pydevd_sys_monitoring._thread_local_info
state_names = (
"f_unhandled_exc_tag",
"f_unhandled_frame",
"f_reported_unhandled_exc_tag",
)

for name in state_names:
if hasattr(thread_local_info, name):
delattr(thread_local_info, name)

try:
unhandled_exception = SystemExit(1)
nested_exception = AttributeError("nested")

_pydevd_sys_monitoring._get_unhandled_exception_frame(
unhandled_exception, 1
)
thread_local_info.f_reported_unhandled_exc_tag = (
thread_local_info.f_unhandled_exc_tag
)
del thread_local_info.f_unhandled_exc_tag
del thread_local_info.f_unhandled_frame

_pydevd_sys_monitoring._get_unhandled_exception_frame(
nested_exception, 1
)

assert (
_pydevd_sys_monitoring._get_unhandled_exception_frame(
unhandled_exception, 1
)
is None
)
finally:
for name in state_names:
if hasattr(thread_local_info, name):
delattr(thread_local_info, name)


def test_variables_on_call(with_monitoring):
monitor.set_events(DEBUGGER_ID, monitor.events.PY_START)

Expand Down
9 changes: 9 additions & 0 deletions tests/debugpy/test_multiproc.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ def code_to_debug():
import multiprocessing
import os
import sys
import warnings

# https://github.com/microsoft/ptvsd/issues/2108
class Foo(object):
Expand Down Expand Up @@ -111,6 +112,14 @@ def grandchild(q, a):

if __name__ == "__main__":
start_method = sys.argv[1]
if start_method == "fork":
# This test intentionally forks with debugpy threads running.
# https://github.com/python/cpython/issues/135427
warnings.filterwarnings(
"ignore",
message=r".*use of fork\(\) may lead to deadlocks in the child\.",
category=DeprecationWarning,
)
if start_method != "":
multiprocessing.set_start_method(start_method)

Expand Down
6 changes: 3 additions & 3 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[tox]
envlist = py{310,311,312,313,314}{,-cov}
envlist = py{310,311,312,313,314,315}{,-cov}

[testenv]
deps = -rtests/requirements.txt
Expand All @@ -8,5 +8,5 @@ setenv =
DEBUGPY_TEST=1
commands_pre = python build_attach_binaries.py
commands =
py{310,311,312,313,314}-!cov: python -Xfrozen_modules=off -m pytest {posargs}
py{310,311,312,313,314}-cov: python -Xfrozen_modules=off -m pytest --cov --cov-append --cov-config=.coveragerc {posargs}
py{310,311,312,313,314,315}-!cov: python -Xfrozen_modules=off -m pytest {posargs}
py{310,311,312,313,314,315}-cov: python -Xfrozen_modules=off -m pytest --cov --cov-append --cov-config=.coveragerc {posargs}
Loading