Markus Korn has proposed merging lp:~zeitgeist/zeitgeist/hooks into lp:zeitgeist.
Requested reviews: Zeitgeist Framework Team (zeitgeist) Related bugs: #604747 Hook before event deletions missing https://bugs.launchpad.net/bugs/604747 Fixed the "hook renaming"/"add missing hooks"-bug Renaming of existing hooks (API change!): * insert_event_hook() -> pre_insert_event() * get_event_hook() -> get_event() * delete_events_hook() -> post_delete_events() Added additional hooks: * added post_insert_event() * added pre_delete_events() changes to the tests: * added tests for all hooks -- https://code.launchpad.net/~zeitgeist/zeitgeist/hooks/+merge/31522 Your team Zeitgeist Framework Team is requested to review the proposed merge of lp:~zeitgeist/zeitgeist/hooks into lp:zeitgeist.
=== modified file '_zeitgeist/engine/extension.py' --- _zeitgeist/engine/extension.py 2010-07-01 08:04:55 +0000 +++ _zeitgeist/engine/extension.py 2010-08-02 10:23:57 +0000 @@ -49,7 +49,7 @@ def __init__(self, engine): self.engine = weakref.proxy(engine) - def insert_event_hook(self, event, sender): + def pre_insert_event(self, event, sender): """ Hook applied to all events before they are inserted into the log. The returned event is progressively passed through all @@ -69,7 +69,27 @@ """ return event - def get_event_hook(self, event, sender): + def post_insert_event(self, event, sender): + """ + Hook applied to all events after they are inserted into the + log. The returned event is progressively passed through all + extensions before the final result is inserted. + + To block an event completely simply return :const:`None`. + The event may also be modified or completely substituted for + another event. + + The default implementation of this method simply returns the + event as is. + + :param event: An :class:`Event <zeitgeist.datamodel.Event>` + instance + :param sender: The D-Bus bus name of the client + :returns: Nothing + """ + pass + + def get_event(self, event, sender): """ Hook applied to all events before they are returned to a client. The event returned from this method is progressively passed @@ -84,22 +104,32 @@ event as is. :param event: An :class:`Event <zeitgeist.datamodel.Event>` - instance + instance or :const:`None` :param sender: The D-Bus bus name of the client :returns: The filtered event instance as the client should see it """ return event - def delete_events_hook(self, ids, sender): + def post_delete_events(self, ids, sender): """ - Hook applied after events has been deleted from the log. + Hook applied after events have been deleted from the log. :param ids: A list of event ids for the events that has been deleted :param sender: The unique DBus name for the client triggering the delete :returns: Nothing """ pass + + def pre_delete_events(self, ids, sender): + """ + Hook applied before events are deleted from the log. + + :param ids: A list of event ids for the events that has been deleted + :param sender: The unique DBus name for the client triggering the delete + :returns: The filtered list of event ids which should be deleted + """ + return ids def get_extensions(): @@ -233,7 +263,7 @@ # FIXME: We need a stable iteration order for ext in self.__extensions.itervalues(): - event = ext.get_event_hook(event, sender) + event = ext.get_event(event, sender) if event is None: # The event has been blocked by # the extension pretend it's @@ -241,23 +271,36 @@ continue return event - def apply_delete_hooks(self, ids, sender): - # Apply extension filters if we have an event - - # FIXME: We need a stable iteration order - for ext in self.__extensions.itervalues(): - event = ext.delete_events_hook(ids, sender) - - - def apply_insert_hooks(self, event, sender): - # FIXME: We need a stable iteration order - for ext in self.__extensions.itervalues(): - event = ext.insert_event_hook(event, sender) + def apply_post_delete(self, ids, sender): + # Apply extension filters if we have an event + + # FIXME: We need a stable iteration order + for ext in self.__extensions.itervalues(): + event = ext.post_delete_events(ids, sender) + + def apply_pre_delete(self, ids, sender): + # Apply extension filters if we have an event + + # FIXME: We need a stable iteration order + for ext in self.__extensions.itervalues(): + ids = ext.pre_delete_events(ids, sender) + + return ids + + def apply_pre_insert(self, event, sender): + # FIXME: We need a stable iteration order + for ext in self.__extensions.itervalues(): + event = ext.pre_insert_event(event, sender) if event is None: # The event has been blocked by the extension return None return event + def apply_post_insert(self, event, sender): + # FIXME: We need a stable iteration order + for ext in self.__extensions.itervalues(): + event = ext.post_insert_event(event, sender) + def __len__(self): return len(self.__extensions) === modified file '_zeitgeist/engine/extensions/blacklist.py' --- _zeitgeist/engine/extensions/blacklist.py 2010-01-21 15:31:07 +0000 +++ _zeitgeist/engine/extensions/blacklist.py 2010-08-02 10:23:57 +0000 @@ -68,7 +68,7 @@ log.debug("No existing blacklist config found") self._blacklist = [] - def insert_event_hook(self, event, sender): + def pre_insert_event(self, event, sender): for tmpl in self._blacklist: if event.matches_template(tmpl): return None return event === modified file '_zeitgeist/engine/extensions/datasource_registry.py' --- _zeitgeist/engine/extensions/datasource_registry.py 2010-07-22 22:59:25 +0000 +++ _zeitgeist/engine/extensions/datasource_registry.py 2010-08-02 10:23:57 +0000 @@ -104,7 +104,7 @@ if datasource[DataSource.UniqueId] == unique_id: return datasource - def insert_event_hook(self, event, sender): + def pre_insert_event(self, event, sender): for (unique_id, bus_names) in self._running.iteritems(): if sender in bus_names: datasource = self._get_data_source(unique_id) === modified file '_zeitgeist/engine/main.py' --- _zeitgeist/engine/main.py 2010-07-28 20:10:07 +0000 +++ _zeitgeist/engine/main.py 2010-08-02 10:23:57 +0000 @@ -511,7 +511,7 @@ id = self.next_event_id() event[0][Event.Id] = id - event = self.extensions.apply_insert_hooks(event, sender) + event = self.extensions.apply_pre_insert(event, sender) if event is None: raise AssertionError("Inserting of event was blocked by an extension") elif not issubclass(type(event), OrigEvent): @@ -569,6 +569,9 @@ self._mimetype[subject.mimetype], subject.text, subject.storage)) + + self.extensions.apply_post_insert(event, sender) + except sqlite3.IntegrityError: # The event was already registered. # Rollback _last_event_id and return the ID of the original event @@ -606,6 +609,7 @@ return "" def delete_events (self, ids, sender=None): + ids = self.extensions.apply_pre_delete(ids, sender) # Extract min and max timestamps for deleted events self._cursor.execute(""" SELECT MIN(timestamp), MAX(timestamp) @@ -622,7 +626,7 @@ self._cursor.connection.commit() log.debug("Deleted %s" % map(int, ids)) - self.extensions.apply_delete_hooks(ids, sender) + self.extensions.apply_post_delete(ids, sender) return timestamps else: === modified file 'test/engine-extension-test.py' --- test/engine-extension-test.py 2010-07-22 09:29:31 +0000 +++ test/engine-extension-test.py 2010-08-02 10:23:57 +0000 @@ -68,14 +68,26 @@ class BlockAllInsertExtension(Extension): PUBLIC_METHODS = [] - - def insert_event_hook(self, event, sender): + insert_count = 0 + do_insert = True + + @classmethod + def pre_insert_event(cls, event, sender): + if cls.do_insert: + cls.do_insert = False + return event return None + @classmethod + def post_insert_event(cls, event, sender): + cls.insert_count += 1 + self.engine.extensions.load(BlockAllInsertExtension) ids = import_events("test/data/five_events.js", self.engine) - # all inserts where blocked, so each id is 0 to indicate this - self.assertEquals(filter(None, ids), []) + + # all but the first one events are blocked + self.assertEquals(filter(None, ids), [1]) + self.assertEquals(BlockAllInsertExtension.insert_count, 1) def testDeleteHook(self): @@ -84,14 +96,43 @@ del_ids = [] @classmethod - def delete_events_hook(self, del_ids, sender): - self.del_ids = del_ids + def pre_delete_events(cls, ids, sender): + return ids[:1] + + @classmethod + def post_delete_events(cls, del_ids, sender): + cls.del_ids = del_ids self.engine.extensions.load(DeleteAllInsertExtension) ids = import_events("test/data/five_events.js", self.engine) - # all inserts where blocked, so each id is 0 to indicate this - self.engine.delete_events([ids[1]]) - self.assertEquals(DeleteAllInsertExtension.del_ids, [ids[1]]) + + # we try to delete the first two events, but the engine will + # block the deletion of the seconds one + self.engine.delete_events(ids[:2]) + self.assertEquals(DeleteAllInsertExtension.del_ids, ids[:1]) + + def testGetHook(self): + + class BlockGetExtension(Extension): + PUBLIC_METHODS = [] + + @classmethod + def get_event(self, event, sender): + if event is not None and int(event.timestamp) > 130: + return None + return event + + self.engine.extensions.load(BlockGetExtension) + ids = import_events("test/data/five_events.js", self.engine) + + # request all events, but only the first event object + # will be returned, the other events are blocked by the extension + # and presented as `None` + events = self.engine.get_events(ids) + self.assertEqual(len(filter(lambda x: x is not None, events)), 1) + + + if __name__ == "__main__": unittest.main()
_______________________________________________ Mailing list: https://launchpad.net/~zeitgeist Post to : zeitgeist@lists.launchpad.net Unsubscribe : https://launchpad.net/~zeitgeist More help : https://help.launchpad.net/ListHelp