File: test_info_variables.py

package info (click to toggle)
python-friendly-traceback 0.7.62%2Bgit20240811.d7dbff6-1.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 9,264 kB
  • sloc: python: 21,500; makefile: 4
file content (133 lines) | stat: -rw-r--r-- 4,509 bytes parent folder | download
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
import inspect

import friendly_traceback as ft

global_a = 1
global_b = 2
global_and_nonlocal_different = 1


def test_get_variables_in_frame_by_scope():
    # We cannot use pytest for this test as it messes with the frames
    # and generates a RuntimeError.

    get = ft.info_variables.get_variables_in_frame_by_scope
    current_frame = None

    b = 2
    global_and_nonlocal_different = 2

    def outer():
        c = 3
        d = 4

        def inner():
            global global_a
            global global_b
            nonlocal current_frame
            nonlocal c
            e = 5
            global_b += 1
            current_frame = inspect.currentframe()

        inner()

    outer()

    # declaring a variable global and changing (or not) its value
    # does not make it a local variable
    assert "global_a" in get(current_frame, "global")
    assert "global_a" not in get(current_frame, "local")
    assert "global_a" not in get(current_frame, "nonlocal")
    assert "global_b" not in get(current_frame, "local")

    # nonlocal variable two frames removed is the same as one frame removed
    # b: two frames removed
    assert "b" in get(current_frame, "nonlocal")
    assert "b" not in get(current_frame, "local")
    assert "b" not in get(current_frame, "global")
    # d: one frame removed
    assert "d" in get(current_frame, "nonlocal")
    assert "d" not in get(current_frame, "local")
    assert "d" not in get(current_frame, "global")

    # declaring a variable nonlocal makes it also a local variable
    assert "c" in get(current_frame, "local")
    assert "c" in get(current_frame, "nonlocal")
    assert "c" not in get(current_frame, "global")

    assert "e" in get(current_frame, "local")

    assert "global_and_nonlocal_different" in get(current_frame, "nonlocal")
    assert "global_and_nonlocal_different" in get(current_frame, "global")

    # test other function after fixing bug (issue #69)
    get_scopes = ft.info_variables.get_definition_scope
    assert "nonlocal" in get_scopes("global_and_nonlocal_different", current_frame)
    assert "global" in get_scopes("global_and_nonlocal_different", current_frame)
    assert "nonlocal" not in get_scopes("global_a", current_frame)
    assert "global" in get_scopes("global_a", current_frame)
    assert "nonlocal" in get_scopes("b", current_frame)
    assert "global" not in get_scopes("b", current_frame)


def test_simplify_repr():
    import math
    import collections

    simplify = ft.info_variables.simplify_repr
    INDENT = ft.info_variables.INDENT

    simplified_math = simplify(repr(math))
    assert simplified_math == "<module math (builtin)>" or (
        "<module math>" in simplified_math and "PYTHON_LIB" in simplified_math
    )
    # replace \ in path so that it works for all OSes
    assert (
        simplify(repr(collections)).replace("\\", "/")
        == "<module collections> from PYTHON_LIB:/collections/__init__.py"
    )
    assert simplify(repr(open)) == "<builtin function open>"
    assert simplify("<class 'AssertionError'>") == "<class AssertionError>"
    assert (
        simplify("<bound method ChainMap.pop of ChainMap({(0, 0): 'origin'}, {})>")
        == "<bound method ChainMap.pop> of ChainMap({(0, 0): 'origin'}, {})"
    )
    assert (
        simplify("<built-in method popitem of dict object at 0x00000267D1C96180>")
        == "<builtin method popitem of dict object>"
    )
    assert (
        simplify("<function test_Generic.<locals>.a at 0x00000267D28B0F70>")
        == "<function a> defined in <function test_Generic>"
    )
    assert (
        simplify(
            "<bound method test_method_got_multiple_argument.<locals>.T.some_method"
            " of <tests.runtime.test_type_error.test_method_got_multiple_argument."
            "<locals>.T object at 0x00000179EE9CD7F0>>"
        )
        == "<bound method T.some_method>"
        + f"\n{INDENT}of <T object>"
        + f"\n{INDENT}defined in <function "
        + "tests.runtime.test_type_error.test_method_got_multiple_argument>"
    )


def test_get_dotted_name_from_frame():
    import itertools
    frame = inspect.currentframe()
    assert ft.info_variables.get_object_from_name('itertools.count', frame) != None


def test_safe_repr_can_handle_errors_on_attribute_access():

    class Proxy:
        def __getattr__(self, name):
            raise NotImplementedError

    assert ft.info_variables.safe_repr(Proxy())


if __name__ == "__main__":
    test_get_variables_in_frame_by_scope()