← Back to team overview

zeitgeist team mailing list archive

[Merge] lp:~zeitgeist/zeitgeist/hooks into lp:zeitgeist

 

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