Transition from v0.1 XML playlists to v0.2 YAML playlists.
[hooke.git] / hooke / command_stack.py
index c1164732f687ebad51374afb0be99d97fbaa6836..234b3f3d85dfbd0ed7f42584c1d04f51517cf6be 100644 (file)
@@ -40,7 +40,7 @@ class CommandStack (list):
 
     Implement a dummy :meth:`execute_command` for testing.
     
-    >>> def execute_cmd(hooke, command_message):
+    >>> def execute_cmd(hooke, command_message, stack=None):
     ...     cm = command_message
     ...     print 'EXECUTE', cm.command, cm.arguments
     >>> c.execute_command = execute_cmd
@@ -80,13 +80,39 @@ class CommandStack (list):
      '<CommandMessage CommandB {param: D}>',
      '<CommandMessage CommandC {param: E}>']
 
+    The data-type is also pickleable, to ensure we can move it between
+    processes with :class:`multiprocessing.Queue`\s and easily save it
+    to disk.
+
+    >>> import pickle
+    >>> s = pickle.dumps(c)
+    >>> z = pickle.loads(s)
+    >>> print [repr(cm) for cm in c]  # doctest: +NORMALIZE_WHITESPACE
+    ['<CommandMessage CommandA {param: A}>',
+     '<CommandMessage CommandB {param: B}>',
+     '<CommandMessage CommandA {param: C}>',
+     '<CommandMessage CommandB {param: D}>',
+     '<CommandMessage CommandC {param: E}>']
+
     There is also a convenience function for clearing the stack.
 
     >>> c.clear()
     >>> print [repr(cm) for cm in c]
     []
     """
-    def execute(self, hooke):
+    def __getstate__(self):
+        state = [{'command':cm.command, 'arguments':cm.arguments}
+                for cm in self]
+        return state
+
+    def __setstate__(self, state):
+        self.clear()
+        for cm_state in state:
+            self.append(CommandMessage(
+                    command=cm_state['command'],
+                    arguments=cm_state['arguments']))
+
+    def execute(self, hooke, stack=False):
         """Execute a stack of commands.
 
         See Also
@@ -96,7 +122,7 @@ class CommandStack (list):
         for command_message in self:
             if self.filter(hooke, command_message) == True:
                 self.execute_command(
-                    hooke=hooke, command_message=command_message)
+                    hooke=hooke, command_message=command_message, stack=stack)
 
     def filter(self, hooke, command_message):
         """Return `True` to execute `command_message`, `False` otherwise.
@@ -105,9 +131,11 @@ class CommandStack (list):
         """
         return True
 
-    def execute_command(self, hooke, command_message):
+    def execute_command(self, hooke, command_message, stack=False):
+        arguments = dict(command_message.arguments)
+        arguments['stack'] = stack
         hooke.run_command(command=command_message.command,
-                          arguments=command_message.arguments)
+                          arguments=arguments)
 
     def clear(self):
         while len(self) > 0:
@@ -121,8 +149,23 @@ class FileCommandStack (CommandStack):
 
     def __init__(self, *args, **kwargs):
         super(FileCommandStack, self).__init__(*args, **kwargs)
-        self.name = None
+        self.name = self.path = None
+
+    def __getstate__(self):
+        command_stack = super(FileCommandStack, self).__getstate__()
+        state = {
+            'command stack': command_stack,
+            'path': self.path,
+            'name': self.name,
+            }
+        return state
+
+    def __setstate__(self, state):
+        super(FileCommandStack, self).__setstate__(
+            state.get('command stack', []))
+        self.name = state.get('name', None)
         self.path = None
+        self.set_path(state.get('path', None))
 
     def set_path(self, path):
         """Set the path (and possibly the name) of the command  stack.