mirror of
https://github.com/microsoft/debugpy.git
synced 2025-12-23 08:48:12 +00:00
Use code object instead of (co_firstlineno, co_name, co_filename) for caching frame info. Fixes #837 Fixes #844
This commit is contained in:
parent
1b8d5ab0be
commit
6134532263
7 changed files with 423 additions and 432 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -677,7 +677,7 @@ cdef class PyDBFrame:
|
|||
cdef str curr_func_name;
|
||||
cdef bint exist_result;
|
||||
cdef dict frame_skips_cache;
|
||||
cdef tuple frame_cache_key;
|
||||
cdef object frame_cache_key;
|
||||
cdef tuple line_cache_key;
|
||||
cdef int breakpoints_in_line_cache;
|
||||
cdef int breakpoints_in_frame_cache;
|
||||
|
|
@ -1640,7 +1640,7 @@ cdef class ThreadTracer:
|
|||
cdef str filename;
|
||||
cdef str base;
|
||||
cdef int pydev_step_cmd;
|
||||
cdef tuple frame_cache_key;
|
||||
cdef object frame_cache_key;
|
||||
cdef dict cache_skips;
|
||||
cdef bint is_stepping;
|
||||
cdef tuple abs_path_canonical_path_and_base;
|
||||
|
|
@ -1667,7 +1667,7 @@ cdef class ThreadTracer:
|
|||
|
||||
# Note: it's important that the context name is also given because we may hit something once
|
||||
# in the global context and another in the local context.
|
||||
frame_cache_key = (frame.f_code.co_firstlineno, frame.f_code.co_name, frame.f_code.co_filename)
|
||||
frame_cache_key = frame.f_code
|
||||
if frame_cache_key in cache_skips:
|
||||
if not is_stepping:
|
||||
# if DEBUG: print('skipped: trace_dispatch (cache hit)', frame_cache_key, frame.f_lineno, event, frame.f_code.co_name)
|
||||
|
|
@ -1681,7 +1681,7 @@ cdef class ThreadTracer:
|
|||
|
||||
back_frame = frame.f_back
|
||||
if back_frame is not None and pydev_step_cmd in (107, 144, 109, 160):
|
||||
back_frame_cache_key = (back_frame.f_code.co_firstlineno, back_frame.f_code.co_name, back_frame.f_code.co_filename)
|
||||
back_frame_cache_key = back_frame.f_code
|
||||
if cache_skips.get(back_frame_cache_key) == 1:
|
||||
# if DEBUG: print('skipped: trace_dispatch (cache hit: 1)', frame_cache_key, frame.f_lineno, event, frame.f_code.co_name)
|
||||
return None if event == 'call' else NO_FTRACE
|
||||
|
|
@ -1721,7 +1721,7 @@ cdef class ThreadTracer:
|
|||
back_frame = frame.f_back
|
||||
if back_frame is not None and pydev_step_cmd in (107, 144, 109, 160):
|
||||
if py_db.apply_files_filter(back_frame, back_frame.f_code.co_filename, False):
|
||||
back_frame_cache_key = (back_frame.f_code.co_firstlineno, back_frame.f_code.co_name, back_frame.f_code.co_filename)
|
||||
back_frame_cache_key = back_frame.f_code
|
||||
cache_skips[back_frame_cache_key] = 1
|
||||
# if DEBUG: print('skipped: trace_dispatch (filtered out: 1)', frame_cache_key, frame.f_lineno, event, frame.f_code.co_name)
|
||||
return None if event == 'call' else NO_FTRACE
|
||||
|
|
|
|||
|
|
@ -544,7 +544,7 @@ class PyDBFrame:
|
|||
# cdef str curr_func_name;
|
||||
# cdef bint exist_result;
|
||||
# cdef dict frame_skips_cache;
|
||||
# cdef tuple frame_cache_key;
|
||||
# cdef object frame_cache_key;
|
||||
# cdef tuple line_cache_key;
|
||||
# cdef int breakpoints_in_line_cache;
|
||||
# cdef int breakpoints_in_frame_cache;
|
||||
|
|
|
|||
|
|
@ -340,7 +340,7 @@ class ThreadTracer(object):
|
|||
# cdef str filename;
|
||||
# cdef str base;
|
||||
# cdef int pydev_step_cmd;
|
||||
# cdef tuple frame_cache_key;
|
||||
# cdef object frame_cache_key;
|
||||
# cdef dict cache_skips;
|
||||
# cdef bint is_stepping;
|
||||
# cdef tuple abs_path_canonical_path_and_base;
|
||||
|
|
@ -367,7 +367,7 @@ class ThreadTracer(object):
|
|||
|
||||
# Note: it's important that the context name is also given because we may hit something once
|
||||
# in the global context and another in the local context.
|
||||
frame_cache_key = (frame.f_code.co_firstlineno, frame.f_code.co_name, frame.f_code.co_filename)
|
||||
frame_cache_key = frame.f_code
|
||||
if frame_cache_key in cache_skips:
|
||||
if not is_stepping:
|
||||
# if DEBUG: print('skipped: trace_dispatch (cache hit)', frame_cache_key, frame.f_lineno, event, frame.f_code.co_name)
|
||||
|
|
@ -381,7 +381,7 @@ class ThreadTracer(object):
|
|||
|
||||
back_frame = frame.f_back
|
||||
if back_frame is not None and pydev_step_cmd in (CMD_STEP_INTO, CMD_STEP_INTO_MY_CODE, CMD_STEP_RETURN, CMD_STEP_RETURN_MY_CODE):
|
||||
back_frame_cache_key = (back_frame.f_code.co_firstlineno, back_frame.f_code.co_name, back_frame.f_code.co_filename)
|
||||
back_frame_cache_key = back_frame.f_code
|
||||
if cache_skips.get(back_frame_cache_key) == 1:
|
||||
# if DEBUG: print('skipped: trace_dispatch (cache hit: 1)', frame_cache_key, frame.f_lineno, event, frame.f_code.co_name)
|
||||
return None if event == 'call' else NO_FTRACE
|
||||
|
|
@ -421,7 +421,7 @@ class ThreadTracer(object):
|
|||
back_frame = frame.f_back
|
||||
if back_frame is not None and pydev_step_cmd in (CMD_STEP_INTO, CMD_STEP_INTO_MY_CODE, CMD_STEP_RETURN, CMD_STEP_RETURN_MY_CODE):
|
||||
if py_db.apply_files_filter(back_frame, back_frame.f_code.co_filename, False):
|
||||
back_frame_cache_key = (back_frame.f_code.co_firstlineno, back_frame.f_code.co_name, back_frame.f_code.co_filename)
|
||||
back_frame_cache_key = back_frame.f_code
|
||||
cache_skips[back_frame_cache_key] = 1
|
||||
# if DEBUG: print('skipped: trace_dispatch (filtered out: 1)', frame_cache_key, frame.f_lineno, event, frame.f_code.co_name)
|
||||
return None if event == 'call' else NO_FTRACE
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Generated by Cython 0.29.26 */
|
||||
/* Generated by Cython 0.29.28 */
|
||||
|
||||
/* BEGIN: Cython Metadata
|
||||
{
|
||||
|
|
@ -32,8 +32,8 @@ END: Cython Metadata */
|
|||
#elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000)
|
||||
#error Cython requires Python 2.6+ or Python 3.3+.
|
||||
#else
|
||||
#define CYTHON_ABI "0_29_26"
|
||||
#define CYTHON_HEX_VERSION 0x001D1AF0
|
||||
#define CYTHON_ABI "0_29_28"
|
||||
#define CYTHON_HEX_VERSION 0x001D1CF0
|
||||
#define CYTHON_FUTURE_DIVISION 0
|
||||
#include <stddef.h>
|
||||
#ifndef offsetof
|
||||
|
|
@ -195,7 +195,10 @@ END: Cython Metadata */
|
|||
#ifndef CYTHON_UNPACK_METHODS
|
||||
#define CYTHON_UNPACK_METHODS 1
|
||||
#endif
|
||||
#ifndef CYTHON_FAST_THREAD_STATE
|
||||
#if PY_VERSION_HEX >= 0x030B00A4
|
||||
#undef CYTHON_FAST_THREAD_STATE
|
||||
#define CYTHON_FAST_THREAD_STATE 0
|
||||
#elif !defined(CYTHON_FAST_THREAD_STATE)
|
||||
#define CYTHON_FAST_THREAD_STATE 1
|
||||
#endif
|
||||
#ifndef CYTHON_FAST_PYCALL
|
||||
|
|
@ -210,7 +213,10 @@ END: Cython Metadata */
|
|||
#ifndef CYTHON_USE_DICT_VERSIONS
|
||||
#define CYTHON_USE_DICT_VERSIONS (PY_VERSION_HEX >= 0x030600B1)
|
||||
#endif
|
||||
#ifndef CYTHON_USE_EXC_INFO_STACK
|
||||
#if PY_VERSION_HEX >= 0x030B00A4
|
||||
#undef CYTHON_USE_EXC_INFO_STACK
|
||||
#define CYTHON_USE_EXC_INFO_STACK 0
|
||||
#elif !defined(CYTHON_USE_EXC_INFO_STACK)
|
||||
#define CYTHON_USE_EXC_INFO_STACK (PY_VERSION_HEX >= 0x030700A3)
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -15236,13 +15242,13 @@ static PyTypeObject __pyx_type_18_pydevd_frame_eval_22pydevd_frame_evaluator_Thr
|
|||
#if PY_VERSION_HEX >= 0x030400a1
|
||||
0, /*tp_finalize*/
|
||||
#endif
|
||||
#if PY_VERSION_HEX >= 0x030800b1
|
||||
#if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800)
|
||||
0, /*tp_vectorcall*/
|
||||
#endif
|
||||
#if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
|
||||
0, /*tp_print*/
|
||||
#endif
|
||||
#if CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM+0 >= 0x06000000
|
||||
#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000
|
||||
0, /*tp_pypy_flags*/
|
||||
#endif
|
||||
};
|
||||
|
|
@ -15454,13 +15460,13 @@ static PyTypeObject __pyx_type_18_pydevd_frame_eval_22pydevd_frame_evaluator_Fun
|
|||
#if PY_VERSION_HEX >= 0x030400a1
|
||||
0, /*tp_finalize*/
|
||||
#endif
|
||||
#if PY_VERSION_HEX >= 0x030800b1
|
||||
#if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800)
|
||||
0, /*tp_vectorcall*/
|
||||
#endif
|
||||
#if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
|
||||
0, /*tp_print*/
|
||||
#endif
|
||||
#if CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM+0 >= 0x06000000
|
||||
#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000
|
||||
0, /*tp_pypy_flags*/
|
||||
#endif
|
||||
};
|
||||
|
|
@ -15624,13 +15630,13 @@ static PyTypeObject __pyx_type_18_pydevd_frame_eval_22pydevd_frame_evaluator__Co
|
|||
#if PY_VERSION_HEX >= 0x030400a1
|
||||
0, /*tp_finalize*/
|
||||
#endif
|
||||
#if PY_VERSION_HEX >= 0x030800b1
|
||||
#if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800)
|
||||
0, /*tp_vectorcall*/
|
||||
#endif
|
||||
#if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
|
||||
0, /*tp_print*/
|
||||
#endif
|
||||
#if CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM+0 >= 0x06000000
|
||||
#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000
|
||||
0, /*tp_pypy_flags*/
|
||||
#endif
|
||||
};
|
||||
|
|
@ -15833,13 +15839,13 @@ static PyTypeObject __pyx_type_18_pydevd_frame_eval_22pydevd_frame_evaluator__Ca
|
|||
#if PY_VERSION_HEX >= 0x030400a1
|
||||
0, /*tp_finalize*/
|
||||
#endif
|
||||
#if PY_VERSION_HEX >= 0x030800b1
|
||||
#if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800)
|
||||
0, /*tp_vectorcall*/
|
||||
#endif
|
||||
#if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
|
||||
0, /*tp_print*/
|
||||
#endif
|
||||
#if CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM+0 >= 0x06000000
|
||||
#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000
|
||||
0, /*tp_pypy_flags*/
|
||||
#endif
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ from _pydevd_bundle._debug_adapter.pydevd_schema import (ThreadEvent, ModuleEven
|
|||
from _pydevd_bundle.pydevd_comm_constants import file_system_encoding
|
||||
from _pydevd_bundle.pydevd_constants import (int_types, IS_64BIT_PROCESS,
|
||||
PY_VERSION_STR, PY_IMPL_VERSION_STR, PY_IMPL_NAME, IS_PY36_OR_GREATER,
|
||||
IS_PYPY, GENERATED_LEN_ATTR_NAME, IS_WINDOWS, IS_LINUX, IS_MAC)
|
||||
IS_PYPY, GENERATED_LEN_ATTR_NAME, IS_WINDOWS, IS_LINUX, IS_MAC, IS_PY38_OR_GREATER)
|
||||
from tests_python import debugger_unittest
|
||||
from tests_python.debug_constants import TEST_CHERRYPY, IS_PY2, TEST_DJANGO, TEST_FLASK, IS_PY26, \
|
||||
IS_PY27, IS_CPYTHON, TEST_GEVENT, TEST_CYTHON
|
||||
|
|
@ -5988,6 +5988,43 @@ def test_pandas(case_setup, pyfile):
|
|||
writer.finished_ok = True
|
||||
|
||||
|
||||
@pytest.mark.skipif(not IS_PY38_OR_GREATER, reason='Python 3.8 onwards required for test.')
|
||||
def test_same_lineno_and_filename(case_setup, pyfile):
|
||||
|
||||
@pyfile
|
||||
def target():
|
||||
|
||||
def some_code():
|
||||
print('1') # Break here
|
||||
|
||||
code_obj = compile('''
|
||||
func()
|
||||
''', __file__, 'exec')
|
||||
|
||||
code_obj = code_obj.replace(co_name=some_code.__code__.co_name, co_firstlineno=some_code.__code__.co_firstlineno)
|
||||
exec(code_obj, {'func': some_code})
|
||||
|
||||
print('TEST SUCEEDED')
|
||||
|
||||
with case_setup.test_file(target) as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_add_breakpoint(writer.get_line_index_with_content('Break here'))
|
||||
json_facade.write_launch(justMyCode=False)
|
||||
json_facade.write_make_initial_run()
|
||||
|
||||
json_hit = json_facade.wait_for_thread_stopped()
|
||||
json_facade.write_continue()
|
||||
|
||||
if sys.version_info[:2] >= (3, 10):
|
||||
# On Python 3.10 we'll stop twice in this specific case
|
||||
# because the line actually matches in the caller (so
|
||||
# this is correct based on what the debugger is seeing...)
|
||||
json_hit = json_facade.wait_for_thread_stopped()
|
||||
json_facade.write_continue()
|
||||
writer.finished_ok = True
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main(['-k', 'test_case_skipping_filters', '-s'])
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,30 @@
|
|||
import pytest
|
||||
pytest_plugins = [
|
||||
str('_pytest.pytester'),
|
||||
]
|
||||
|
||||
|
||||
def _run_and_check(testdir, path, check_for='Worked'):
|
||||
result = testdir.runpython(path)
|
||||
def _run_and_check(testdir_or_pytester, path, check_for='Worked'):
|
||||
result = testdir_or_pytester.runpython(path)
|
||||
result.stdout.fnmatch_lines([
|
||||
check_for
|
||||
])
|
||||
|
||||
def test_run(testdir):
|
||||
|
||||
if hasattr(pytest, 'version_tuple') and pytest.version_tuple[0] >= 7:
|
||||
|
||||
@pytest.fixture
|
||||
def testdir_or_pytester(pytester):
|
||||
return pytester
|
||||
|
||||
else:
|
||||
|
||||
@pytest.fixture
|
||||
def testdir_or_pytester(testdir):
|
||||
return testdir
|
||||
|
||||
|
||||
def test_run(testdir_or_pytester):
|
||||
from tests_python import debugger_unittest
|
||||
import sys
|
||||
import os
|
||||
|
|
@ -24,7 +39,7 @@ def test_run(testdir):
|
|||
pydevd_dir = os.path.dirname(os.path.dirname(__file__))
|
||||
assert os.path.exists(os.path.join(pydevd_dir, 'pydevd.py'))
|
||||
|
||||
_run_and_check(testdir, testdir.makepyfile('''
|
||||
_run_and_check(testdir_or_pytester, testdir_or_pytester.makepyfile('''
|
||||
import sys
|
||||
sys.path.append(%(pydevd_dir)r)
|
||||
import pydevd
|
||||
|
|
@ -33,7 +48,7 @@ py_db.ready_to_run = True
|
|||
py_db.run(%(foo_dir)r)
|
||||
''' % locals()))
|
||||
|
||||
_run_and_check(testdir, testdir.makepyfile('''
|
||||
_run_and_check(testdir_or_pytester, testdir_or_pytester.makepyfile('''
|
||||
import sys
|
||||
sys.path.append(%(pydevd_dir)r)
|
||||
import pydevd
|
||||
|
|
@ -45,7 +60,7 @@ py_db.run(%(foo_dir)r, set_trace=False)
|
|||
# Not valid for Python 2.6
|
||||
return
|
||||
|
||||
_run_and_check(testdir, testdir.makepyfile('''
|
||||
_run_and_check(testdir_or_pytester, testdir_or_pytester.makepyfile('''
|
||||
import sys
|
||||
sys.path.append(%(pydevd_dir)r)
|
||||
sys.argv.append('--as-module')
|
||||
|
|
@ -55,7 +70,7 @@ py_db.ready_to_run = True
|
|||
py_db.run(%(foo_module)r, is_module=True)
|
||||
''' % locals()))
|
||||
|
||||
_run_and_check(testdir, testdir.makepyfile('''
|
||||
_run_and_check(testdir_or_pytester, testdir_or_pytester.makepyfile('''
|
||||
import sys
|
||||
sys.argv.append('--as-module')
|
||||
sys.path.append(%(pydevd_dir)r)
|
||||
|
|
@ -65,7 +80,7 @@ py_db.run(%(foo_module)r, is_module=True, set_trace=False)
|
|||
''' % locals()))
|
||||
|
||||
|
||||
def test_run_on_local_module_without_adding_to_pythonpath(testdir):
|
||||
def test_run_on_local_module_without_adding_to_pythonpath(testdir_or_pytester):
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
|
@ -76,7 +91,7 @@ def test_run_on_local_module_without_adding_to_pythonpath(testdir):
|
|||
with open(os.path.join(os.getcwd(), 'local_foo.py'), 'w') as stream:
|
||||
stream.write('print("WorkedLocalFoo")')
|
||||
|
||||
_run_and_check(testdir, testdir.makepyfile('''
|
||||
_run_and_check(testdir_or_pytester, testdir_or_pytester.makepyfile('''
|
||||
import sys
|
||||
import os
|
||||
sys.path.append(%(pydevd_dir)r)
|
||||
|
|
@ -90,7 +105,7 @@ py_db.ready_to_run = True
|
|||
py_db.run(%(foo_module)r, is_module=True)
|
||||
''' % locals()), check_for='WorkedLocalFoo')
|
||||
|
||||
_run_and_check(testdir, testdir.makepyfile('''
|
||||
_run_and_check(testdir_or_pytester, testdir_or_pytester.makepyfile('''
|
||||
import sys
|
||||
import os
|
||||
sys.argv.append('--as-module')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue