Переглянути джерело

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.
Wojtek Porczyk 9 роки тому
батько
коміт
99edcb56c1
2 змінених файлів з 26 додано та 33 видалено
  1. 20 27
      qubes/events.py
  2. 6 6
      qubes/ext/__init__.py

+ 20 - 27
qubes/events.py

@@ -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,33 +51,34 @@ class EmitterMeta(type):
         super(type, cls).__init__(name, bases, dict_)
         cls.__handlers__ = collections.defaultdict(set)
 
-
-class Emitter(object):
-    '''Subject that can emit events
-    '''
-
-    __metaclass__ = EmitterMeta
-
-    def __init__(self, *args, **kwargs):
-        super(Emitter, self).__init__(*args, **kwargs)
-        self.events_enabled = True
-
         try:
-            propnames = set(prop.__name__ for prop in self.get_props_list())
+            propnames = set(prop.__name__ for prop in cls.get_props_list())
         except AttributeError:
             propnames = set()
 
-        for attr in dir(self):
+        for attr in dict_:
             if attr in propnames:
                 # we have to be careful, not to getattr() on properties which
                 # may be unset
                 continue
 
-            attr = getattr(self, attr)
+            attr = dict_[attr]
             if not ishandler(attr):
                 continue
 
-            self.add_handler(attr.ha_event, attr)
+            for event in attr.ha_events:
+                cls.add_handler(event, attr)
+
+
+class Emitter(object):
+    '''Subject that can emit events
+    '''
+
+    __metaclass__ = EmitterMeta
+
+    def __init__(self, *args, **kwargs):
+        super(Emitter, self).__init__(*args, **kwargs)
+        self.events_enabled = True
 
 
     @classmethod
@@ -103,18 +103,11 @@ 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)
+                handler(self, event, *args, **kwargs)
 
 
     def fire_event(self, event, *args, **kwargs):

+ 6 - 6
qubes/ext/__init__.py

@@ -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