Transition from v0.1 XML playlists to v0.2 YAML playlists.
authorW. Trevor King <wking@drexel.edu>
Sat, 21 Aug 2010 13:57:08 +0000 (09:57 -0400)
committerW. Trevor King <wking@drexel.edu>
Sat, 21 Aug 2010 13:57:08 +0000 (09:57 -0400)
All test/ tests pass except for tutorial.py and note.py, which take
forever to run.  I'm going to figure out what's going on there next.

Anyone with old playlist files can either upgrade by hand (the new
syntax is pretty simple, see the playlists under test/data/ for
examples), or use the automatic script
  contrib/upgrade_playlist_0p1.py
which converts the playlists automatically.  The output from the
upgrade script is, like most auto-generated files, less concise
than a hand coded playlist, but it will work just fine.

For an introduction to YAML, see
  http://www.yaml.orlg/
which contains links YAML libraries in a number of languages.  The
playlists are generated with PyYAML
  http://pyyaml.org/
which handles YAML 1.1
  http://yaml.org/spec/1.1/
The Hooke playlist format is pretty simple, so it shouldn't be too
strongly tied to any particular version of YAML, although I haven't
actually tested it with a 1.0 or 1.2 parser.

23 files changed:
contrib/upgrade_playlist_0p1.py [new file with mode: 0755]
hooke/command_stack.py
hooke/compat/minidom.py [deleted file]
hooke/curve.py
hooke/engine.py
hooke/playlist.py
hooke/plugin/note.py
hooke/plugin/playlist.py
test/curve_info.py
test/data/fclamp_hemingway/playlist.hkp
test/data/test.hkp
test/data/vclamp_jpk/playlist.hkp
test/data/vclamp_mfp3d/playlist.hkp
test/data/vclamp_picoforce/playlist.hkp
test/data/vclamp_wtk/playlist.hkp
test/flat_filter_playlist.py
test/hemingway_driver.py
test/jpk_driver.py
test/mfp3d_driver.py
test/multiple_curve_analysis.py
test/picoforce_driver.py
test/polymer_fit.py
test/wtk_driver.py

diff --git a/contrib/upgrade_playlist_0p1.py b/contrib/upgrade_playlist_0p1.py
new file mode 100755 (executable)
index 0000000..4a0cf80
--- /dev/null
@@ -0,0 +1,93 @@
+#!/usr/bin/python
+# Copyright
+
+"""Upgrade version 0.1 playlists (XML) to the current Hooke playlist
+file format.
+"""
+
+import sys
+import xml.dom.minidom
+
+import yaml
+
+from hooke.playlist import FilePlaylist
+
+
+class Converter (FilePlaylist):
+    def _restore_key(self, key):
+        """Restore keys encoded with :meth:`_clean_key`.
+        """
+        return key.replace(u'\u00B7', ' ')
+
+    def _from_xml_doc(self, doc, identify=True):
+        """Load a playlist from an :class:`xml.dom.minidom.Document`
+        instance.
+        """
+        root = doc.documentElement
+        for attribute,value in root.attributes.items():
+            attribute = self._restore_key(attribute)
+            if attribute == 'version':
+                assert value == '0.1', \
+                    'Cannot read v%s playlist with a v%s reader' \
+                    % (value, self.version)
+            elif attribute == 'index':
+                self._index = int(value)
+            else:
+                self.info[attribute] = value
+        for curve_element in doc.getElementsByTagName('curve'):
+            path = curve_element.getAttribute('path')
+            info = dict([(self._restore_key(key), value)
+                         for key,value in curve_element.attributes.items()])
+            info.pop('path')
+            self.append_curve_by_path(path, info, identify=identify)
+        self.jump(self._index) # ensure valid index
+
+    def from_string(self, string, identify=True):
+        u"""Load a playlist from a string.
+
+        Examples
+        --------
+
+        >>> string = '''<?xml version="1.0" encoding="utf-8"?>
+        ... <playlist index="1" note="An example playlist" version="0.1">
+        ...     <curve note="The first curve" path="../curve/one"/>
+        ...     <curve attr\xb7with\xb7spaces="The second curve&#xA;with endlines" path="../curve/two"/>
+        ... </playlist>
+        ... '''
+        >>> p = FilePlaylist(drivers=[],
+        ...                  path=os.path.join('path', 'to', 'my', 'playlist'))
+        >>> p.from_string(string, identify=False)
+        >>> p._index
+        1
+        >>> p.info
+        {u'note': u'An example playlist'}
+        >>> for curve in p:
+        ...     print curve.path
+        path/to/curve/one
+        path/to/curve/two
+        >>> p[-1].info['attr with spaces']
+        u'The second curve\\nwith endlines'
+        """
+        doc = xml.dom.minidom.parseString(string)
+        self._from_xml_doc(doc, identify=identify)
+
+    def load(self, path=None, identify=True, hooke=None):
+        """Load a playlist from a file.
+        """
+        self.set_path(path)
+        doc = xml.dom.minidom.parse(self.path)
+        self._from_xml_doc(doc, identify=identify)
+        #self._digest = self.digest()
+        for curve in self:
+            curve.set_hooke(hooke)
+
+
+if __name__ == '__main__':
+    if len(sys.argv) < 2:
+        print >> sys.stderr, 'usage: upgrade_playlist_0p1.py X.hkp [Y.hkp ...]'
+        sys.exit(1)
+
+    for path in sys.argv[1:]:
+        p = Converter(drivers=None, path=path)
+        p.load(identify=False)
+        p.save()
index 17a633ba954343996c6ef97be56ea3da6a12ac64..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,12 +80,38 @@ 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 __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.
 
@@ -123,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.
diff --git a/hooke/compat/minidom.py b/hooke/compat/minidom.py
deleted file mode 100644 (file)
index 01d3be0..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-# Copyright (C) 2010 W. Trevor King <wking@drexel.edu>
-#
-# This file is part of Hooke.
-#
-# Hooke is free software: you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# Hooke is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
-# Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with Hooke.  If not, see
-# <http://www.gnu.org/licenses/>.
-
-"""Dynamically patch :mod:`xml.dom.minidom`'s attribute value escaping.
-
-:meth:`xml.dom.minidom.Element.setAttribute` doesn't preform some
-character escaping (see the `Python bug`_ and `XML specs`_).
-Importing this module applies the suggested patch dynamically.
-
-.. _Python bug: http://bugs.python.org/issue5752
-.. _XML specs:
-  http://www.w3.org/TR/2000/WD-xml-c14n-20000119.html#charescaping
-"""
-
-import logging
-import xml.dom.minidom
-
-
-def _write_data(writer, data, isAttrib=False):
-    "Writes datachars to writer."
-    if isAttrib:
-        data = data.replace("\r", "&#xD;").replace("\n", "&#xA;")
-        data = data.replace("\t", "&#x9;").replace('"', "&quot;")
-    writer.write(data)
-xml.dom.minidom._write_data = _write_data
-
-def writexml(self, writer, indent="", addindent="", newl=""):
-    # indent = current indentation
-    # addindent = indentation to add to higher levels
-    # newl = newline string
-    writer.write(indent+"<" + self.tagName)
-
-    attrs = self._get_attributes()
-    a_names = attrs.keys()
-    a_names.sort()
-
-    for a_name in a_names:
-        writer.write(" %s=\"" % a_name)
-        _write_data(writer, attrs[a_name].value, isAttrib=True)
-        writer.write("\"")
-    if self.childNodes:
-        writer.write(">%s"%(newl))
-        for node in self.childNodes:
-            node.writexml(writer,indent+addindent,addindent,newl)
-        writer.write("%s</%s>%s" % (indent,self.tagName,newl))
-    else:
-        writer.write("/>%s"%(newl))
-# For an introduction to overriding instance methods, see
-#   http://irrepupavel.com/documents/python/instancemethod/
-instancemethod = type(xml.dom.minidom.Element.writexml)
-xml.dom.minidom.Element.writexml = instancemethod(
-    writexml, None, xml.dom.minidom.Element)
-
-logging.warn(
-    'monkey patched xml.dom.minidom.Element and ._write_data for issue5752')
index a87a7fd52b776d72d397cf2ed13f48461673d173..629e0a8bd5da99ef95e37e150aa6724fe1b28f8c 100644 (file)
@@ -165,13 +165,13 @@ class Curve (object):
     """
     def __init__(self, path, info=None):
         #the data dictionary contains: {name of data: list of data sets [{[x], [y]}]
-        self.path = path
+        self.name = None
+        self.set_path(path)
         self.driver = None
         self.data = None
         if info == None:
             info = {}
         self.info = info
-        self.name = os.path.basename(path)
         self.command_stack = CommandStack()
         self._hooke = None  # Hooke instance for Curve.load()
 
@@ -184,14 +184,29 @@ class Curve (object):
     def __repr__(self):
         return self.__str__()
 
+    def set_path(self, path):
+        self.path = path
+        if self.name == None and path != None:
+            self.name = os.path.basename(path)
+
     def __getstate__(self):
-        data = dict(self.__dict__)
-        del(data['_hooke'])
-        return data
+        state = dict(self.__dict__)
+        del(state['_hooke'])
+        dc = state['command_stack']
+        if hasattr(dc, '__getstate__'):
+            state['command_stack'] = dc.__getstate__()
+        return state
 
-    def __setstate__(self, data):
-        self._hooke = None
-        for key,value in data.items():
+    def __setstate__(self, state):
+        self.name = self._hooke = None
+        for key,value in state.items():
+            if key == 'path':
+                self.set_path(value)
+                continue
+            elif key == 'command_stack':
+                v = CommandStack()
+                v.__setstate__(value)
+                value = v
             setattr(self, key, value)
 
     def set_hooke(self, hooke=None):
index e024c737357f9abc8aa9d57110c1218d4b3dc2af..be4be5fecaf7b1024ca1d67d12bb7c9e327c5cc7 100644 (file)
@@ -97,6 +97,7 @@ class CommandEngine (object):
         be ready to receive the next :class:`QueueMessage`.
         """
         log = logging.getLogger('hooke')
+        log.debug('engine starting')
         while True:
             log.debug('engine waiting for command')
             msg = ui_to_command_queue.get()
index f8199d4a5a44429044b690cbfd4ff50b6695f7af..fdebc4042fa01b8b502ebea4053a94d687639b70 100644 (file)
@@ -26,10 +26,11 @@ import hashlib
 import os
 import os.path
 import types
-import xml.dom.minidom
+
+import yaml
+from yaml.representer import RepresenterError
 
 from . import curve as curve
-from .compat import minidom as minidom  # dynamically patch xml.sax.minidom
 from .util.itertools import reverse_enumerate
 
 
@@ -45,6 +46,7 @@ class NoteIndexList (list):
         self.name = name
         self.info = {}
         self._index = 0
+        self._set_ignored_attrs()
 
     def __str__(self):
         return str(self.__unicode__())
@@ -55,6 +57,56 @@ class NoteIndexList (list):
     def __repr__(self):
         return self.__str__()
 
+    def _set_ignored_attrs(self):
+        self._ignored_attrs = ['_ignored_attrs', '_default_attrs']
+        self._default_attrs = {
+            'info': {},
+            }
+
+    def __getstate__(self):
+        state = dict(self.__dict__)
+        for key in self._ignored_attrs:
+            if key in state:
+                del(state[key])
+        for key,value in self._default_attrs.items():
+            if key in state and state[key] == value:
+                del(state[key])
+        assert 'items' not in state
+        state['items'] = []
+        self._assert_clean_state(self, state)
+        for item in self:  # save curves and their attributes
+            item_state = self._item_getstate(item)
+            self._assert_clean_state(item, item_state)
+            state['items'].append(item_state)
+        return state
+
+    def __setstate__(self, state):
+        self._set_ignored_attrs()
+        for key,value in self._default_attrs.items():
+            setattr(self, key, value)
+        for key,value in state.items():
+            if key == 'items':
+                continue
+            setattr(self, key, value)
+        for item_state in state['items']:
+            self.append(self._item_setstate(item_state))
+
+    def _item_getstate(self, item):
+        return item
+
+    def _item_setstate(self, state):
+        return state
+
+    def _assert_clean_state(self, owner, state):
+        return
+        for k,v in state.items():
+            try:
+                yaml.safe_dump((k,v))
+            except RepresenterError, e:
+                raise NotImplementedError(
+                    'cannot convert %s.%s = %s (%s) to safe YAML'
+                    % (owner.__class__.__name__, k, v, type(v)))
+
     def _setup_item(self, item):
         """Perform any required initialization before returning an item.
         """
@@ -112,9 +164,14 @@ class NoteIndexList (list):
             yield item
         self._index = index
 
-    def filter(self, keeper_fn=lambda item:True, *args, **kwargs):
+    def filter(self, keeper_fn=lambda item:True, load_curves=True,
+               *args, **kwargs):
         c = copy.deepcopy(self)
-        for item in c.items(reverse=True):
+        if load_curves == True:
+            items = c.items(reverse=True)
+        else:
+            items = reversed(c)
+        for item in items: 
             if keeper_fn(item, *args, **kwargs) != True:
                 c.remove(item)
         try: # attempt to maintain the same current item
@@ -132,9 +189,42 @@ class Playlist (NoteIndexList):
     def __init__(self, drivers, name=None):
         super(Playlist, self).__init__(name=name)
         self.drivers = drivers
-        self._loaded = [] # List of loaded curves, see :meth:`._setup_item`.
         self._max_loaded = 100 # curves to hold in memory simultaneously.
 
+    def _set_ignored_attrs(self):
+        super(Playlist, self)._set_ignored_attrs()
+        self._ignored_attrs.extend([
+                '_item_ignored_attrs', '_item_default_attrs',
+                '_loaded'])
+        self._item_ignored_attrs = []
+        self._item_default_attrs = {
+            'command_stack': [],
+            'data': None,
+            'driver': None,
+            'info': {},
+            'name': None,
+            }
+        self._loaded = [] # List of loaded curves, see :meth:`._setup_item`.
+
+    def _item_getstate(self, item):
+        assert isinstance(item, curve.Curve), type(item)
+        state = item.__getstate__()
+        for key in self._item_ignored_attrs:
+            if key in state:
+                del(state[key])
+        for key,value in self._item_default_attrs.items():
+            if key in state and state[key] == value:
+                del(state[key])
+        return state
+
+    def _item_setstate(self, state):
+        for key,value in self._item_default_attrs.items():
+            if key not in state:
+                state[key] = value
+        item = curve.Curve(path=None)
+        item.__setstate__(state)
+        return item
+
     def append_curve_by_path(self, path, info=None, identify=True, hooke=None):
         path = os.path.normpath(path)
         c = curve.Curve(path, info=info)
@@ -161,28 +251,65 @@ class Playlist (NoteIndexList):
 class FilePlaylist (Playlist):
     """A file-backed :class:`Playlist`.
     """
-    version = '0.1'
+    version = '0.2'
 
     def __init__(self, drivers, name=None, path=None):
         super(FilePlaylist, self).__init__(drivers, name)
-        self.path = None
+        self.path = self._base_path = None
         self.set_path(path)
+        self._relative_curve_paths = True
+
+    def _set_ignored_attrs(self):
+        super(FilePlaylist, self)._set_ignored_attrs()
+        self._ignored_attrs.append('_digest')
         self._digest = None
-        self._ignored_keys = [
-            'experiment',  # class instance, not very exciting.
-            ]
+
+    def __getstate__(self):
+        state = super(FilePlaylist, self).__getstate__()
+        assert 'version' not in state, state
+        state['version'] = self.version
+        return state
+
+    def __setstate__(self, state):
+        assert('version') in state, state
+        version = state.pop('version')
+        assert version == FilePlaylist.version, (
+            'invalid version %s (%s) != %s (%s)'
+            % (version, type(version),
+               FilePlaylist.version, type(FilePlaylist.version)))
+        super(FilePlaylist, self).__setstate__(state)
+
+    def _item_getstate(self, item):
+        state = super(FilePlaylist, self)._item_getstate(item)
+        if state.get('path', None) != None:
+            path = os.path.abspath(os.path.expanduser(state['path']))
+            if self._relative_curve_paths == True:
+                path = os.path.relpath(path, self._base_path)
+            state['path'] = path
+        return state
+
+    def _item_setstate(self, state):
+        item = super(FilePlaylist, self)._item_setstate(state)
+        if 'path' in state:
+            item.set_path(os.path.join(self._base_path, state['path']))
+        return item
 
     def set_path(self, path):
-        if path != None:
+        if path == None:
+            if self._base_path == None:
+                self._base_path = os.getcwd()
+        else:
             if not path.endswith('.hkp'):
                 path += '.hkp'
             self.path = path
+            self._base_path = os.path.dirname(os.path.abspath(
+                os.path.expanduser(self.path)))
             if self.name == None:
                 self.name = os.path.basename(path)
 
     def append_curve_by_path(self, path, *args, **kwargs):
-        if self.path != None:
-            path = os.path.join(os.path.dirname(self.path), path)
+        if self._base_path != None:
+            path = os.path.join(self._base_path, path)
         super(FilePlaylist, self).append_curve_by_path(path, *args, **kwargs)
 
     def is_saved(self):
@@ -206,41 +333,20 @@ class FilePlaylist (Playlist):
         >>> c.info['note'] = 'The second curve'
         >>> p.append(c)
         >>> p.digest()
-        '\\\x14\x87\x88*q\xf8\xaa\xa7\x84f\x82\xa1S>\xfd3+\xd0o'
+        '\xa1\x1ax\xb1|\x84uA\xe4\x1d\xbf`\x004|\x82\xc2\xdd\xc1\x9e'
         """
         string = self.flatten()
         return hashlib.sha1(string).digest()
 
-    def _clean_key(self, key):
-        """Replace spaces in keys with \\u00B7 (middle dot).
-
-        This character is deemed unlikely to occur in keys to our
-        playlist and curve info dictionaries, while many keys have
-        spaces in them.
-
-        \\u00B7 is allowed in XML 1.0 as of the 5th edition.  See
-        the `4th edition errata`_ for details.
-
-        .. _4th edition errata:
-          http://www.w3.org/XML/xml-V10-4e-errata#E09
-        """
-        return key.replace(' ', u'\u00B7')
-
-    def _restore_key(self, key):
-        """Restore keys encoded with :meth:`_clean_key`.
-        """
-        return key.replace(u'\u00B7', ' ')
-
-    def flatten(self, absolute_paths=False):
+    def flatten(self):
         """Create a string representation of the playlist.
 
-        A playlist is an XML document with the following syntax::
+        A playlist is a YAML document with the following minimal syntax::
 
-            <?xml version="1.0" encoding="utf-8"?>
-            <playlist attribute="value">
-              <curve path="/my/file/path/"/ attribute="value" ...>
-              <curve path="...">
-            </playlist>
+            version: '0.2'
+            items:
+            - path: picoforce.000
+            - path: picoforce.001
 
         Relative paths are interpreted relative to the location of the
         playlist file.
@@ -248,6 +354,8 @@ class FilePlaylist (Playlist):
         Examples
         --------
 
+        >>> from .engine import CommandMessage
+
         >>> root_path = os.path.sep + 'path'
         >>> p = FilePlaylist(drivers=[],
         ...                  path=os.path.join(root_path, 'to','playlist'))
@@ -257,121 +365,140 @@ class FilePlaylist (Playlist):
         >>> p.append(c)
         >>> c = curve.Curve(os.path.join(root_path, 'to', 'curve', 'two'))
         >>> c.info['attr with spaces'] = 'The second curve\\nwith endlines'
+        >>> c.command_stack.extend([
+        ...         CommandMessage('command A', {'arg 0':0, 'arg 1':'X'}),
+        ...         CommandMessage('command B', {'arg 0':1, 'arg 1':'Y'}),
+        ...         ])
         >>> p.append(c)
-        >>> def _print(string):
-        ...     escaped_string = unicode(string, 'utf-8').encode('unicode escape')
-        ...     print escaped_string.replace('\\\\n', '\\n').replace('\\\\t', '\\t'),
-        >>> _print(p.flatten())  # doctest: +NORMALIZE_WHITESPACE +REPORT_UDIFF
-        <?xml version="1.0" encoding="utf-8"?>
-        <playlist index="0" note="An example playlist" version="0.1">
-           <curve note="The first curve" path="curve/one"/>
-           <curve attr\\xb7with\\xb7spaces="The second curve&#xA;with endlines" path="curve/two"/>
-        </playlist>
-        >>> _print(p.flatten(absolute_paths=True))  # doctest: +NORMALIZE_WHITESPACE +REPORT_UDIFF
-        <?xml version="1.0" encoding="utf-8"?>
-        <playlist index="0" note="An example playlist" version="0.1">
-           <curve note="The first curve" path="/path/to/curve/one"/>
-           <curve attr\\xb7with\\xb7spaces="The second curve&#xA;with endlines" path="/path/to/curve/two"/>
-        </playlist>
+        >>> print p.flatten()  # doctest: +REPORT_UDIFF
+        # Hooke playlist version 0.2
+        _base_path: /path/to
+        _index: 0
+        _max_loaded: 100
+        _relative_curve_paths: true
+        drivers: []
+        info: {note: An example playlist}
+        items:
+        - 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
+          info: {attr with spaces: 'The second curve
+        <BLANKLINE>
+              with endlines'}
+          name: two
+          path: curve/two
+        name: playlist.hkp
+        path: /path/to/playlist.hkp
+        version: '0.2'
+        <BLANKLINE>
+        >>> p._relative_curve_paths = False
+        >>> print p.flatten()  # doctest: +REPORT_UDIFF
+        # Hooke playlist version 0.2
+        _base_path: /path/to
+        _index: 0
+        _max_loaded: 100
+        _relative_curve_paths: false
+        drivers: []
+        info: {note: An example playlist}
+        items:
+        - 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
+          info: {attr with spaces: 'The second curve
+        <BLANKLINE>
+              with endlines'}
+          name: two
+          path: /path/to/curve/two
+        name: playlist.hkp
+        path: /path/to/playlist.hkp
+        version: '0.2'
+        <BLANKLINE>
         """
-        implementation = xml.dom.minidom.getDOMImplementation()
-        # create the document DOM object and the root element
-        doc = implementation.createDocument(None, 'playlist', None)
-        root = doc.documentElement
-        root.setAttribute('version', self.version) # store playlist version
-        root.setAttribute('index', str(self._index))
-        for key,value in self.info.items(): # save info variables
-            if (key in self._ignored_keys
-                or not isinstance(value, types.StringTypes)):
-                continue
-            root.setAttribute(self._clean_key(key), str(value))
-        if self.path == None:
-            base_path = os.getcwd()
-        else:
-            base_path = os.path.abspath(
-                os.path.expanduser(self.path))
-        for curve in self: # save curves and their attributes
-            curve_element = doc.createElement('curve')
-            root.appendChild(curve_element)
-            path = os.path.abspath(os.path.expanduser(curve.path))
-            if absolute_paths == False:
-                path = os.path.relpath(
-                    path,
-                    os.path.dirname(base_path))
-            curve_element.setAttribute('path', path)
-            for key,value in curve.info.items():
-                if (key in self._ignored_keys
-                    or not isinstance(value, types.StringTypes)):
-                    continue
-                curve_element.setAttribute(self._clean_key(key), str(value))
-        string = doc.toprettyxml(encoding='utf-8')
-        root.unlink() # break circular references for garbage collection
-        return string
-
-    def _from_xml_doc(self, doc, identify=True):
-        """Load a playlist from an :class:`xml.dom.minidom.Document`
-        instance.
-        """
-        root = doc.documentElement
-        for attribute,value in root.attributes.items():
-            attribute = self._restore_key(attribute)
-            if attribute == 'version':
-                assert value == self.version, \
-                    'Cannot read v%s playlist with a v%s reader' \
-                    % (value, self.version)
-            elif attribute == 'index':
-                self._index = int(value)
-            else:
-                self.info[attribute] = value
-        for curve_element in doc.getElementsByTagName('curve'):
-            path = curve_element.getAttribute('path')
-            info = dict([(self._restore_key(key), value)
-                         for key,value in curve_element.attributes.items()])
-            info.pop('path')
-            self.append_curve_by_path(path, info, identify=identify)
-        self.jump(self._index) # ensure valid index
-
-    def from_string(self, string, identify=True):
+        yaml_string = yaml.dump(self.__getstate__(), allow_unicode=True)
+        return ('# Hooke playlist version %s\n' % self.version) + yaml_string
+
+    def from_string(self, string):
         u"""Load a playlist from a string.
 
         Examples
         --------
 
-        >>> string = '''<?xml version="1.0" encoding="utf-8"?>
-        ... <playlist index="1" note="An example playlist" version="0.1">
-        ...     <curve note="The first curve" path="../curve/one"/>
-        ...     <curve attr\xb7with\xb7spaces="The second curve&#xA;with endlines" path="../curve/two"/>
-        ... </playlist>
+        Minimal example.
+
+        >>> string = '''# Hooke playlist version 0.2
+        ... version: '0.2'
+        ... items:
+        ... - path: picoforce.000
+        ... - path: picoforce.001
+        ... '''
+        >>> p = FilePlaylist(drivers=[],
+        ...                 path=os.path.join('/path', 'to', 'my', 'playlist'))
+        >>> p.from_string(string)
+        >>> for curve in p:
+        ...     print curve.path
+        /path/to/my/picoforce.000
+        /path/to/my/picoforce.001
+
+        More complicated example.
+
+        >>> string = '''# Hooke playlist version 0.2
+        ... _base_path: /path/to
+        ... _digest: null
+        ... _index: 1
+        ... _max_loaded: 100
+        ... _relative_curve_paths: true
+        ... info: {note: An example 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
+        ...   info: {attr with spaces: 'The second curve
+        ... 
+        ...       with endlines'}
+        ...   name: two
+        ...   path: curve/two
+        ... name: playlist.hkp
+        ... path: /path/to/playlist.hkp
+        ... version: '0.2'
         ... '''
         >>> p = FilePlaylist(drivers=[],
         ...                  path=os.path.join('path', 'to', 'my', 'playlist'))
-        >>> p.from_string(string, identify=False)
+        >>> p.from_string(string)
         >>> p._index
         1
         >>> p.info
-        {u'note': u'An example playlist'}
+        {'note': 'An example playlist'}
         >>> for curve in p:
-        ...     print curve.path
-        path/to/curve/one
-        path/to/curve/two
+        ...     print curve.name, curve.path
+        one /path/to/curve/one
+        two /path/to/curve/two
         >>> p[-1].info['attr with spaces']
-        u'The second curve\\nwith endlines'
+        'The second curve\\nwith endlines'
+        >>> type(p[-1].command_stack)
+        <class 'hooke.command_stack.CommandStack'>
+        >>> p[-1].command_stack  # doctest: +NORMALIZE_WHITESPACE
+        [<CommandMessage command A {arg 0: 0, arg 1: X}>,
+         <CommandMessage command B {arg 0: 1, arg 1: Y}>]
         """
-        doc = xml.dom.minidom.parseString(string)
-        self._from_xml_doc(doc, identify=identify)
-
-    def load(self, path=None, identify=True, hooke=None):
-        """Load a playlist from a file.
-        """
-        self.set_path(path)
-        doc = xml.dom.minidom.parse(self.path)
-        self._from_xml_doc(doc, identify=identify)
-        self._digest = self.digest()
-        for curve in self:
-            curve.set_hooke(hooke)
+        state = yaml.load(string)
+        self.__setstate__(state)
 
     def save(self, path=None, makedirs=True):
-        """Saves the playlist in a XML file.
+        """Saves the playlist to a YAML file.
         """
         self.set_path(path)
         dirname = os.path.dirname(self.path) or '.'
@@ -380,3 +507,16 @@ class FilePlaylist (Playlist):
         with open(self.path, 'w') as f:
             f.write(self.flatten())
             self._digest = self.digest()
+
+    def load(self, path=None, identify=True, hooke=None):
+        """Load a playlist from a file.
+        """
+        self.set_path(path)
+        with open(self.path, 'r') as f:
+            text = f.read()
+        self.from_string(text)
+        self._digest = self.digest()
+        for curve in self:
+            curve.set_hooke(hooke)
+            if identify == True:
+                curve.identify(self.drivers)
index 0d0bada88aa05104c13068d5ff7408c7db76c1cb..b31dfd350fc69e9d6a7f937386c653d11a901d63 100644 (file)
@@ -85,7 +85,7 @@ class NoteFilterCommand (FilterCommand):
     """
     def __init__(self, plugin):
         super(NoteFilterCommand, self).__init__(
-            plugin, name='note filter playlist')
+            plugin, name='note filter playlist', load_curves=False)
 
     def filter(self, curve, hooke, inqueue, outqueue, params):
         return 'note' in curve.info and curve.info['note'] != None
index fbd30fa28da62e0da12892eae8382c4f14c359a7..3b1d83754b16d9dc5d050ea8f1c5662fc8129e15 100644 (file)
@@ -393,9 +393,10 @@ class FilterCommand (PlaylistAddingCommand, PlaylistCommand):
     method of their subclass.  See, for example,
     :meth:`NoteFilterCommand.filter`.
     """
-    def __init__(self, plugin, name='filter playlist'):
+    def __init__(self, plugin, name='filter playlist', load_curves=True):
         super(FilterCommand, self).__init__(
             name=name, help=self.__doc__, plugin=plugin)
+        self._load_curves = load_curves
         if not hasattr(self, 'filter'):
             self.arguments.append(
                 Argument(name='filter', type='function', optional=False,
@@ -409,7 +410,8 @@ Function returning `True` for "good" curves.
             filter_fn = params['filter']
         else:
             filter_fn = self.filter
-        p = self._playlist(hooke, params).filter(filter_fn,
+        p = self._playlist(hooke, params).filter(
+            filter_fn, load_curves=self._load_curves,
             hooke=hooke, inqueue=inqueue, outqueue=outqueue, params=params)
         self._set_playlist(hooke, params, p)
         if hasattr(p, 'path') and p.path != None:
index 9ab0ce60f947248facd54a27815c175bc732b8fd..28b14f38723262a03866a59cc500fb75cad48065 100644 (file)
@@ -26,11 +26,11 @@ Success
 <BLANKLINE>
 >>> h = r.run_lines(h, ['curve_info']) # doctest: +ELLIPSIS, +REPORT_UDIFF
 name: picoforce.000
-path: test/data/picoforce.000
+path: .../test/data/picoforce.000
 experiment: <class 'hooke.experiment.VelocityClamp'>
 driver: <hooke.driver.picoforce.PicoForceDriver object at 0x...>
 filetype: picoforce
-note: 
+note: None
 blocks: 2
 block sizes: [(2048, 2), (2048, 2)]
 Success
index dbae686b84fe40d5842a402a7b93eedb4acde5e3..05966ab6c2a508e0685b3a907ba4c8536c13ec0b 100644 (file)
@@ -1,26 +1,27 @@
-<?xml version="1.0" encoding="utf-8"?>
-<playlist index="0" version="0.1">
-  <curve note="" path="20080428_a53t-0-0-10.dat"/>
-  <curve note="" path="20080428_a53t-0-0-31.dat"/>
-  <curve note="" path="20080428_a53t-0-0-43.dat"/>
-  <curve note="" path="20080428_a53t-0-2-2.dat"/>
-  <curve note="" path="20080428_a53t-0-2-3.dat"/>
-  <curve note="" path="20080428_a53t-0-4-28.dat"/>
-  <curve note="" path="20080428_a53t-0-9-7.dat"/>
-  <curve note="" path="20080428_a53t-1-0-14.dat"/>
-  <curve note="" path="20080428_a53t-1-2-2.dat"/>
-  <curve note="" path="20080428_a53t-1-4-16.dat"/>
-  <curve note="" path="20080428_a53t-1-4-28.dat"/>
-  <curve note="" path="20080428_a53t-1-6-20.dat"/>
-  <curve note="" path="20080428_a53t-1-8-10.dat"/>
-  <curve note="" path="20080428_a53t-1-9-10.dat"/>
-  <curve note="" path="20080428_a53t-1-9-12.dat"/>
-  <curve note="" path="20080428_a53t-1-9-13.dat"/>
-  <curve note="" path="20080428_a53t-1-9-24.dat"/>
-  <curve note="" path="fclamp_i27-0-0-42.dat"/>
-  <curve note="" path="fclamp_i27-0-1-35.dat"/>
-  <curve note="" path="fclamp_i27-1-5-17.dat"/>
-  <curve note="" path="fclamp_i27-2-1-4.dat"/>
-  <curve note="" path="fclamp_i27-3-4-17.dat"/>
-  <curve note="" path="fclamp_i27-5-1-6.dat"/>
-</playlist>
+# Hooke playlist version 0.2
+version: '0.2'
+name: Hemingway
+items:
+- path: 20080428_a53t-0-0-10.dat
+- path: 20080428_a53t-0-0-31.dat
+- path: 20080428_a53t-0-0-43.dat
+- path: 20080428_a53t-0-2-2.dat
+- path: 20080428_a53t-0-2-3.dat
+- path: 20080428_a53t-0-4-28.dat
+- path: 20080428_a53t-0-9-7.dat
+- path: 20080428_a53t-1-0-14.dat
+- path: 20080428_a53t-1-2-2.dat
+- path: 20080428_a53t-1-4-16.dat
+- path: 20080428_a53t-1-4-28.dat
+- path: 20080428_a53t-1-6-20.dat
+- path: 20080428_a53t-1-8-10.dat
+- path: 20080428_a53t-1-9-10.dat
+- path: 20080428_a53t-1-9-12.dat
+- path: 20080428_a53t-1-9-13.dat
+- path: 20080428_a53t-1-9-24.dat
+- path: fclamp_i27-0-0-42.dat
+- path: fclamp_i27-0-1-35.dat
+- path: fclamp_i27-1-5-17.dat
+- path: fclamp_i27-2-1-4.dat
+- path: fclamp_i27-3-4-17.dat
+- path: fclamp_i27-5-1-6.dat
index a88c68b504aee5e9ec72b6e26b55816cbe9bf31a..fb51f0812832128b5eb9aebb726ad71edfeb3d82 100644 (file)
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<playlist index="0" version="0.1">
-  <curve note="" path="picoforce.000"/>
-</playlist>
+# Hooke playlist version 0.2
+version: '0.2'
+items:
+- path: picoforce.000
index 323b20a19e0837874f419d5805d27177c5ba6ab0..7f3a90db0c10b3eb9033ce5645c82331b1a2f572 100644 (file)
@@ -1,6 +1,6 @@
-<?xml version="1.0" encoding="utf-8"?>
-<playlist index="0" version="0.1">
-  <curve note="" path="2009.04.23-15.15.47.jpk"/>
-  <curve note="" height_nominal_to_calibrated_calibration_file="default.cal"
-        path="2009.04.23-15.21.39.jpk"/>
-</playlist>
+# Hooke playlist version 0.2
+version: '0.2'
+name: JPK
+items:
+- path: 2009.04.23-15.15.47.jpk
+- path: 2009.04.23-15.21.39.jpk
index b3afa4005ab6667c8fd897c21860787883803493..3665bc7ed5fdee80090065415641cb123450cded 100644 (file)
@@ -1,29 +1,30 @@
-<?xml version="1.0" encoding="utf-8"?>
-<playlist index="0" version="0.1">
-  <curve note="" path="Line0004Point0000.ibw"/>
-  <curve note="" path="Line0004Point0001.ibw"/>
-  <curve note="" path="Line0004Point0002.ibw"/>
-  <curve note="" path="Line0004Point0003.ibw"/>
-  <curve note="" path="Line0004Point0004.ibw"/>
-  <curve note="" path="Line0004Point0005.ibw"/>
-  <curve note="" path="Line0004Point0006.ibw"/>
-  <curve note="" path="Line0004Point0007.ibw"/>
-  <curve note="" path="Line0004Point0008.ibw"/>
-  <curve note="" path="Line0004Point0009.ibw"/>
-  <curve note="" path="Line0004Point0010.ibw"/>
-  <curve note="" path="Line0004Point0011.ibw"/>
-  <curve note="" path="Line0004Point0012.ibw"/>
-  <curve note="" path="Line0004Point0013.ibw"/>
-  <curve note="" path="Line0004Point0014.ibw"/>
-  <curve note="" path="Line0004Point0015.ibw"/>
-  <curve note="" path="Line0004Point0016.ibw"/>
-  <curve note="" path="Line0004Point0017.ibw"/>
-  <curve note="" path="Line0004Point0018.ibw"/>
-  <curve note="" path="Line0004Point0019.ibw"/>
-  <curve note="" path="Image0238.ibw"/>
-  <curve note="" path="Image0255.ibw"/>
-  <curve note="" path="Image0360.ibw"/>
-  <curve note="" path="Image0365.ibw"/>
-  <curve note="" path="Image0386.ibw"/>
-  <curve note="" path="Image0396.ibw"/>
-</playlist>
+# Hooke playlist version 0.2
+version: '0.2'
+name: MFP3D
+items:
+- path: Line0004Point0000.ibw
+- path: Line0004Point0001.ibw
+- path: Line0004Point0002.ibw
+- path: Line0004Point0003.ibw
+- path: Line0004Point0004.ibw
+- path: Line0004Point0005.ibw
+- path: Line0004Point0006.ibw
+- path: Line0004Point0007.ibw
+- path: Line0004Point0008.ibw
+- path: Line0004Point0009.ibw
+- path: Line0004Point0010.ibw
+- path: Line0004Point0011.ibw
+- path: Line0004Point0012.ibw
+- path: Line0004Point0013.ibw
+- path: Line0004Point0014.ibw
+- path: Line0004Point0015.ibw
+- path: Line0004Point0016.ibw
+- path: Line0004Point0017.ibw
+- path: Line0004Point0018.ibw
+- path: Line0004Point0019.ibw
+- path: Image0238.ibw
+- path: Image0255.ibw
+- path: Image0360.ibw
+- path: Image0365.ibw
+- path: Image0386.ibw
+- path: Image0396.ibw
index fb10798a84b7cc9a3a961354e1a5a4bc79afde78..3fe3e11cd61aa44b41b148cebcf30d51e5d6d864 100644 (file)
-<?xml version="1.0" encoding="utf-8"?>
-<playlist index="0" version="0.1">
-  <curve note="" path="20071120a_i27_t33.100"/>
-  <curve note="" path="20071120a_i27_t33.101"/>
-  <curve note="" path="20071120a_i27_t33.102"/>
-  <curve note="" path="20071120a_i27_t33.103"/>
-  <curve note="" path="20071120a_i27_t33.104"/>
-  <curve note="" path="20071120a_i27_t33.105"/>
-  <curve note="" path="20071120a_i27_t33.106"/>
-  <curve note="" path="20071120a_i27_t33.107"/>
-  <curve note="" path="20071120a_i27_t33.108"/>
-  <curve note="" path="20071120a_i27_t33.109"/>
-  <curve note="" path="20071120a_i27_t33.110"/>
-  <curve note="" path="20071120a_i27_t33.111"/>
-  <curve note="" path="20071120a_i27_t33.112"/>
-  <curve note="" path="20071120a_i27_t33.113"/>
-  <curve note="" path="20071120a_i27_t33.114"/>
-  <curve note="" path="20071120a_i27_t33.115"/>
-  <curve note="" path="20071120a_i27_t33.116"/>
-  <curve note="" path="20071120a_i27_t33.117"/>
-  <curve note="" path="20071120a_i27_t33.118"/>
-  <curve note="" path="20071120a_i27_t33.119"/>
-  <curve note="" path="20071120a_i27_t33.120"/>
-  <curve note="" path="20071120a_i27_t33.121"/>
-  <curve note="" path="20071120a_i27_t33.122"/>
-  <curve note="" path="20071120a_i27_t33.123"/>
-  <curve note="" path="20071120a_i27_t33.124"/>
-  <curve note="" path="20071120a_i27_t33.125"/>
-  <curve note="" path="20071120a_i27_t33.126"/>
-  <curve note="" path="20071120a_i27_t33.127"/>
-  <curve note="" path="20071120a_i27_t33.128"/>
-  <curve note="" path="20071120a_i27_t33.129"/>
-  <curve note="" path="20071120a_i27_t33.130"/>
-  <curve note="" path="20071120a_i27_t33.131"/>
-  <curve note="" path="20071120a_i27_t33.132"/>
-  <curve note="" path="20071120a_i27_t33.133"/>
-  <curve note="" path="20071120a_i27_t33.134"/>
-  <curve note="" path="20071120a_i27_t33.135"/>
-  <curve note="" path="20071120a_i27_t33.136"/>
-  <curve note="" path="20071120a_i27_t33.137"/>
-  <curve note="" path="20071120a_i27_t33.138"/>
-  <curve note="" path="20071120a_i27_t33.139"/>
-  <curve note="" path="20071120a_i27_t33.140"/>
-  <curve note="" path="20071120a_i27_t33.141"/>
-  <curve note="" path="20071120a_i27_t33.142"/>
-  <curve note="" path="20071120a_i27_t33.143"/>
-  <curve note="" path="20071120a_i27_t33.144"/>
-  <curve note="" path="20071120a_i27_t33.145"/>
-  <curve note="" path="20071120a_i27_t33.146"/>
-  <curve note="" path="20071120a_i27_t33.147"/>
-  <curve note="" path="20071120a_i27_t33.148"/>
-  <curve note="" path="20071120a_i27_t33.149"/>
-  <curve note="" path="20071120a_i27_t33.150"/>
-  <curve note="" path="20071120a_i27_t33.151"/>
-  <curve note="" path="20071120a_i27_t33.152"/>
-  <curve note="" path="20071120a_i27_t33.153"/>
-  <curve note="" path="20071120a_i27_t33.154"/>
-  <curve note="" path="20071120a_i27_t33.155"/>
-  <curve note="" path="20071120a_i27_t33.156"/>
-  <curve note="" path="20071120a_i27_t33.157"/>
-  <curve note="" path="20071120a_i27_t33.158"/>
-  <curve note="" path="20071120a_i27_t33.159"/>
-  <curve note="" path="20071120a_i27_t33.160"/>
-  <curve note="" path="20071120a_i27_t33.161"/>
-  <curve note="" path="20071120a_i27_t33.162"/>
-  <curve note="" path="20071120a_i27_t33.163"/>
-  <curve note="" path="20071120a_i27_t33.164"/>
-  <curve note="" path="20071120a_i27_t33.165"/>
-  <curve note="" path="20071120a_i27_t33.166"/>
-  <curve note="" path="20071120a_i27_t33.167"/>
-  <curve note="" path="20071120a_i27_t33.168"/>
-  <curve note="" path="20071120a_i27_t33.169"/>
-  <curve note="" path="20071120a_i27_t33.170"/>
-  <curve note="" path="20071120a_i27_t33.171"/>
-  <curve note="" path="20071120a_i27_t33.172"/>
-  <curve note="" path="20071120a_i27_t33.173"/>
-  <curve note="" path="20071120a_i27_t33.174"/>
-  <curve note="" path="20071120a_i27_t33.175"/>
-  <curve note="" path="20071120a_i27_t33.176"/>
-  <curve note="" path="20071120a_i27_t33.177"/>
-  <curve note="" path="20071120a_i27_t33.178"/>
-  <curve note="" path="20071120a_i27_t33.179"/>
-  <curve note="" path="20071120a_i27_t33.180"/>
-  <curve note="" path="20071120a_i27_t33.181"/>
-  <curve note="" path="20071120a_i27_t33.182"/>
-  <curve note="" path="20071120a_i27_t33.183"/>
-  <curve note="" path="20071120a_i27_t33.184"/>
-  <curve note="" path="20071120a_i27_t33.185"/>
-  <curve note="" path="20071120a_i27_t33.186"/>
-  <curve note="" path="20071120a_i27_t33.187"/>
-  <curve note="" path="20071120a_i27_t33.188"/>
-  <curve note="" path="20071120a_i27_t33.189"/>
-  <curve note="" path="20071120a_i27_t33.190"/>
-  <curve note="" path="20071120a_i27_t33.191"/>
-  <curve note="" path="20071120a_i27_t33.192"/>
-  <curve note="" path="20071120a_i27_t33.193"/>
-  <curve note="" path="20071120a_i27_t33.194"/>
-  <curve note="" path="20071120a_i27_t33.195"/>
-  <curve note="" path="20071120a_i27_t33.196"/>
-  <curve note="" path="20071120a_i27_t33.197"/>
-  <curve note="" path="20071120a_i27_t33.198"/>
-  <curve note="" path="20071120a_i27_t33.199"/>
-  <curve note="" path="0x06130001"/>
-  <curve note="" path="0x07200000"/>
-</playlist>
+# Hooke playlist version 0.2
+version: '0.2'
+name: PicoForce
+items:
+- path: 20071120a_i27_t33.100
+- path: 20071120a_i27_t33.101
+- path: 20071120a_i27_t33.102
+- path: 20071120a_i27_t33.103
+- path: 20071120a_i27_t33.104
+- path: 20071120a_i27_t33.105
+- path: 20071120a_i27_t33.106
+- path: 20071120a_i27_t33.107
+- path: 20071120a_i27_t33.108
+- path: 20071120a_i27_t33.109
+- path: 20071120a_i27_t33.110
+- path: 20071120a_i27_t33.111
+- path: 20071120a_i27_t33.112
+- path: 20071120a_i27_t33.113
+- path: 20071120a_i27_t33.114
+- path: 20071120a_i27_t33.115
+- path: 20071120a_i27_t33.116
+- path: 20071120a_i27_t33.117
+- path: 20071120a_i27_t33.118
+- path: 20071120a_i27_t33.119
+- path: 20071120a_i27_t33.120
+- path: 20071120a_i27_t33.121
+- path: 20071120a_i27_t33.122
+- path: 20071120a_i27_t33.123
+- path: 20071120a_i27_t33.124
+- path: 20071120a_i27_t33.125
+- path: 20071120a_i27_t33.126
+- path: 20071120a_i27_t33.127
+- path: 20071120a_i27_t33.128
+- path: 20071120a_i27_t33.129
+- path: 20071120a_i27_t33.130
+- path: 20071120a_i27_t33.131
+- path: 20071120a_i27_t33.132
+- path: 20071120a_i27_t33.133
+- path: 20071120a_i27_t33.134
+- path: 20071120a_i27_t33.135
+- path: 20071120a_i27_t33.136
+- path: 20071120a_i27_t33.137
+- path: 20071120a_i27_t33.138
+- path: 20071120a_i27_t33.139
+- path: 20071120a_i27_t33.140
+- path: 20071120a_i27_t33.141
+- path: 20071120a_i27_t33.142
+- path: 20071120a_i27_t33.143
+- path: 20071120a_i27_t33.144
+- path: 20071120a_i27_t33.145
+- path: 20071120a_i27_t33.146
+- path: 20071120a_i27_t33.147
+- path: 20071120a_i27_t33.148
+- path: 20071120a_i27_t33.149
+- path: 20071120a_i27_t33.150
+- path: 20071120a_i27_t33.151
+- path: 20071120a_i27_t33.152
+- path: 20071120a_i27_t33.153
+- path: 20071120a_i27_t33.154
+- path: 20071120a_i27_t33.155
+- path: 20071120a_i27_t33.156
+- path: 20071120a_i27_t33.157
+- path: 20071120a_i27_t33.158
+- path: 20071120a_i27_t33.159
+- path: 20071120a_i27_t33.160
+- path: 20071120a_i27_t33.161
+- path: 20071120a_i27_t33.162
+- path: 20071120a_i27_t33.163
+- path: 20071120a_i27_t33.164
+- path: 20071120a_i27_t33.165
+- path: 20071120a_i27_t33.166
+- path: 20071120a_i27_t33.167
+- path: 20071120a_i27_t33.168
+- path: 20071120a_i27_t33.169
+- path: 20071120a_i27_t33.170
+- path: 20071120a_i27_t33.171
+- path: 20071120a_i27_t33.172
+- path: 20071120a_i27_t33.173
+- path: 20071120a_i27_t33.174
+- path: 20071120a_i27_t33.175
+- path: 20071120a_i27_t33.176
+- path: 20071120a_i27_t33.177
+- path: 20071120a_i27_t33.178
+- path: 20071120a_i27_t33.179
+- path: 20071120a_i27_t33.180
+- path: 20071120a_i27_t33.181
+- path: 20071120a_i27_t33.182
+- path: 20071120a_i27_t33.183
+- path: 20071120a_i27_t33.184
+- path: 20071120a_i27_t33.185
+- path: 20071120a_i27_t33.186
+- path: 20071120a_i27_t33.187
+- path: 20071120a_i27_t33.188
+- path: 20071120a_i27_t33.189
+- path: 20071120a_i27_t33.190
+- path: 20071120a_i27_t33.191
+- path: 20071120a_i27_t33.192
+- path: 20071120a_i27_t33.193
+- path: 20071120a_i27_t33.194
+- path: 20071120a_i27_t33.195
+- path: 20071120a_i27_t33.196
+- path: 20071120a_i27_t33.197
+- path: 20071120a_i27_t33.198
+- path: 20071120a_i27_t33.199
+- path: '0x06130001'
+- path: '0x07200000'
index b5797222fc64ed0eeb3a7147c8416c02f6a40ed9..766a36304510154ae5cbbb43c7eca231b530e6d6 100644 (file)
@@ -1,33 +1,34 @@
-<?xml version="1.0" encoding="utf-8"?>
-<playlist index="0" version="0.1">
-  <curve note="" path="unfold/20100504/20100504144209_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144221_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144231_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144239_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144246_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144252_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144258_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144304_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144310_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144335_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144353_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144405_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144415_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144423_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144430_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144436_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144442_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144448_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144454_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144519_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144537_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144549_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144559_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144607_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144614_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144620_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144626_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144632_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144638_unfold"/>
-  <curve note="" path="unfold/20100504/20100504144703_unfold"/>
-</playlist>
+# Hooke playlist version 0.2
+version: '0.2'
+name: WTK
+items:
+- path: unfold/20100504/20100504144209_unfold
+- path: unfold/20100504/20100504144221_unfold
+- path: unfold/20100504/20100504144231_unfold
+- path: unfold/20100504/20100504144239_unfold
+- path: unfold/20100504/20100504144246_unfold
+- path: unfold/20100504/20100504144252_unfold
+- path: unfold/20100504/20100504144258_unfold
+- path: unfold/20100504/20100504144304_unfold
+- path: unfold/20100504/20100504144310_unfold
+- path: unfold/20100504/20100504144335_unfold
+- path: unfold/20100504/20100504144353_unfold
+- path: unfold/20100504/20100504144405_unfold
+- path: unfold/20100504/20100504144415_unfold
+- path: unfold/20100504/20100504144423_unfold
+- path: unfold/20100504/20100504144430_unfold
+- path: unfold/20100504/20100504144436_unfold
+- path: unfold/20100504/20100504144442_unfold
+- path: unfold/20100504/20100504144448_unfold
+- path: unfold/20100504/20100504144454_unfold
+- path: unfold/20100504/20100504144519_unfold
+- path: unfold/20100504/20100504144537_unfold
+- path: unfold/20100504/20100504144549_unfold
+- path: unfold/20100504/20100504144559_unfold
+- path: unfold/20100504/20100504144607_unfold
+- path: unfold/20100504/20100504144614_unfold
+- path: unfold/20100504/20100504144620_unfold
+- path: unfold/20100504/20100504144626_unfold
+- path: unfold/20100504/20100504144632_unfold
+- path: unfold/20100504/20100504144638_unfold
+- path: unfold/20100504/20100504144703_unfold
index dfd94a1ee550d298b8b849ca864fc6e3d34f75a6..d84f19c69b333efa409809e533b86cb1b06a1188 100644 (file)
@@ -21,7 +21,7 @@
 >>> h = Hooke()
 >>> r = HookeRunner()
 >>> h = r.run_lines(h, ['load_playlist test/data/vclamp_picoforce/playlist']) # doctest: +ELLIPSIS
-<FilePlaylist playlist.hkp>
+<FilePlaylist PicoForce>
 Success
 <BLANKLINE>
 >>> h = r.run_lines(h, ['flat_filter_playlist --distance_column "z piezo (m)" --deflection_column "deflection (m)"']) # doctest: +ELLIPSIS
index 374af169193ac62283f185bd21dc7e9e0af166d1..3ac273b70418d629886d801784ec486a655364a5 100644 (file)
 >>> r = HookeRunner()
 >>> playlist = os.path.join('test', 'data', 'fclamp_hemingway', 'playlist')
 >>> h = r.run_lines(h, ['load_playlist ' + playlist]) # doctest: +ELLIPSIS
-<FilePlaylist playlist.hkp>
+<FilePlaylist Hemingway>
 Success
 <BLANKLINE>
 >>> h = r.run_lines(h, ['curve_info']) # doctest: +ELLIPSIS, +REPORT_UDIFF
 name: 20080428_a53t-0-0-10.dat
-path: test/data/fclamp_hemingway/20080428_a53t-0-0-10.dat
+path: .../test/data/fclamp_hemingway/20080428_a53t-0-0-10.dat
 experiment: <class 'hooke.experiment.ForceClamp'>
 driver: <hooke.driver.hemingway.HemingwayDriver object at 0x...>
 filetype: hemingway
-note: 
+note: None
 blocks: 1
 block sizes: [(14798, 5)]
 Success
index 2515273c5efc9e4f0750bcc48ecb5499ff6a5c09..8261c7e27994694c6e1ed3dab1ff46bbfc53c88d 100644 (file)
 >>> r = HookeRunner()
 >>> playlist = os.path.join('test', 'data', 'vclamp_jpk', 'playlist')
 >>> h = r.run_lines(h, ['load_playlist ' + playlist]) # doctest: +ELLIPSIS
-<FilePlaylist playlist.hkp>
+<FilePlaylist JPK>
 Success
 <BLANKLINE>
 >>> h = r.run_lines(h, ['curve_info']) # doctest: +ELLIPSIS, +REPORT_UDIFF
 name: 2009.04.23-15.15.47.jpk
-path: test/data/vclamp_jpk/2009.04.23-15.15.47.jpk
-experiment: None
+path: .../test/data/vclamp_jpk/2009.04.23-15.15.47.jpk
+experiment: <class 'hooke.experiment.VelocityClamp'>
 driver: <hooke.driver.jpk.JPKDriver object at 0x...>
-filetype: None
-note: 
+filetype: jpk
+note: None
 blocks: 2
 block sizes: [(4096, 6), (4096, 4)]
 Success
 <BLANKLINE>
-
-Load the second curve, to test calibration file overriding.
-
->>> h = r.run_lines(h, ['next_curve'])
-Success
-<BLANKLINE>
->>> h = r.run_lines(h, ['curve_info']) # doctest: +ELLIPSIS, +REPORT_UDIFF
-name: 2009.04.23-15.21.39.jpk
-path: test/data/vclamp_jpk/2009.04.23-15.21.39.jpk
-experiment: None
-driver: <hooke.driver.jpk.JPKDriver object at 0x...>
-filetype: None
-note: 
-blocks: 3
-block sizes: [(4096, 6), (2048, 3), (4096, 4)]
-Success
-<BLANKLINE>
 """
index ba9a3b87bb50537edcfc44f2a4e026e336f823d4..cefb85176789327d664f2ea71eeb68f641cd7f93 100644 (file)
 >>> r = HookeRunner()
 >>> playlist = os.path.join('test', 'data', 'vclamp_mfp3d', 'playlist')
 >>> h = r.run_lines(h, ['load_playlist ' + playlist])
-<FilePlaylist playlist.hkp>
+<FilePlaylist MFP3D>
 Success
 <BLANKLINE>
 >>> h = r.run_lines(h, ['curve_info']) # doctest: +ELLIPSIS, +REPORT_UDIFF
 name: Line0004Point0000.ibw
-path: test/data/vclamp_mfp3d/Line0004Point0000.ibw
+path: .../test/data/vclamp_mfp3d/Line0004Point0000.ibw
 experiment: <class 'hooke.experiment.VelocityClamp'>
 driver: <hooke.driver.mfp3d.MFP3DDriver object at 0x...>
 filetype: mfp3d
-note: 
-blocks: 2
-block sizes: [(1091, 2), (0, 2)]
+note: None
+blocks: 3
+block sizes: [(491, 2), (497, 2), (105, 2)]
 Success
 <BLANKLINE>
 
-Also checkout a newer Image* file
+Also checkout a newer Image* file.
 
 >>> h = r.run_lines(h, ['previous_curve'])
 Success
 <BLANKLINE>
 >>> h = r.run_lines(h, ['curve_info']) # doctest: +ELLIPSIS, +REPORT_UDIFF
 name: Image0396.ibw
-path: test/data/vclamp_mfp3d/Image0396.ibw
+path: .../test/data/vclamp_mfp3d/Image0396.ibw
 experiment: <class 'hooke.experiment.VelocityClamp'>
 driver: <hooke.driver.mfp3d.MFP3DDriver object at 0x...>
 filetype: mfp3d
-note: 
-blocks: 2
-block sizes: [(1006, 3), (0, 3)]
+note: None
+blocks: 3
+block sizes: [(506, 3), (6, 3), (496, 3)]
 Success
 <BLANKLINE>
 """
index d7c82c604ea9aed66ba04ffbb875d12675a1d679..dd5d126a8ea7f78c657d9330e9a57aa61d08dcbd 100644 (file)
@@ -24,7 +24,7 @@
 Setup a playlist to act on.
 
 >>> h = r.run_lines(h, ['load_playlist test/data/vclamp_picoforce/playlist'])
-<FilePlaylist playlist.hkp>
+<FilePlaylist PicoForce>
 Success
 <BLANKLINE>
 
index ffe823c1cd64b7e2cf9489ce8403cf8efcfee943..d36aa180e545755874ce1ce0517b5b4574e0e141 100644 (file)
 >>> r = HookeRunner()
 >>> playlist = os.path.join('test', 'data', 'vclamp_picoforce', 'playlist')
 >>> h = r.run_lines(h, ['load_playlist ' + playlist])
-<FilePlaylist playlist.hkp>
+<FilePlaylist PicoForce>
 Success
 <BLANKLINE>
 >>> h = r.run_lines(h, ['curve_info']) # doctest: +ELLIPSIS, +REPORT_UDIFF
 name: 20071120a_i27_t33.100
-path: test/data/vclamp_picoforce/20071120a_i27_t33.100
+path: .../test/data/vclamp_picoforce/20071120a_i27_t33.100
 experiment: <class 'hooke.experiment.VelocityClamp'>
 driver: <hooke.driver.picoforce.PicoForceDriver object at 0x...>
 filetype: picoforce
-note: 
+note: None
 blocks: 2
 block sizes: [(2048, 2), (2048, 2)]
 Success
@@ -45,11 +45,11 @@ Success
 <BLANKLINE>
 >>> h = r.run_lines(h, ['curve_info']) # doctest: +ELLIPSIS, +REPORT_UDIFF
 name: 0x07200000
-path: test/data/vclamp_picoforce/0x07200000
+path: .../test/data/vclamp_picoforce/0x07200000
 experiment: <class 'hooke.experiment.VelocityClamp'>
 driver: <hooke.driver.picoforce.PicoForceDriver object at 0x...>
 filetype: picoforce
-note: 
+note: None
 blocks: 2
 block sizes: [(512, 2), (512, 2)]
 Success
@@ -59,11 +59,11 @@ Success
 <BLANKLINE>
 >>> h = r.run_lines(h, ['curve_info']) # doctest: +ELLIPSIS, +REPORT_UDIFF
 name: 0x06130001
-path: test/data/vclamp_picoforce/0x06130001
+path: .../test/data/vclamp_picoforce/0x06130001
 experiment: <class 'hooke.experiment.VelocityClamp'>
 driver: <hooke.driver.picoforce.PicoForceDriver object at 0x...>
 filetype: picoforce
-note: 
+note: None
 blocks: 2
 block sizes: [(2048, 2), (2048, 2)]
 Success
index fe5ccc76a26e09bb07c89ed84c7463de16713402..c20ecd7b56cfe49b8c7c5a8897c48348bc5af99b 100644 (file)
@@ -84,11 +84,11 @@ Data([[ NaN,  NaN],
        [ NaN,  NaN],
        [ NaN,  NaN]])
 >>> retract[1097:1103,-2:]  # doctest: +ELLIPSIS
-Data([[             NaN,   5.234...e-10],
-       [             NaN,   5.612...e-10],
-       [             NaN,   6.132...e-10],
-       [             NaN,   6.292...e-10],
-       [             NaN,   7.105...e-10],
+Data([[             NaN,   5.2...e-10],
+       [             NaN,   5...e-10],
+       [             NaN,   6.1...e-10],
+       [             NaN,   6.2...e-10],
+       [             NaN,   7...e-10],
        [             NaN,              NaN]])
 >>> retract[-5:,-2:]
 Data([[ NaN,  NaN],
index 0953a3a3232ac7506304ead1ac3c19e26283d244..f34907caef8122b42bff302fd4eaaed4ddf1bcf8 100644 (file)
@@ -38,16 +38,16 @@ Proceed with the test itself.
 >>> r = HookeRunner()
 >>> playlist = os.path.join('test', 'data', 'vclamp_wtk', 'playlist')
 >>> h = r.run_lines(h, ['load_playlist ' + playlist])
-<FilePlaylist playlist.hkp>
+<FilePlaylist WTK>
 Success
 <BLANKLINE>
 >>> h = r.run_lines(h, ['curve_info']) # doctest: +ELLIPSIS, +REPORT_UDIFF
 name: 20100504144209_unfold
-path: test/data/vclamp_wtk/unfold/20100504/20100504144209_unfold
+path: .../test/data/vclamp_wtk/unfold/20100504/20100504144209_unfold
 experiment: <class 'hooke.experiment.VelocityClamp'>
 driver: <hooke.driver.wtk.WTKDriver object at 0x...>
 filetype: wtk
-note: 
+note: None
 blocks: 2
 block sizes: [(810, 2), (8001, 2)]
 Success