[kupfer: 5/53] commandexec: Allow passing down an ExecutionToken with Action.activate



commit 3d3acac48c5671773c8f566373865eac5c110b0a
Author: Ulrik Sverdrup <ulrik sverdrup gmail com>
Date:   Thu Mar 24 17:22:32 2011 +0100

    commandexec: Allow passing down an ExecutionToken with Action.activate
    
    Shift the model away from global state, and pass along a context
    object with each activate.
    
    To keep compatibility, an action has to define::
    
        def wants_context(self):
            return True
    
    And the action will receive an ExecutionToken as the ctx keyword
    argument in activate or activate-multiple::
    
        def activate(self, obj, iobj, ctx):
            pass

 kupfer/commandexec.py |   66 +++++++++++++++++++++++++++++++++++++++---------
 kupfer/obj/base.py    |    8 ++++++
 2 files changed, 61 insertions(+), 13 deletions(-)
---
diff --git a/kupfer/commandexec.py b/kupfer/commandexec.py
index 8e7f649..fe87edf 100644
--- a/kupfer/commandexec.py
+++ b/kupfer/commandexec.py
@@ -68,33 +68,40 @@ def _get_leaf_members(leaf):
 def _is_multiple(leaf):
 	return hasattr(leaf, "get_multiple_leaf_representation")
 
-def activate_action(obj, action, iobj):
+def _wants_context(action):
+	return action.wants_context()
+
+def activate_action(context, obj, action, iobj):
 	""" Activate @action in simplest manner """
+	kwargs = {}
+	if _wants_context(action):
+		kwargs['ctx'] = context
 	if not _is_multiple(obj) and not _is_multiple(iobj):
-		return _activate_action_single(obj, action, iobj)
+		return _activate_action_single(obj, action, iobj, kwargs)
 	else:
-		return _activate_action_multiple(obj, action, iobj)
+		return _activate_action_multiple(obj, action, iobj, kwargs)
 
-def _activate_action_single(obj, action, iobj):
+def _activate_action_single(obj, action, iobj, kwargs):
 	if action.requires_object():
-		ret = action.activate(obj, iobj)
+		ret = action.activate(obj, iobj, **kwargs)
 	else:
-		ret = action.activate(obj)
+		ret = action.activate(obj, **kwargs)
 	return ret
 
-def _activate_action_multiple(obj, action, iobj):
+def _activate_action_multiple(obj, action, iobj, kwargs):
 	if not hasattr(action, "activate_multiple"):
 		iobjs = (None, ) if iobj is None else _get_leaf_members(iobj)
 		return _activate_action_multiple_multiplied(_get_leaf_members(obj),
-				action, iobjs)
+				action, iobjs, kwargs)
 
 	if action.requires_object():
-		ret = action.activate_multiple(_get_leaf_members(obj), _get_leaf_members(iobj))
+		ret = action.activate_multiple(_get_leaf_members(obj),
+				_get_leaf_members(iobj), kwargs)
 	else:
-		ret = action.activate_multiple(_get_leaf_members(obj))
+		ret = action.activate_multiple(_get_leaf_members(obj), **kwargs)
 	return ret
 
-def _activate_action_multiple_multiplied(objs, action, iobjs):
+def _activate_action_multiple_multiplied(objs, action, iobjs, kwargs):
 	"""
 	Multiple dispatch by "mulitplied" invocation of the simple activation
 
@@ -103,7 +110,7 @@ def _activate_action_multiple_multiplied(objs, action, iobjs):
 	rets = []
 	for L in objs:
 		for I in iobjs:
-			ret = _activate_action_single(L, action, I)
+			ret = _activate_action_single(L, action, I, kwargs)
 			rets.append(ret)
 	ctx = DefaultActionExecutionContext()
 	ret = ctx._combine_action_result_multiple(action, rets)
@@ -124,6 +131,37 @@ def parse_action_result(action, ret):
 		res = RESULT_ASYNC
 	return res
 
+class ExecutionToken (object):
+	"""
+	A token object that an ``Action`` carries with it
+	from ``activate``.
+
+	Must be used for access to current execution context,
+	and to access the environment.
+	"""
+	def __init__(self, aectx, async_token, ui_ctx):
+		self._aectx = aectx
+		self._token = async_token
+		self._ui_ctx = ui_ctx
+
+	def register_late_result(self, result_object, show=True):
+		self._aectx.register_late_result(self._token, result_object, show=show)
+
+	def register_late_error(self, exc_info=None):
+		self._aectx.register_late_error(self._token, exc_info)
+
+	def delegated_run(self, *objs):
+		return self._aectx.run(*objs, delegate=True)
+
+	def get_environment_timestamp(self):
+		raise NotImplementedError
+
+	def get_environment_startup_notification_id(self):
+		raise NotImplementedError
+
+	def get_environment_screen(self):
+		raise NotImplementedError
+
 
 class ActionExecutionContext (gobject.GObject, pretty.OutputMixin):
 	"""
@@ -246,9 +284,11 @@ class ActionExecutionContext (gobject.GObject, pretty.OutputMixin):
 		if iobj is None and action.requires_object():
 			raise ActionExecutionError("%s requires indirect object" % action)
 
+		# The execution token object for the current invocation
+		execution_token = ExecutionToken(self, self.get_async_token(), None)
 		with self._error_conversion(obj, action, iobj):
 			with self._nesting():
-				ret = activate_action(obj, action, iobj)
+				ret = activate_action(execution_token, obj, action, iobj)
 
 		# remember last command, but not delegated commands.
 		if not delegate:
diff --git a/kupfer/obj/base.py b/kupfer/obj/base.py
index 61f6c60..4fd5da9 100644
--- a/kupfer/obj/base.py
+++ b/kupfer/obj/base.py
@@ -245,6 +245,14 @@ class Action (KupferObject):
 		"""
 		pass
 
+	def wants_context(self):
+		"""Return ``True`` if ``activate`` should receive the
+		ActionExecutionContext as the keyword argument context
+
+		Defaults to ``False`` in accordance with the old protocol
+		"""
+		return False
+
 	def is_factory(self):
 		"""Return whether action may return a result collection as a Source"""
 		return False



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