File: utils.py

package info (click to toggle)
python-executing 2.2.0-0.3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 11,860 kB
  • sloc: python: 10,235; sh: 48; makefile: 10
file content (215 lines) | stat: -rw-r--r-- 6,149 bytes parent folder | download | duplicates (3)
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
import sys
import ast
import inspect
from collections import namedtuple

import executing.executing

from executing.executing import attr_names_match, Instruction
try:
    from dis import Instruction as DisInstruction
except ImportError:
    DisInstruction = None

executing.executing.TESTING = 1

from executing import Source

non_existing_argument=object()

class Tester(object):
    def __init__(self):
        self.decorators = []
        self.__name__ = ""  # weird pypy3.6 thing

    def test_set_private_attrs(self):
        # Test that attributes with leading __ are handled properly,
        # as Python mangles their names.
        self.a, self.aa, self._a, self.__a, self.__aa = range(5)

    def check_decorators(self, expected):
        assert self.decorators == expected, (self.decorators, expected)
        self.decorators = []

    def get_node(self, typ):
        ex = self.get_executing(inspect.currentframe().f_back.f_back)
        node = ex.node
        assert isinstance(node, typ), (node, typ)
        return node

    def get_executing(self, frame):
        Source.lazycache(frame)
        return Source.executing(frame)

    def check(self, node, value):
        frame = inspect.currentframe().f_back.f_back
        result = eval(
            compile(ast.Expression(node), frame.f_code.co_filename, 'eval'),
            frame.f_globals,
            frame.f_locals,
        )
        assert result == value, (result, value)

    def __call__(self, arg=non_existing_argument, check_func=True):
        ex = self.get_executing(inspect.currentframe().f_back)
        if ex.decorator:
            assert {ex.node} == ex.statements
            self.decorators.append(ex.node.decorator_list.index(ex.decorator))
        else:
            call = ex.node
            if arg is non_existing_argument:
                assert len(call.args)==0
            else:
                self.check(call.args[0], arg)

            if check_func:
                self.check(call.func, self)
            if (
                isinstance(call.parent, (ast.ClassDef, ast.FunctionDef))
                and call in call.parent.decorator_list
            ):
                return self

        if arg is non_existing_argument:
            return tester
        else:
            return arg

    def __getattr__(self, item):
        parent_frame=inspect.currentframe().f_back

        # pytest is accessing tester to check if it is a test function
        if "_pytest" not in parent_frame.f_code.co_filename:
            node = self.get_node(ast.Attribute)
            self.check(node.value, self)
            assert node.attr == item

        return self

    def __getitem__(self, item):
        node = self.get_node(ast.Subscript)
        self.check(node.value, self)
        self.check(subscript_item(node), item)
        return self

    def __setattr__(self, name, value):
        if name in ('decorators', '__name__'):
            super(Tester, self).__setattr__(name, value)
            return

        node = self.get_node(ast.Attribute)
        self.check(node.value, self)
        if node.attr.startswith('__'):
            # Account for Python's name mangling of private attributes.
            assert name == "_{self.__class__.__name__}{node.attr}".format(self=self, node=node)
        else:
            assert name == node.attr
        assert attr_names_match(node.attr, name)
        return self

    def __delattr__(self, name):
        node = self.get_node(ast.Attribute)
        assert isinstance(node.ctx, ast.Del)
        assert node.attr == name

    def __setitem__(self, key, value):
        node = self.get_node(ast.Subscript)
        self.check(node.value, self)
        if not isinstance(key, slice):
            self.check(subscript_item(node), key)
        return self

    def __add__(self, other):
        node = self.get_node(ast.BinOp)
        self.check(node.left, self)
        self.check(node.right, other)
        return self

    __pow__ = __mul__ = __sub__ = __add__

    def __invert__(self):
        node = self.get_node(ast.UnaryOp)
        self.check(node.operand, self)
        return self

    __neg__ = __pos__ = __invert__

    def __lt__(self, other):
        node = self.get_node(ast.Compare)
        self.check(node.left, self)
        self.check(node.comparators[0], other)
        return self

    __ne__ = __ge__ = __lt__

    def __bool__(self):
        if sys.version_info >= (3, 11):
            self.get_node(ast.BoolOp)
            return False
        else:
            try:
                self.get_node(None)
            except RuntimeError:
                return False
            assert 0

    def __enter__(self):
        self.get_node(ast.With)
        return self

    def __exit__(self, exc_typ, exc_value, exc_traceback):
        self.get_node(ast.With)

    __nonzero__ = __bool__


tester = Tester()


def subscript_item(node):
    if sys.version_info < (3, 9):
        return node.slice.value
    else:
        return node.slice


def in_finally(node):
    while hasattr(node, 'parent'):
        if isinstance(node.parent, ast.Try) and node in node.parent.finalbody:
            return True
        node = node.parent
    return False


SourcePosition = namedtuple("SourcePosition", ["lineno", "col_offset"])


def start_position(obj):
    """
    returns the start source position as a (lineno,col_offset) tuple.
    obj can be ast.AST or Instruction.
    """
    if isinstance(obj, Instruction) or (DisInstruction is not None and isinstance(obj, DisInstruction)):
        obj = obj.positions

    if isinstance(obj,ast.Module):
        obj=obj.body[0]

    return SourcePosition(obj.lineno, obj.col_offset)


def end_position(obj):
    """
    returns the end source position as a (lineno,col_offset) tuple.
    obj can be ast.AST or Instruction.
    """
    if sys.version_info < (3, 8):
        return start_position(obj)

    if isinstance(obj, Instruction) or (DisInstruction is not None and isinstance(obj, DisInstruction)):
        obj = obj.positions

    if isinstance(obj,ast.Module):
        obj=obj.body[-1]

    return SourcePosition(obj.end_lineno, obj.end_col_offset)