Tracked down problems saving playlists with loaded curves to numpy.dtype
[hooke.git] / hooke / playlist.py
index fdebc4042fa01b8b502ebea4053a94d687639b70..b996a5f7777c460de74268c528e1897c4e7a7eb2 100644 (file)
@@ -27,6 +27,24 @@ import os
 import os.path
 import types
 
+if False: # YAML dump debugging code
+    """To help isolate data types etc. that give YAML problems.
+
+    This is usually caused by external C modules (e.g. numpy) that
+    define new types (e.g. numpy.dtype) which YAML cannot inspect.
+    """
+    import yaml.representer
+    import sys
+    def ignore_aliases(data):
+        print data, type(data)
+        sys.stdout.flush()
+        if data in [None, ()]:
+            return True
+        if isinstance(data, (str, unicode, bool, int, float)):
+            return True
+    yaml.representer.SafeRepresenter.ignore_aliases = staticmethod(
+        ignore_aliases)
+
 import yaml
 from yaml.representer import RepresenterError
 
@@ -98,14 +116,15 @@ class NoteIndexList (list):
         return state
 
     def _assert_clean_state(self, owner, state):
-        return
         for k,v in state.items():
+            if k == 'drivers':  # HACK.  Need better driver serialization.
+                continue
             try:
-                yaml.safe_dump((k,v))
+                yaml.dump((k,v))
             except RepresenterError, e:
                 raise NotImplementedError(
-                    'cannot convert %s.%s = %s (%s) to safe YAML'
-                    % (owner.__class__.__name__, k, v, type(v)))
+                    'cannot convert %s.%s = %s (%s) to YAML\n%s'
+                    % (owner.__class__.__name__, k, v, type(v), e))
 
     def _setup_item(self, item):
         """Perform any required initialization before returning an item.
@@ -196,10 +215,9 @@ class Playlist (NoteIndexList):
         self._ignored_attrs.extend([
                 '_item_ignored_attrs', '_item_default_attrs',
                 '_loaded'])
-        self._item_ignored_attrs = []
+        self._item_ignored_attrs = ['data']
         self._item_default_attrs = {
             'command_stack': [],
-            'data': None,
             'driver': None,
             'info': {},
             'name': None,
@@ -382,11 +400,14 @@ class FilePlaylist (Playlist):
         - info: {note: The first curve}
           name: one
           path: curve/one
-        - command_stack:
-          - arguments: {arg 0: 0, arg 1: X}
-            command: command A
-          - arguments: {arg 0: 1, arg 1: Y}
-            command: command B
+        - command_stack: !!python/object/new:hooke.command_stack.CommandStack
+            listitems:
+            - !!python/object:hooke.engine.CommandMessage
+              arguments: {arg 0: 0, arg 1: X}
+              command: command A
+            - !!python/object:hooke.engine.CommandMessage
+              arguments: {arg 0: 1, arg 1: Y}
+              command: command B
           info: {attr with spaces: 'The second curve
         <BLANKLINE>
               with endlines'}
@@ -409,11 +430,14 @@ class FilePlaylist (Playlist):
         - info: {note: The first curve}
           name: one
           path: /path/to/curve/one
-        - command_stack:
-          - arguments: {arg 0: 0, arg 1: X}
-            command: command A
-          - arguments: {arg 0: 1, arg 1: Y}
-            command: command B
+        - command_stack: !!python/object/new:hooke.command_stack.CommandStack
+            listitems:
+            - !!python/object:hooke.engine.CommandMessage
+              arguments: {arg 0: 0, arg 1: X}
+              command: command A
+            - !!python/object:hooke.engine.CommandMessage
+              arguments: {arg 0: 1, arg 1: Y}
+              command: command B
           info: {attr with spaces: 'The second curve
         <BLANKLINE>
               with endlines'}
@@ -461,11 +485,14 @@ class FilePlaylist (Playlist):
         ... items:
         ... - info: {note: The first curve}
         ...   path: curve/one
-        ... - command_stack:
-        ...   - arguments: {arg 0: 0, arg 1: X}
-        ...     command: command A
-        ...   - arguments: {arg 0: 1, arg 1: Y}
-        ...     command: command B
+        ... - command_stack: !!python/object/new:hooke.command_stack.CommandStack
+        ...      listitems:
+        ...      - !!python/object:hooke.engine.CommandMessage
+        ...        arguments: {arg 0: 0, arg 1: X}
+        ...        command: command A
+        ...      - !!python/object:hooke.engine.CommandMessage
+        ...        arguments: {arg 0: 1, arg 1: Y}
+        ...        command: command B
         ...   info: {attr with spaces: 'The second curve
         ... 
         ...       with endlines'}
@@ -520,3 +547,19 @@ class FilePlaylist (Playlist):
             curve.set_hooke(hooke)
             if identify == True:
                 curve.identify(self.drivers)
+
+
+class Playlists (NoteIndexList):
+    """A :class:`NoteIndexList` of :class:`FilePlaylist`\s.
+    """
+    def __init__(self, *arg, **kwargs):
+        super(Playlists, self).__init__(*arg, **kwargs)
+
+    def _item_getstate(self, item):
+        assert isinstance(item, FilePlaylist), type(item)
+        return item.__getstate__()
+
+    def _item_setstate(self, state):
+        item = FilePlaylist(drivers=[])
+        item.__setstate__(state)
+        return item