qubes: fix event framework
Two important fixes are in this commit: handlers from decorators are added when class is defined (and not when class is instantiated); also multiple events can be specified in the decorator.
This commit is contained in:
parent
7971342811
commit
99edcb56c1
@ -10,7 +10,7 @@ etc.
|
|||||||
import collections
|
import collections
|
||||||
|
|
||||||
|
|
||||||
def handler(event):
|
def handler(*events):
|
||||||
'''Event handler decorator factory.
|
'''Event handler decorator factory.
|
||||||
|
|
||||||
To hook an event, decorate a method in your plugin class with this
|
To hook an event, decorate a method in your plugin class with this
|
||||||
@ -27,8 +27,7 @@ def handler(event):
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
def decorator(f):
|
def decorator(f):
|
||||||
f.ha_event = event
|
f.ha_events = events
|
||||||
f.ha_bound = True
|
|
||||||
return f
|
return f
|
||||||
|
|
||||||
return decorator
|
return decorator
|
||||||
@ -43,7 +42,7 @@ def ishandler(o):
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
return callable(o) \
|
return callable(o) \
|
||||||
and hasattr(o, 'ha_event')
|
and hasattr(o, 'ha_events')
|
||||||
|
|
||||||
|
|
||||||
class EmitterMeta(type):
|
class EmitterMeta(type):
|
||||||
@ -52,6 +51,24 @@ class EmitterMeta(type):
|
|||||||
super(type, cls).__init__(name, bases, dict_)
|
super(type, cls).__init__(name, bases, dict_)
|
||||||
cls.__handlers__ = collections.defaultdict(set)
|
cls.__handlers__ = collections.defaultdict(set)
|
||||||
|
|
||||||
|
try:
|
||||||
|
propnames = set(prop.__name__ for prop in cls.get_props_list())
|
||||||
|
except AttributeError:
|
||||||
|
propnames = set()
|
||||||
|
|
||||||
|
for attr in dict_:
|
||||||
|
if attr in propnames:
|
||||||
|
# we have to be careful, not to getattr() on properties which
|
||||||
|
# may be unset
|
||||||
|
continue
|
||||||
|
|
||||||
|
attr = dict_[attr]
|
||||||
|
if not ishandler(attr):
|
||||||
|
continue
|
||||||
|
|
||||||
|
for event in attr.ha_events:
|
||||||
|
cls.add_handler(event, attr)
|
||||||
|
|
||||||
|
|
||||||
class Emitter(object):
|
class Emitter(object):
|
||||||
'''Subject that can emit events
|
'''Subject that can emit events
|
||||||
@ -63,23 +80,6 @@ class Emitter(object):
|
|||||||
super(Emitter, self).__init__(*args, **kwargs)
|
super(Emitter, self).__init__(*args, **kwargs)
|
||||||
self.events_enabled = True
|
self.events_enabled = True
|
||||||
|
|
||||||
try:
|
|
||||||
propnames = set(prop.__name__ for prop in self.get_props_list())
|
|
||||||
except AttributeError:
|
|
||||||
propnames = set()
|
|
||||||
|
|
||||||
for attr in dir(self):
|
|
||||||
if attr in propnames:
|
|
||||||
# we have to be careful, not to getattr() on properties which
|
|
||||||
# may be unset
|
|
||||||
continue
|
|
||||||
|
|
||||||
attr = getattr(self, attr)
|
|
||||||
if not ishandler(attr):
|
|
||||||
continue
|
|
||||||
|
|
||||||
self.add_handler(attr.ha_event, attr)
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_handler(cls, event, handler):
|
def add_handler(cls, event, handler):
|
||||||
@ -103,18 +103,11 @@ class Emitter(object):
|
|||||||
return
|
return
|
||||||
|
|
||||||
for cls in order:
|
for cls in order:
|
||||||
# first fire bound (= our own) handlers, then handlers from extensions
|
|
||||||
if not hasattr(cls, '__handlers__'):
|
if not hasattr(cls, '__handlers__'):
|
||||||
continue
|
continue
|
||||||
for handler in sorted(cls.__handlers__[event],
|
for handler in sorted(cls.__handlers__[event],
|
||||||
key=(lambda handler: hasattr(handler, 'ha_bound')), reverse=True):
|
key=(lambda handler: hasattr(handler, 'ha_bound')), reverse=True):
|
||||||
if hasattr(handler, 'ha_bound'):
|
handler(self, event, *args, **kwargs)
|
||||||
# this is our (bound) method, self is implicit
|
|
||||||
handler(event, *args, **kwargs)
|
|
||||||
else:
|
|
||||||
# this is from extension or hand-added, so we see method as
|
|
||||||
# unbound, therefore we need to pass self
|
|
||||||
handler(self, event, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def fire_event(self, event, *args, **kwargs):
|
def fire_event(self, event, *args, **kwargs):
|
||||||
|
@ -55,7 +55,7 @@ class Extension(object):
|
|||||||
self.app.add_hook(attr.ha_event, attr)
|
self.app.add_hook(attr.ha_event, attr)
|
||||||
|
|
||||||
|
|
||||||
def handler(event, vm=None, system=False):
|
def handler(*events, **kwargs):
|
||||||
'''Event handler decorator factory.
|
'''Event handler decorator factory.
|
||||||
|
|
||||||
To hook an event, decorate a method in your plugin class with this
|
To hook an event, decorate a method in your plugin class with this
|
||||||
@ -71,14 +71,14 @@ def handler(event, vm=None, system=False):
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
def decorator(f):
|
def decorator(f):
|
||||||
f.ho_event = event
|
f.ha_events = events
|
||||||
|
|
||||||
if system:
|
if kwargs.get('system', False):
|
||||||
f.ha_vm = None
|
f.ha_vm = None
|
||||||
elif vm is None:
|
elif 'vm' in kwargs:
|
||||||
f.ha_vm = qubes.vm.BaseVM
|
f.ha_vm = kwargs['vm']
|
||||||
else:
|
else:
|
||||||
f.ha_vm = vm
|
f.ha_vm = qubes.vm.BaseVM
|
||||||
|
|
||||||
return f
|
return f
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user