import queue
import threading


class ThreadedQueue(queue.Queue):
	"""Abstract implementation of a multi-threaded queue processor

	To implement a concrete multi-threaded queue processor based on ThreadedQueue, the following methods must be implemented:
	process_item(item)
	"""

	def __init__(self, threads, *args, **kwargs):
		"""Initialize instance dependencies and start the specified number of threads"""
		super().__init__(*args, **kwargs)

		self.exception = None
		self.is_running = False

		self.start(threads)

	def start(self, threads):
		"""Start the specified number of threads"""

		if not self.is_running:
			self.is_running = True

			for thread_count in range(threads):
				thread = threading.Thread(target=self.do_work, daemon=True)
				thread.start()

	def do_work(self):
		"""Repeatedly get items and process them"""

		while self.is_running:

			item = None
			try:
				item = self.get_nowait()
			except queue.Empty:
				pass

			if item is not None:
				try:
					self.process_item(item)
				except BaseException as e:
					self.stop(e)
				finally:
					self.task_done()

	def stop(self, exception=None):
		"""Stop all threads"""

		if self.is_running:
			self.is_running = False

		if exception is not None and self.exception is None:
			self.exception = exception


class WorkerQueue(ThreadedQueue):
	"""A concrete implementation of ThreadedQueue that processes worker tasks"""

	def add_item(self, target, target_args=None, target_kwargs=None, callback=None):
		"""Add an item to the queue"""

		self.put({
			'target':			target,
			'target_args':		target_args,
			'target_kwargs':	target_kwargs,
			'callback':			callback
			})

	def process_item(self, item):
		"""Process the specified item"""

		target = item['target']
		target_args = item['target_args']
		target_kwargs = item['target_kwargs']
		callback = item['callback']

		if target_args is None: target_args=[]
		if target_kwargs is None: target_kwargs={}
		output = target(*target_args, **target_kwargs)

		if callback is not None:
			callback(output)
@@ -1085,24 +1085,145 @@
 ask_done()%0A%0A
+%09def put(self, item):%0A%09%09%22%22%22Add item to the queue if the queue is running%22%22%22%0A%0A%09%09if self.is_running:%0A%09%09%09super().put(item)%0A%0A
 %09def stop(se
@@ -1404,16 +1404,235 @@
 ception%0A
+%09%09%0A%09%09self.clear()%0A%0A%09def clear(self):%0A%09%09%22%22%22Remove all pending items from the queue without processing them%22%22%22%0A%0A%09%09while not self.empty():%0A%09%09%09try:%0A%09%09%09%09self.get_nowait()%0A%09%09%09%09self.task_done()%0A%09%09%09except queue.Empty:%0A%09%09%09%09pass%0A
 %0A%0Aclass 

Fix issue with exceptions hanging Iterator (fixes #14)