diff --git a/qubes/__init__.py b/qubes/__init__.py index 6659c324..fe252e6f 100644 --- a/qubes/__init__.py +++ b/qubes/__init__.py @@ -510,9 +510,9 @@ class property(object): value = self._type(value) if has_oldvalue: - instance.fire_event('property-pre-set:' + self.__name__, value, oldvalue) + instance.fire_event_pre('property-pre-set:' + self.__name__, value, oldvalue) else: - instance.fire_event('property-pre-set:' + self.__name__, value) + instance.fire_event_pre('property-pre-set:' + self.__name__, value) instance._init_property(self, value) diff --git a/qubes/events.py b/qubes/events.py index fa5a9d64..58180f59 100644 --- a/qubes/events.py +++ b/qubes/events.py @@ -92,24 +92,17 @@ class Emitter(object): cls.__handlers__[event].add(handler) - def fire_event(self, event, *args, **kwargs): - '''Call all handlers for an event. + def _fire_event_in_order(self, order, event, *args, **kwargs): + '''Fire event for classes in given order. - Handlers are called for class and all parent classess, in method - resolution order. For each class first are called bound handlers - (specified in class definition), then handlers from extensions. Aside - from above, remaining order is undefined. - - :param str event: event identificator - - All *args* and *kwargs* are passed verbatim. They are different for - different events. + Do not use this method. Use :py:meth:`fire_event` or + :py:meth:`fire_event_pre`. ''' if not self.events_enabled: return - for cls in self.__class__.__mro__: + for cls in order: # first fire bound (= our own) handlers, then handlers from extensions if not hasattr(cls, '__handlers__'): continue @@ -122,3 +115,42 @@ class Emitter(object): # 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): + '''Call all handlers for an event. + + Handlers are called for class and all parent classess, in **reversed** + method resolution order. For each class first are called bound handlers + (specified in class definition), then handlers from extensions. Aside + from above, remaining order is undefined. + + .. seealso:: + :py:meth:`fire_event_pre` + + :param str event: event identificator + + All *args* and *kwargs* are passed verbatim. They are different for + different events. + ''' + + self._fire_event_in_order(reversed(self.__class__.__mro__), event, *args, **kwargs) + + + def fire_event_pre(self, event, *args, **kwargs): + '''Call all handlers for an event. + + Handlers are called for class and all parent classess, in **true** + method resolution order. This is intended for ``-pre-`` events, where + order of invocation should be reversed. + + .. seealso:: + :py:meth:`fire_event` + + :param str event: event identificator + + All *args* and *kwargs* are passed verbatim. They are different for + different events. + ''' + + self._fire_event_in_order(self.__class__.__mro__, event, *args, **kwargs) diff --git a/qubes/vm/__init__.py b/qubes/vm/__init__.py index 3a94a0f9..d499d6a6 100644 --- a/qubes/vm/__init__.py +++ b/qubes/vm/__init__.py @@ -93,7 +93,7 @@ class DeviceCollection(object): raise KeyError( 'device {!r} of class {} already attached to {!r}'.format( device, self._class, self._vm)) - self._vm.fire_event('device-pre-attached:{}'.format(self._class), device) + self._vm.fire_event_pre('device-pre-attached:{}'.format(self._class), device) self._set.add(device) self._vm.fire_event('device-attached:{}'.format(self._class), device) @@ -108,7 +108,7 @@ class DeviceCollection(object): raise KeyError( 'device {!r} of class {} not attached to {!r}'.format( device, self._class, self._vm)) - self._vm.fire_event('device-pre-detached:{}'.format(self._class), device) + self._vm.fire_event_pre('device-pre-detached:{}'.format(self._class), device) self._set.remove(device) self._vm.fire_event('device-detached:{}'.format(self._class), device)