Completed
Push — master ( 0fdc83...4e3b27 )
by Ionel Cristian
55s
created

src.hunter.Not.__invert__()   A

Complexity

Conditions 1

Size

Total Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 2
rs 10
cc 1
1
from __future__ import absolute_import
2
3
import inspect
4
from itertools import chain
5
6
from fields import Fields
7
from six import string_types
8
9
from .actions import Action
10
from .event import Event
11
12
13
class Query(Fields.query):
14
    """
15
    A query class.
16
17
    See :class:`hunter.Event` for fields that can be filtered on.
18
    """
19
    query = ()
20
    allowed = tuple(i for i in Event.__dict__.keys() if not i.startswith('_'))
21
22
    def __init__(self, **query):
23
        """
24
        Args:
25
            query: criteria to match on.
26
27
                Accepted arguments: ``arg``, ``code``, ``filename``, ``frame``, ``fullsource``, ``function``,
28
                ``globals``, ``kind``, ``lineno``, ``locals``, ``module``, ``source``, ``stdlib``, ``tracer``.
29
        """
30
        for key in query:
31
            if key not in self.allowed:
32
                raise TypeError("Unexpected argument {!r}. Must be one of {}.".format(key, self.allowed))
33
        self.query = query
34
35
    def __repr__(self):
36
        return "Query({})".format(
37
            ', '.join("{}={!r}".format(*item) for item in self.query.items()),
38
        )
39
40
    def __call__(self, event):
41
        """
42
        Handles event. Returns True if all criteria matched.
43
        """
44
        for key, value in self.query.items():
45
            evalue = event[key]
46
            if isinstance(evalue, string_types) and isinstance(value, (list, tuple, set)):
47
                if not evalue.startswith(tuple(value)):
48
                    return False
49
            elif evalue != value:
50
                return False
51
52
        return True
53
54
    def __or__(self, other):
55
        """
56
        Convenience API so you can do ``Q() | Q()``. It converts that to ``Or(Q(), Q())``.
57
        """
58
        return Or(self, other)
59
60
    def __and__(self, other):
61
        """
62
        Convenience API so you can do ``Q() & Q()``. It converts that to ``And(Q(), Q())``.
63
        """
64
        return And(self, other)
65
66
    def __invert__(self):
67
        return Not(self)
68
69
70
class When(Fields.condition.actions):
71
    """
72
    Runs ``actions`` when ``condition(event)`` is ``True``.
73
74
    Actions take a single ``event`` argument.
75
    """
76
77
    def __init__(self, condition, *actions):
78
        if not actions:
79
            raise TypeError("Must give at least one action.")
80
        super(When, self).__init__(condition, [
81
            action() if inspect.isclass(action) and issubclass(action, Action) else action
82
            for action in actions
83
            ])
84
85
    def __call__(self, event):
86
        """
87
        Handles the event.
88
        """
89
        if self.condition(event):
90
            for action in self.actions:
91
                action(event)
92
93
            return True
94
        return False
95
96
    def __or__(self, other):
97
        return Or(self, other)
98
99
    def __and__(self, other):
100
        return And(self, other)
101
102
103
class And(Fields.predicates):
104
    """
105
    `And` predicate. Exits at the first sub-predicate that returns ``False``.
106
    """
107
108
    def __init__(self, *predicates):
109
        self.predicates = predicates
110
111
    def __str__(self):
112
        return "And({})".format(', '.join(str(p) for p in self.predicates))
113
114
    def __call__(self, event):
115
        """
116
        Handles the event.
117
        """
118
        for predicate in self.predicates:
119
            if not predicate(event):
120
                return False
121
        return True
122
123
    def __or__(self, other):
124
        return Or(self, other)
125
126
    def __and__(self, other):
127
        return And(*chain(self.predicates, other.predicates if isinstance(other, And) else (other,)))
128
129
    def __invert__(self):
130
        return Not(self)
131
132
133
class Or(Fields.predicates):
134
    """
135
    `Or` predicate. Exits at first sub-predicate that returns ``True``.
136
    """
137
138
    def __init__(self, *predicates):
139
        self.predicates = predicates
140
141
    def __str__(self):
142
        return "Or({})".format(', '.join(str(p) for p in self.predicates))
143
144
    def __call__(self, event):
145
        """
146
        Handles the event.
147
        """
148
        for predicate in self.predicates:
149
            if predicate(event):
150
                return True
151
        return False
152
153
    def __or__(self, other):
154
        return Or(*chain(self.predicates, other.predicates if isinstance(other, Or) else (other,)))
155
156
    def __and__(self, other):
157
        return And(self, other)
158
159
    def __invert__(self):
160
        return Not(self)
161
162
163
class Not(Fields.predicate):
164
    """
165
    `Not` predicate.
166
    """
167
168
    def __str__(self):
169
        return "Not({})".format(self.predicate)
170
171
    def __call__(self, event):
172
        """
173
        Handles the event.
174
        """
175
        return not self.predicate(event)
176
177
    def __or__(self, other):
178
        if isinstance(other, Not):
179
            return Not(And(self.predicate, other.predicate))
180
        return Or(self, other)
181
182
    def __and__(self, other):
183
        if isinstance(other, Not):
184
            return Not(Or(self.predicate, other.predicate))
185
        return And(self, other)
186
187
    def __invert__(self):
188
        return self.predicate
189