[kupfer: 11/27] task: Redesign task API to be start with finish callback



commit e5630ace9b7b538b94bd94ded108cab18b985d8d
Author: Ulrik Sverdrup <ulrik sverdrup gmail com>
Date:   Tue Feb 9 15:52:50 2010 +0100

    task: Redesign task API to be start with finish callback

 kupfer/task.py |  121 ++++++++++++++++++++-----------------------------------
 1 files changed, 44 insertions(+), 77 deletions(-)
---
diff --git a/kupfer/task.py b/kupfer/task.py
index 7b48577..ae15a8a 100644
--- a/kupfer/task.py
+++ b/kupfer/task.py
@@ -1,3 +1,4 @@
+import sys
 import threading
 
 import gobject
@@ -6,51 +7,20 @@ from kupfer import scheduler, pretty
 
 class Task (object):
 	"""Represent a task that can be done in the background"""
-	def __init__(self):
-		self.name = None
+	def __init__(self, name=None):
+		self.name = name
 
 	def __unicode__(self):
 		return self.name
 
-	def is_thread(self):
-		return False
-
-	def run(self):
+	def start(self, finish_callback):
 		raise NotImplementedError
 
-class StepTask (Task):
-	"""A step task runs a part of the task in StepTask.step,
-	doing final cleanup in StepTask.finish, which is guaranteed to
-	be called regardless of exit or failure mode
-	"""
-	def step(self):
-		"""Do a small part of the task.
-		Return True to continue processing,
-		or a False value to finish.
-		"""
-		pass
-	def finish(self):
-		pass
-	def run(self):
-		try:
-			while True:
-				if not self.step():
-					break
-				yield
-		finally:
-			self.finish()
-
 class ThreadTask (Task):
 	"""Run in a thread"""
-	def __init__(self):
-		Task.__init__(self)
-
-	def is_thread(self):
-		return True
-
-	def _run_thread(self):
-		self.thread_do()
-		gobject.idle_add(self.thread_finish)
+	def __init__(self, name=None):
+		Task.__init__(self, name)
+		self.finish_callback = None
 
 	def thread_do(self):
 		"""Override this to run what should be done in the thread"""
@@ -62,59 +32,56 @@ class ThreadTask (Task):
 		"""
 		pass
 
-	def run(self):
-		thread = None
-		while True:
-			if not thread:
-				thread = threading.Thread(target=self._run_thread)
-				thread.start()
-			elif not thread.isAlive():
-				return
-			yield
+	def thread_finally(self, exc_info):
+		"""Always run at thread finish"""
+		pass
+
+	def _thread_finally(self, exc_info):
+		try:
+			self.thread_finally(exc_info)
+		finally:
+			self.finish_callback(self)
+
+	def _run_thread(self):
+		try:
+			self.thread_do()
+			gobject.idle_add(self.thread_finish)
+		except:
+			exc_info = sys.exc_info()
+			raise
+		else:
+			exc_info = None
+		finally:
+			gobject.idle_add(self._thread_finally, exc_info)
+
+	def start(self, finish_callback):
+		self.finish_callback = finish_callback
+		thread = threading.Thread(target=self._run_thread)
+		thread.start()
+
 
 class TaskRunner (pretty.OutputMixin):
 	"""Run Tasks in the idle Loop"""
 	def __init__(self, end_on_finish):
-		self.task_iters = {}
-		self.thread_iters = {}
-		self.idle_timer = scheduler.Timer(True)
+		self.tasks = set()
 		self.end_on_finish = end_on_finish
 		scheduler.GetScheduler().connect("finish", self._finish_cleanup)
 
+	def _task_finished(self, task):
+		self.output_debug("Task finished", task)
+		self.tasks.remove(task)
+
 	def add_task(self, task):
 		"""Register @task to be run"""
-		if task.is_thread():
-			# start thread
-			self.thread_iters[task] = task.run()
-			# run through all threads
-			self._step_tasks(self.thread_iters)
-		else:
-			self.task_iters[task] = task.run()
-		self._setup_timers()
-
-	def _setup_timers(self):
-		if self.task_iters:
-			self.idle_timer.set_idle(self._step_tasks, self.task_iters)
-
-	def _step_tasks(self, tasks):
-		for task, task_iter in tasks.items():
-			try:
-				task_iter.next()
-			except StopIteration:
-				self.output_debug("Task done:", task)
-				del tasks[task]
-		self._setup_timers()
+		self.tasks.add(task)
+		task.start(self._task_finished)
 
 	def _finish_cleanup(self, sched):
 		if self.end_on_finish:
-			self.task_iters.clear()
-			self.thread_iters.clear()
+			self.tasks.clear()
 			return
-		self._step_tasks(self.thread_iters)
-		if self.task_iters or self.thread_iters:
+		if self.tasks:
 			self.output_info("Uncompleted tasks:")
-			for task in self.task_iters:
-				self.output_info(task)
-			for task in self.thread_iters:
+			for task in self.tasks:
 				self.output_info(task)
 



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