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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def handler(event):
 | 
			
		||||
def handler(*events):
 | 
			
		||||
    '''Event handler decorator factory.
 | 
			
		||||
 | 
			
		||||
    To hook an event, decorate a method in your plugin class with this
 | 
			
		||||
@ -27,8 +27,7 @@ def handler(event):
 | 
			
		||||
    '''
 | 
			
		||||
 | 
			
		||||
    def decorator(f):
 | 
			
		||||
        f.ha_event = event
 | 
			
		||||
        f.ha_bound = True
 | 
			
		||||
        f.ha_events = events
 | 
			
		||||
        return f
 | 
			
		||||
 | 
			
		||||
    return decorator
 | 
			
		||||
@ -43,7 +42,7 @@ def ishandler(o):
 | 
			
		||||
    '''
 | 
			
		||||
 | 
			
		||||
    return callable(o) \
 | 
			
		||||
        and hasattr(o, 'ha_event')
 | 
			
		||||
        and hasattr(o, 'ha_events')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EmitterMeta(type):
 | 
			
		||||
@ -52,6 +51,24 @@ class EmitterMeta(type):
 | 
			
		||||
        super(type, cls).__init__(name, bases, dict_)
 | 
			
		||||
        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):
 | 
			
		||||
    '''Subject that can emit events
 | 
			
		||||
@ -63,23 +80,6 @@ class Emitter(object):
 | 
			
		||||
        super(Emitter, self).__init__(*args, **kwargs)
 | 
			
		||||
        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
 | 
			
		||||
    def add_handler(cls, event, handler):
 | 
			
		||||
@ -103,17 +103,10 @@ class Emitter(object):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        for cls in order:
 | 
			
		||||
            # first fire bound (= our own) handlers, then handlers from extensions
 | 
			
		||||
            if not hasattr(cls, '__handlers__'):
 | 
			
		||||
                continue
 | 
			
		||||
            for handler in sorted(cls.__handlers__[event],
 | 
			
		||||
                    key=(lambda handler: hasattr(handler, 'ha_bound')), reverse=True):
 | 
			
		||||
                if hasattr(handler, 'ha_bound'):
 | 
			
		||||
                    # 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)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -55,7 +55,7 @@ class Extension(object):
 | 
			
		||||
                self.app.add_hook(attr.ha_event, attr)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def handler(event, vm=None, system=False):
 | 
			
		||||
def handler(*events, **kwargs):
 | 
			
		||||
    '''Event handler decorator factory.
 | 
			
		||||
 | 
			
		||||
    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):
 | 
			
		||||
        f.ho_event = event
 | 
			
		||||
        f.ha_events = events
 | 
			
		||||
 | 
			
		||||
        if system:
 | 
			
		||||
        if kwargs.get('system', False):
 | 
			
		||||
            f.ha_vm = None
 | 
			
		||||
        elif vm is None:
 | 
			
		||||
            f.ha_vm = qubes.vm.BaseVM
 | 
			
		||||
        elif 'vm' in kwargs:
 | 
			
		||||
            f.ha_vm = kwargs['vm']
 | 
			
		||||
        else:
 | 
			
		||||
            f.ha_vm = vm
 | 
			
		||||
            f.ha_vm = qubes.vm.BaseVM
 | 
			
		||||
 | 
			
		||||
        return f
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user