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
|
"""
The event system handles all events throughout the sqlalchemy
and sqlalchemy.orm packages.
Event specifications:
:attr:`sqlalchemy.pool.Pool.events`
"""
from sqlalchemy import util
def listen(fn, identifier, target, *args):
"""Listen for events, passing to fn."""
getattr(target.events, identifier).append(fn, target)
NO_RESULT = util.symbol('no_result')
class _DispatchMeta(type):
def __init__(cls, classname, bases, dict_):
for k in dict_:
if k.startswith('on_'):
setattr(cls, k, EventDescriptor(dict_[k]))
return type.__init__(cls, classname, bases, dict_)
class Events(object):
__metaclass__ = _DispatchMeta
def __init__(self, parent_cls):
self.parent_cls = parent_cls
class _ExecEvent(object):
def exec_and_clear(self, *args, **kw):
"""Execute this event once, then clear all listeners."""
self(*args, **kw)
self[:] = []
def exec_until_return(self, *args, **kw):
"""Execute listeners for this event until
one returns a non-None value.
Returns the value, or None.
"""
if self:
for fn in self:
r = fn(*args, **kw)
if r is not None:
return r
return None
def __call__(self, *args, **kw):
"""Execute this event."""
if self:
for fn in self:
fn(*args, **kw)
class EventDescriptor(object):
"""Represent an event type associated with a :class:`Events` class
as well as class-level listeners.
"""
def __init__(self, fn):
self.__name__ = fn.__name__
self.__doc__ = fn.__doc__
self._clslevel = []
def append(self, obj, target):
self._clslevel.append((obj, target))
def __get__(self, obj, cls):
if obj is None:
return self
obj.__dict__[self.__name__] = result = Listeners()
result.extend([
fn for fn, target in
self._clslevel
if issubclass(obj.parent_cls, target)
])
return result
class Listeners(_ExecEvent, list):
"""Represent a collection of listeners linked
to an instance of :class:`Events`."""
def append(self, obj, target):
list.append(self, obj)
class dispatcher(object):
def __init__(self, events):
self.dispatch_cls = events
def __get__(self, obj, cls):
if obj is None:
return self.dispatch_cls
obj.__dict__['events'] = disp = self.dispatch_cls(cls)
return disp
|