[kupfer: 13/27] backgroundtask: Introduce background_loader decorator in helplib



commit db443f7983d91bc1304d85b9adb71c206a149a1f
Author: Karol BÄ?dkowski <karol bedkowsk+gh gmail com>
Date:   Tue Feb 9 22:40:18 2010 +0100

    backgroundtask: Introduce background_loader decorator in helplib

 kupfer/obj/helplib.py |   68 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 68 insertions(+), 0 deletions(-)
---
diff --git a/kupfer/obj/helplib.py b/kupfer/obj/helplib.py
index 992b2af..d00b69d 100644
--- a/kupfer/obj/helplib.py
+++ b/kupfer/obj/helplib.py
@@ -5,8 +5,13 @@ This module is a part of the program Kupfer, see the main program file for
 more information.
 """
 
+import functools
+import traceback
+
 import gio
 
+from kupfer import task
+
 class PicklingHelperMixin (object):
 	""" This pickling helper will define __getstate__/__setstate__
 	acting simply on the class dictionary; it is up to the inheriting
@@ -119,3 +124,66 @@ def reverse_action(action, rank=0):
 			return None
 	ReverseAction.__name__ = "Reverse" + action.__name__
 	return ReverseAction
+
+
+def background_loader(interval, delay=5, name=None, update_empty=False):
+	""" Run decorated function in background and cache it result.
+
+	@interval: time between runs function in seconds
+	@delay: optional delay to run background process in second
+	@name: optional name of the thread (for logging)
+	@update_empty: when function return empty result we may decide is cached
+	result should be updated or not. When update_empty==True result always
+	is stored.
+
+	Example:
+	@background_loader(interval=600)
+	def load():
+		return list(<items>)
+
+	Background process should be started by:
+		load.bind_and_start(<optional callback>))
+		- callback is launched after each update
+	or:
+		load.start()
+
+	If cache should be initially filled this may be done with:
+	load.fill_cache(<value>)
+
+	To force run background job call:
+	load.activate()
+	"""
+	return functools.partial(_BackgroundLoader, interval=interval,
+			delay=delay, name=name, update_empty=update_empty)
+
+class _BackgroundLoader (object):
+	def __init__(self, func, **kwargs):
+		self.cache = []
+		self.update_empty = kwargs.pop("update_empty", False)
+		self.job = task.BackgroundTaskRunner(func, **kwargs)
+		self.new_data_callback = None
+		self.job.result_callback = self._result_callback
+		self.job.error_callback = self._error_callback
+
+	def _result_callback(self, data):
+		if data or self.update_empty:
+			self.cache[:] = data
+			if self.new_data_callback:
+				self.new_data_callback()
+
+	def _error_callback(self, exc_info):
+		traceback.print_exception(*exc_info)
+
+	def fill_cache(self, data):
+		if data:
+			self.cache[:] = data
+
+	def bind_and_start(self, callback):
+		self.new_data_callback = callback
+		self.job.start()
+
+	def activate(self):
+		self.job.activate()
+
+	def __call__(self):
+		return iter(self.cache)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]