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()
|