File: test_frame_evaluator.py

package info (click to toggle)
pydevd 3.3.0%2Bds-4
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 13,892 kB
  • sloc: python: 77,508; cpp: 1,869; sh: 368; makefile: 50; ansic: 4
file content (136 lines) | stat: -rw-r--r-- 4,909 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import sys
import threading
import pytest
from tests_python.debugger_unittest import IS_PY36_OR_GREATER, IS_CPYTHON
from tests_python.debug_constants import TEST_CYTHON
from _pydevd_bundle.pydevd_constants import IS_PY311_OR_GREATER

pytestmark = pytest.mark.skipif(
    not IS_PY36_OR_GREATER or not IS_CPYTHON or not TEST_CYTHON or IS_PY311_OR_GREATER, reason="Requires CPython >= 3.6 < 3.11"
)


def get_foo_frame():
    frame = sys._getframe()
    return frame


class CheckClass(object):
    def collect_info(self):
        from _pydevd_frame_eval import pydevd_frame_evaluator

        thread_info = pydevd_frame_evaluator.get_thread_info_py()
        self.thread_info = thread_info


@pytest.mark.parametrize("_times", range(2))
def test_thread_info(_times):
    obj = CheckClass()
    obj.collect_info()
    assert obj.thread_info.additional_info is not None
    assert not obj.thread_info.is_pydevd_thread
    thread_info = obj.thread_info
    obj.collect_info()
    assert obj.thread_info is thread_info

    obj = CheckClass()
    t = threading.Thread(target=obj.collect_info)
    t.is_pydev_daemon_thread = True
    t.start()
    t.join()

    assert obj.thread_info.additional_info is None
    assert obj.thread_info.is_pydevd_thread


def method():
    return sys._getframe()


@pytest.fixture
def _custom_global_dbg():
    from _pydevd_bundle.pydevd_constants import GlobalDebuggerHolder
    from pydevd import PyDB

    curr = GlobalDebuggerHolder.global_dbg
    PyDB()  # Will make itself current
    yield
    GlobalDebuggerHolder.global_dbg = curr


@pytest.mark.parametrize("_times", range(2))
def test_func_code_info(_times, _custom_global_dbg):
    from _pydevd_frame_eval import pydevd_frame_evaluator

    # Must be called before get_func_code_info_py to initialize the _code_extra_index.
    thread_info = pydevd_frame_evaluator.get_thread_info_py()

    func_info = pydevd_frame_evaluator.get_func_code_info_py(thread_info, method(), method.__code__)
    assert func_info.co_filename is method.__code__.co_filename
    func_info2 = pydevd_frame_evaluator.get_func_code_info_py(thread_info, method(), method.__code__)
    assert func_info is func_info2

    some_func = eval("lambda:sys._getframe()")
    func_info3 = pydevd_frame_evaluator.get_func_code_info_py(thread_info, some_func(), some_func.__code__)
    del some_func
    del func_info3

    some_func = eval("lambda:sys._getframe()")
    pydevd_frame_evaluator.get_func_code_info_py(thread_info, some_func(), some_func.__code__)
    func_info = pydevd_frame_evaluator.get_func_code_info_py(thread_info, some_func(), some_func.__code__)
    assert pydevd_frame_evaluator.get_func_code_info_py(thread_info, some_func(), some_func.__code__) is func_info


def test_generate_code_with_breakpoints():
    from _pydevd_frame_eval.pydevd_frame_evaluator import generate_code_with_breakpoints_py
    from _pydevd_frame_eval.pydevd_frame_evaluator import get_cached_code_obj_info_py

    def create_breakpoints_dict(lines):
        return dict((line, None) for line in lines)

    def method():
        a = 1
        a = 2
        a = 3

    breakpoint_found, new_code = generate_code_with_breakpoints_py(
        method.__code__, create_breakpoints_dict([method.__code__.co_firstlineno + 1, method.__code__.co_firstlineno + 2])
    )

    assert breakpoint_found
    with pytest.raises(AssertionError):
        # We must use the cached one directly (in the real-world, this would indicate a reuse
        # of the code object -- which is related to generator handling).
        generate_code_with_breakpoints_py(new_code, create_breakpoints_dict([method.__code__.co_firstlineno + 1]))

    cached_value = get_cached_code_obj_info_py(new_code)
    breakpoint_found, force_stay_in_untraced_mode = cached_value.compute_force_stay_in_untraced_mode(
        create_breakpoints_dict([method.__code__.co_firstlineno + 1])
    )

    assert breakpoint_found
    assert force_stay_in_untraced_mode

    # i.e.: no breakpoints match (stay in untraced mode)
    breakpoint_found, force_stay_in_untraced_mode = cached_value.compute_force_stay_in_untraced_mode(
        create_breakpoints_dict([method.__code__.co_firstlineno + 10])
    )

    assert not breakpoint_found
    assert force_stay_in_untraced_mode

    # i.e.: one of the breakpoints match (stay in untraced mode)
    breakpoint_found, force_stay_in_untraced_mode = cached_value.compute_force_stay_in_untraced_mode(
        create_breakpoints_dict([method.__code__.co_firstlineno + 2])
    )

    assert breakpoint_found
    assert force_stay_in_untraced_mode

    # i.e.: one of the breakpoints doesn't match (leave untraced mode)
    breakpoint_found, force_stay_in_untraced_mode = cached_value.compute_force_stay_in_untraced_mode(
        create_breakpoints_dict([method.__code__.co_firstlineno + 3])
    )

    assert breakpoint_found
    assert not force_stay_in_untraced_mode