File: test_frame_utils.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 (235 lines) | stat: -rw-r--r-- 7,802 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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# coding: utf-8
import sys
from _pydevd_bundle.pydevd_constants import EXCEPTION_TYPE_USER_UNHANDLED
import pytest
from tests_python.debug_constants import IS_PY311_OR_GREATER


def test_create_frames_list_from_traceback():
    def method():
        raise RuntimeError("first")

    def method1():
        try:
            method()
        except Exception as e:
            raise RuntimeError("second") from e

    def method2():
        try:
            method1()
        except Exception as e:
            raise RuntimeError("third") from e

    try:
        method2()
    except Exception as e:
        exc_type, exc_desc, trace_obj = sys.exc_info()
        frame = sys._getframe()

        from _pydevd_bundle.pydevd_frame_utils import create_frames_list_from_traceback

        frames_list = create_frames_list_from_traceback(trace_obj, frame, exc_type, exc_desc, exception_type=EXCEPTION_TYPE_USER_UNHANDLED)
        assert str(frames_list.exc_desc) == "third"
        assert str(frames_list.chained_frames_list.exc_desc) == "second"
        assert str(frames_list.chained_frames_list.chained_frames_list.exc_desc) == "first"
        assert frames_list.chained_frames_list.chained_frames_list.chained_frames_list is None


if IS_PY311_OR_GREATER:
    import traceback

    _byte_offset_to_character_offset = getattr(traceback, "_byte_offset_to_character_offset", None)
    if _byte_offset_to_character_offset is not None:
        _original = traceback._byte_offset_to_character_offset

        def _byte_offset_to_character_offset(*args, **kwargs):
            try:
                return _original(*args, **kwargs)
            except:
                # Replacement to deal with the buggy version released on Python 3.11.0.
                def replacement(str, offset):
                    as_utf8 = str.encode("utf-8")
                    if offset > len(as_utf8):
                        offset = len(as_utf8)

                    return len(as_utf8[: offset + 1].decode("utf-8", "replace"))

                return replacement(*args, **kwargs)

        traceback._byte_offset_to_character_offset = _byte_offset_to_character_offset

_USE_UNICODE = [False, True]


@pytest.mark.parametrize("use_unicode", _USE_UNICODE)
@pytest.mark.skipif(not IS_PY311_OR_GREATER, reason="Python 3.11 required.")
def test_collect_anchors_subscript(use_unicode):
    from _pydevd_bundle.pydevd_frame_utils import create_frames_list_from_traceback

    if use_unicode:

        def method():
            d = {"x": {"á": {"í": {"theta": 1}}}}

            result = d["x"]["á"]["í"]["beta"]

    else:

        def method():
            d = {"x": {"y": {"i": {"theta": 1}}}}

            result = d["x"]["y"]["i"]["beta"]

    try:
        method()
    except:
        exc_type, exc_desc, trace_obj = sys.exc_info()
        memo = {}
        frame = None
        frames_list = create_frames_list_from_traceback(trace_obj, frame, exc_type, exc_desc, memo)
        iter_in = iter(frames_list)
        f = next(iter_in)
        assert f.f_code.co_name == "method"
        line_col_info = frames_list.frame_id_to_line_col_info[id(f)]

        if use_unicode:
            line = '            result = d["x"]["á"]["í"]["beta"]'
        else:
            line = '            result = d["x"]["y"]["i"]["beta"]'

        # Ok, so, the range that we we have covers >>d["x"]["á"]["í"]["beta"]<<
        # the problem here is that ideally we'd like to present to the user that
        # the current key is "beta", so, we need to do some additional computation
        # to find out the proper column to show to the user.
        # (see https://github.com/microsoft/debugpy/issues/1099
        # for more information).
        assert line_col_info.colno == line.index('d["x"]')

        # It's +1 here due to the í unicode char (we need to convert from the bytes
        # index to the actual character in the string to get the actual col).
        if use_unicode:
            assert line_col_info.end_colno == len(line) + 2
        else:
            assert line_col_info.end_colno == len(line)
        original_line = line

        col, endcol = line_col_info.map_columns_to_line(original_line)
        assert col == line.index('["beta"]')
        assert endcol == len(line)


@pytest.mark.parametrize("use_unicode", _USE_UNICODE)
@pytest.mark.skipif(not IS_PY311_OR_GREATER, reason="Python 3.11 required.")
def test_collect_anchors_binop_1(use_unicode):
    from _pydevd_bundle.pydevd_frame_utils import create_frames_list_from_traceback

    if use_unicode:

        def method():
            á = 1
            í = 2
            c = tuple

            result = á + í + c

    else:

        def method():
            a = 1
            b = 2
            c = tuple

            result = a + b + c

    try:
        method()
    except:
        exc_type, exc_desc, trace_obj = sys.exc_info()
        memo = {}
        frame = None
        frames_list = create_frames_list_from_traceback(trace_obj, frame, exc_type, exc_desc, memo)
        iter_in = iter(frames_list)
        f = next(iter_in)
        assert f.f_code.co_name == "method"
        line_col_info = frames_list.frame_id_to_line_col_info[id(f)]

        if use_unicode:
            line = "            result = á + í + c"
            expected_index = line.index("á + í")
        else:
            line = "            result = a + b + c"
            expected_index = line.index("a + b")

        assert line_col_info.colno == expected_index

        # It's +2 here due to the á and í unicode chars (we need to convert from the bytes
        # index to the actual character in the string to get the actual col).
        if use_unicode:
            assert line_col_info.end_colno == len(line) + 2
        else:
            assert line_col_info.end_colno == len(line)
        original_line = line

        col, endcol = line_col_info.map_columns_to_line(original_line)
        assert col == line.index("+ c")
        assert endcol == col + 1


@pytest.mark.parametrize("use_unicode", _USE_UNICODE)
@pytest.mark.skipif(not IS_PY311_OR_GREATER, reason="Python 3.11 required.")
def test_collect_anchors_binop_2(use_unicode):
    from _pydevd_bundle.pydevd_frame_utils import create_frames_list_from_traceback

    if use_unicode:

        def method():
            á = 1
            í = 2
            c = tuple

            result = á + c + í

    else:

        def method():
            a = 1
            b = 2
            c = tuple

            result = a + c + b

    try:
        method()
    except:
        exc_type, exc_desc, trace_obj = sys.exc_info()
        memo = {}
        frame = None
        frames_list = create_frames_list_from_traceback(trace_obj, frame, exc_type, exc_desc, memo)
        iter_in = iter(frames_list)
        f = next(iter_in)
        assert f.f_code.co_name == "method"
        line_col_info = frames_list.frame_id_to_line_col_info[id(f)]

        if use_unicode:
            line = "            result = á + c + í"
            expected_index = line.index("á + c")
        else:
            line = "            result = a + c + b"
            expected_index = line.index("a + c")

        assert line_col_info.colno == expected_index

        # It's +2 here due to the á and í unicode chars (we need to convert from the bytes
        # index to the actual character in the string to get the actual col).
        if use_unicode:
            assert line_col_info.end_colno == line.index("c + í") + 2
        else:
            assert line_col_info.end_colno == line.index("c + b") + 1
        original_line = line

        col, endcol = line_col_info.map_columns_to_line(original_line)
        assert col == 23
        assert endcol == 24
        assert col == line.index("+ c")
        assert endcol == col + 1