mirror of
https://github.com/microsoft/debugpy.git
synced 2025-12-23 08:48:12 +00:00
Get Python 3.13 to work (#1692)
* Get debug launch working * Turn Cython support back on * Fix test failures * Fix gevent test to be skipped * Missed a version change in pipeline * Fix comment * Review feedback
This commit is contained in:
parent
25955a05d8
commit
f7d5df027c
14 changed files with 7133 additions and 6877 deletions
|
|
@ -65,6 +65,8 @@ jobs:
|
|||
python.version: "3.11"
|
||||
py312:
|
||||
python.version: "3.12"
|
||||
py313:
|
||||
python.version: "3.13"
|
||||
|
||||
steps:
|
||||
|
||||
|
|
@ -93,6 +95,8 @@ jobs:
|
|||
python.version: "3.11"
|
||||
py312:
|
||||
python.version: "3.12"
|
||||
py313:
|
||||
python.version: "3.13"
|
||||
|
||||
steps:
|
||||
|
||||
|
|
@ -124,6 +128,8 @@ jobs:
|
|||
python.version: "3.11"
|
||||
py312:
|
||||
python.version: "3.12"
|
||||
py313:
|
||||
python.version: "3.13"
|
||||
|
||||
steps:
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from _pydev_bundle._pydev_saved_modules import threading
|
|||
# circumstances).
|
||||
# It is required to debug threads started by start_new_thread in Python 3.4
|
||||
_temp = threading.Thread()
|
||||
if hasattr(_temp, "_is_stopped"): # Python 3.x has this
|
||||
if hasattr(_temp, "_is_stopped"): # Python 3.12 and earlier has this
|
||||
|
||||
def is_thread_alive(t):
|
||||
return not t._is_stopped
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ from _pydevd_bundle.pydevd_constants import (
|
|||
)
|
||||
from _pydev_bundle import pydev_log
|
||||
from _pydev_bundle._pydev_saved_modules import threading
|
||||
from _pydev_bundle.pydev_is_thread_alive import is_thread_alive
|
||||
import weakref
|
||||
|
||||
version = 11
|
||||
|
|
@ -135,7 +136,7 @@ class PyDBAdditionalThreadInfo(object):
|
|||
if thread is None:
|
||||
return False
|
||||
|
||||
if thread._is_stopped:
|
||||
if not is_thread_alive(thread):
|
||||
return None
|
||||
|
||||
if thread._ident is None: # Can this happen?
|
||||
|
|
|
|||
|
|
@ -173,9 +173,11 @@ IS_PY39_OR_GREATER = sys.version_info >= (3, 9)
|
|||
IS_PY310_OR_GREATER = sys.version_info >= (3, 10)
|
||||
IS_PY311_OR_GREATER = sys.version_info >= (3, 11)
|
||||
IS_PY312_OR_GREATER = sys.version_info >= (3, 12)
|
||||
IS_PY313_OR_GREATER = sys.version_info >= (3, 13)
|
||||
IS_PY314_OR_GREATER = sys.version_info >= (3, 14)
|
||||
|
||||
# Not currently supported in Python 3.12.
|
||||
SUPPORT_ATTACH_TO_PID = not IS_PY312_OR_GREATER
|
||||
# Not currently supported in Python 3.14.
|
||||
SUPPORT_ATTACH_TO_PID = not IS_PY314_OR_GREATER
|
||||
|
||||
|
||||
def version_str(v):
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -16,6 +16,7 @@ from _pydevd_bundle.pydevd_constants import (
|
|||
)
|
||||
from _pydev_bundle import pydev_log
|
||||
from _pydev_bundle._pydev_saved_modules import threading
|
||||
from _pydev_bundle.pydev_is_thread_alive import is_thread_alive
|
||||
import weakref
|
||||
|
||||
version = 11
|
||||
|
|
@ -141,7 +142,7 @@ cdef class PyDBAdditionalThreadInfo:
|
|||
if thread is None:
|
||||
return False
|
||||
|
||||
if thread._is_stopped:
|
||||
if not is_thread_alive(thread):
|
||||
return None
|
||||
|
||||
if thread._ident is None: # Can this happen?
|
||||
|
|
|
|||
|
|
@ -35,7 +35,12 @@ def add_exception_to_frame(frame, exception_info):
|
|||
|
||||
|
||||
def remove_exception_from_frame(frame):
|
||||
frame.f_locals.pop("__exception__", None)
|
||||
# In 3.13 frame.f_locals became a proxy for a dict, so we need to copy it to a real dict
|
||||
# so we can call the defined update method. Just deleting the entry throws in 3.13.
|
||||
items = {key: value for key, value in frame.f_locals.items()}
|
||||
if "__exception__" in items:
|
||||
del items["__exception__"]
|
||||
frame.f_locals.update(items)
|
||||
|
||||
|
||||
FILES_WITH_IMPORT_HOOKS = ["pydev_monkey_qt.py", "pydev_import_hook.py"]
|
||||
|
|
@ -140,6 +145,7 @@ _utf8_with_4_bytes = 0x10000
|
|||
def _utf8_byte_offset_to_character_offset(s: str, offset: int):
|
||||
byte_offset = 0
|
||||
char_offset = 0
|
||||
offset = offset or 0
|
||||
|
||||
for char_offset, character in enumerate(s):
|
||||
byte_offset += 1
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ from typing import Dict, Optional, Tuple, Any
|
|||
from os.path import basename, splitext
|
||||
|
||||
from _pydev_bundle import pydev_log
|
||||
from _pydev_bundle.pydev_is_thread_alive import is_thread_alive
|
||||
from _pydevd_bundle import pydevd_dont_trace
|
||||
from _pydevd_bundle.pydevd_constants import (
|
||||
GlobalDebuggerHolder,
|
||||
|
|
@ -459,9 +460,10 @@ def _get_code_line_info(code_obj, _cache={}):
|
|||
last_line = None
|
||||
|
||||
for offset, line in dis.findlinestarts(code_obj):
|
||||
line_to_offset[line] = offset
|
||||
if offset is not None and line is not None:
|
||||
line_to_offset[line] = offset
|
||||
|
||||
if line_to_offset:
|
||||
if len(line_to_offset):
|
||||
first_line = min(line_to_offset)
|
||||
last_line = max(line_to_offset)
|
||||
ret = _CodeLineInfo(line_to_offset, first_line, last_line)
|
||||
|
|
@ -837,7 +839,7 @@ def _unwind_event(code, instruction, exc):
|
|||
if py_db is None or py_db.pydb_disposed:
|
||||
return
|
||||
|
||||
if not thread_info.trace or thread_info.thread._is_stopped:
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
|
@ -911,7 +913,7 @@ def _raise_event(code, instruction, exc):
|
|||
if py_db is None or py_db.pydb_disposed:
|
||||
return
|
||||
|
||||
if not thread_info.trace or thread_info.thread._is_stopped:
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
|
@ -1029,7 +1031,7 @@ def _return_event(code, instruction, retval):
|
|||
if py_db is None or py_db.pydb_disposed:
|
||||
return monitor.DISABLE
|
||||
|
||||
if not thread_info.trace or thread_info.thread._is_stopped:
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
|
@ -1340,7 +1342,7 @@ def _jump_event(code, from_offset, to_offset):
|
|||
if py_db is None or py_db.pydb_disposed:
|
||||
return monitor.DISABLE
|
||||
|
||||
if not thread_info.trace or thread_info.thread._is_stopped:
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
|
@ -1397,7 +1399,7 @@ def _line_event(code, line):
|
|||
if py_db is None or py_db.pydb_disposed:
|
||||
return monitor.DISABLE
|
||||
|
||||
if not thread_info.trace or thread_info.thread._is_stopped:
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
|
@ -1644,7 +1646,7 @@ def _start_method_event(code, instruction_offset):
|
|||
if py_db is None or py_db.pydb_disposed:
|
||||
return monitor.DISABLE
|
||||
|
||||
if not thread_info.trace or thread_info.thread._is_stopped:
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -13,13 +13,13 @@ import dis
|
|||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
from _pydev_bundle._pydev_saved_modules import threading
|
||||
from types import CodeType, FrameType
|
||||
from typing import Dict, Optional, Tuple, Any
|
||||
from os.path import basename, splitext
|
||||
|
||||
from _pydev_bundle import pydev_log
|
||||
from _pydev_bundle.pydev_is_thread_alive import is_thread_alive
|
||||
from _pydevd_bundle import pydevd_dont_trace
|
||||
from _pydevd_bundle.pydevd_constants import (
|
||||
GlobalDebuggerHolder,
|
||||
|
|
@ -466,9 +466,10 @@ cdef _get_code_line_info(code_obj, _cache={}):
|
|||
last_line = None
|
||||
|
||||
for offset, line in dis.findlinestarts(code_obj):
|
||||
line_to_offset[line] = offset
|
||||
if offset is not None and line is not None:
|
||||
line_to_offset[line] = offset
|
||||
|
||||
if line_to_offset:
|
||||
if len(line_to_offset):
|
||||
first_line = min(line_to_offset)
|
||||
last_line = max(line_to_offset)
|
||||
ret = _CodeLineInfo(line_to_offset, first_line, last_line)
|
||||
|
|
@ -844,7 +845,7 @@ cdef _unwind_event(code, instruction, exc):
|
|||
if py_db is None or py_db.pydb_disposed:
|
||||
return
|
||||
|
||||
if not thread_info.trace or thread_info.thread._is_stopped:
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
|
@ -918,7 +919,7 @@ cdef _raise_event(code, instruction, exc):
|
|||
if py_db is None or py_db.pydb_disposed:
|
||||
return
|
||||
|
||||
if not thread_info.trace or thread_info.thread._is_stopped:
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
|
@ -1036,7 +1037,7 @@ cdef _return_event(code, instruction, retval):
|
|||
if py_db is None or py_db.pydb_disposed:
|
||||
return monitor.DISABLE
|
||||
|
||||
if not thread_info.trace or thread_info.thread._is_stopped:
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
|
@ -1347,7 +1348,7 @@ cdef _jump_event(code, int from_offset, int to_offset):
|
|||
if py_db is None or py_db.pydb_disposed:
|
||||
return monitor.DISABLE
|
||||
|
||||
if not thread_info.trace or thread_info.thread._is_stopped:
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
|
@ -1404,7 +1405,7 @@ cdef _line_event(code, int line):
|
|||
if py_db is None or py_db.pydb_disposed:
|
||||
return monitor.DISABLE
|
||||
|
||||
if not thread_info.trace or thread_info.thread._is_stopped:
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
|
@ -1651,7 +1652,7 @@ cdef _start_method_event(code, instruction_offset):
|
|||
if py_db is None or py_db.pydb_disposed:
|
||||
return monitor.DISABLE
|
||||
|
||||
if not thread_info.trace or thread_info.thread._is_stopped:
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ PYDEVD_TEST_VM = os.getenv("PYDEVD_TEST_VM", None)
|
|||
|
||||
IS_PY36_OR_GREATER = sys.version_info[0:2] >= (3, 6)
|
||||
IS_PY311_OR_GREATER = sys.version_info[0:2] >= (3, 11)
|
||||
IS_PY313_OR_GREATER = sys.version_info[0:2] >= (3, 13)
|
||||
IS_PY311 = sys.version_info[0:2] == (3, 11)
|
||||
IS_PY312 = sys.version_info[0:2] == (3, 12)
|
||||
IS_CPYTHON = platform.python_implementation() == "CPython"
|
||||
|
|
|
|||
|
|
@ -353,9 +353,9 @@ def test_exception_stack(pyfile, target, run, max_frames):
|
|||
session.expected_exit_code = some.int
|
||||
|
||||
max_frames, (min_expected_lines, max_expected_lines) = {
|
||||
"all": (0, (100, 221)),
|
||||
"default": (None, (100, 221)),
|
||||
10: (10, (10, 22)),
|
||||
"all": (0, (100, 308)),
|
||||
"default": (None, (100, 308)),
|
||||
10: (10, (10, 32)),
|
||||
}[max_frames]
|
||||
if max_frames is not None:
|
||||
session.config["maxExceptionStackFrames"] = max_frames
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@
|
|||
# Licensed under the MIT License. See LICENSE in the project root
|
||||
# for license information.
|
||||
|
||||
import pytest
|
||||
from tests import debug
|
||||
from tests.patterns import some
|
||||
from _pydevd_bundle.pydevd_constants import IS_PY313_OR_GREATER
|
||||
|
||||
|
||||
@pytest.mark.skipif(IS_PY313_OR_GREATER, reason="gevent is not up to date with 3.13 (_tstate_lock is not part of thread anymore)")
|
||||
def test_gevent(pyfile, target, run):
|
||||
@pyfile
|
||||
def code_to_debug():
|
||||
|
|
|
|||
6
tox.ini
6
tox.ini
|
|
@ -1,5 +1,5 @@
|
|||
[tox]
|
||||
envlist = py{38,39,310,311,312}{,-cov}
|
||||
envlist = py{38,39,310,311,312,313}{,-cov}
|
||||
|
||||
[testenv]
|
||||
deps = -rtests/requirements.txt
|
||||
|
|
@ -9,5 +9,5 @@ setenv =
|
|||
commands =
|
||||
py{38,39}-!cov: python -m pytest {posargs}
|
||||
py{38,39}-cov: python -m pytest --cov --cov-append --cov-config=.coveragerc {posargs}
|
||||
py{310,311,312}-!cov: python -Xfrozen_modules=off -m pytest {posargs}
|
||||
py{310,311,312}-cov: python -Xfrozen_modules=off -m pytest --cov --cov-append --cov-config=.coveragerc {posargs}
|
||||
py{310,311,312,313}-!cov: python -Xfrozen_modules=off -m pytest {posargs}
|
||||
py{310,311,312,313}-cov: python -Xfrozen_modules=off -m pytest --cov --cov-append --cov-config=.coveragerc {posargs}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue