qubes/events: fix event handling order

Events are divided into "pre" and "post" events. "Pre" events fire handlers in
MRO, "post" fire them in reverse.
This commit is contained in:
Wojtek Porczyk 2014-12-29 13:07:20 +01:00
parent 41fef46db2
commit 9fa3d60d0b
3 changed files with 48 additions and 16 deletions

View File

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

View File

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

View File

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