diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-07-24 17:55:06 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-07-24 17:55:06 -0400 |
commit | 693e2dcacf7c6317c131ad11fcc0466e6c9164b8 (patch) | |
tree | f807bae733831f9b09fc59447b8ffabd022d7a66 /lib/sqlalchemy/event.py | |
parent | 8a7ae371535342bb35491d59aaa1131ba7c435fa (diff) | |
download | sqlalchemy-693e2dcacf7c6317c131ad11fcc0466e6c9164b8.tar.gz |
- worked it out so that classes declare a nested class "event",
with methods representing events. This is self-documenting via sphinx.
- implemented new model for pool, classmanager. Most events are
one or two args, so going back to allowing any kind of *arg, **kw
signature for events - this is simpler and improves performance,
though we don't get the "we can add new kw's anytime". perhaps
there's some other way to approach that.
Diffstat (limited to 'lib/sqlalchemy/event.py')
-rw-r--r-- | lib/sqlalchemy/event.py | 97 |
1 files changed, 70 insertions, 27 deletions
diff --git a/lib/sqlalchemy/event.py b/lib/sqlalchemy/event.py index 1b0b62b34..f844b3345 100644 --- a/lib/sqlalchemy/event.py +++ b/lib/sqlalchemy/event.py @@ -1,44 +1,87 @@ +""" +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.""" - target._dispatch.append(fn, identifier, target, *args) + 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 Dispatch(object): +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 the given event once, then clear all listeners.""" - def append(self, identifier, fn, target): - getattr(self, identifier).append(fn) - - def __getattr__(self, key): - self.__dict__[key] = coll = [] - return coll - - def chain(self, identifier, chain_kw, **kw): - ret = NO_RESULT - for fn in getattr(self, identifier): - ret = fn(**kw) - kw['chain_kw'] = ret - return ret - - def __call__(self, identifier, **kw): - for fn in getattr(self, identifier): - fn(**kw) + self(*args, **kw) + self[:] = [] + def __call__(self, *args, **kw): + """Execute the given 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, dispatch_cls=Dispatch): - self.dispatch_cls = dispatch_cls - self._dispatch = dispatch_cls() + def __init__(self, events): + self.dispatch_cls = events def __get__(self, obj, cls): if obj is None: - return self._dispatch - obj.__dict__['_dispatch'] = disp = self.dispatch_cls() - for key in self._dispatch.__dict__: - if key.startswith('on_'): - disp.__dict__[key] = self._dispatch.__dict__[k].copy() + return self.dispatch_cls + obj.__dict__['events'] = disp = self.dispatch_cls(cls) return disp |