-# Copyright
+# 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/>.
"""The `playlist` module provides a :class:`Playlist` and its subclass
:class:`FilePlaylist` for manipulating lists of
self.info = {}
self._index = 0
+ def __str__(self):
+ return '<%s %s>' % (self.__class__.__name__, self.name)
+
+ def _setup_item(self, item):
+ """Perform any required initialization before returning an item.
+ """
+ pass
+
def current(self):
if len(self) == 0:
return None
- return self[self._index]
+ item = self[self._index]
+ self._setup_item(item)
+ return item
def jump(self, index):
if len(self) == 0:
def previous(self):
self.jump(self._index - 1)
- def filter(self, keeper_fn=lambda item:True):
+ def filter(self, keeper_fn=lambda item:True, *args, **kwargs):
c = copy.deepcopy(self)
for item in reversed(c):
- if keeper_fn(item) != True:
+ c._setup_item(item)
+ if keeper_fn(item, *args, **kwargs) != True:
c.remove(item)
try: # attempt to maintain the same current item
c._index = c.index(self.current())
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 append_curve_by_path(self, path, info=None, identify=True):
if self.path != None:
- path = os.path.join(self.path, path)
+ path = os.path.join(os.path.dirname(self.path), path)
path = os.path.normpath(path)
c = curve.Curve(path, info=info)
if identify == True:
self.append(c)
return c
+ def _setup_item(self, curve):
+ if curve != None and curve not in self._loaded:
+ if curve not in self:
+ self.append(curve)
+ if curve.driver == None:
+ c.identify(self.drivers)
+ if curve.data == None:
+ curve.load()
+ self._loaded.append(curve)
+ if len(self._loaded) > self._max_loaded:
+ oldest = self._loaded.pop(0)
+ oldest.unload()
+
class FilePlaylist (Playlist):
version = '0.1'
super(FilePlaylist, self).__init__(drivers, name)
self.set_path(path)
self._digest = None
+ self._ignored_keys = [
+ 'experiment', # class instance, not very exciting.
+ ]
def set_path(self, path):
if path != None:
>>> c.info['note'] = 'The second curve'
>>> p.append(c)
>>> p.digest()
- "\xa1\x99\x8a\x99\xed\xad\x13'\xa7w\x12\x00\x07Z\xb3\xd0zN\xa2\xe1"
+ '\\\x14\x87\x88*q\xf8\xaa\xa7\x84f\x82\xa1S>\xfd3+\xd0o'
"""
string = self.flatten()
return hashlib.sha1(string).digest()
>>> 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 note="The second curve" path="../curve/two"/>
+ <curve note="The first curve" path="curve/one"/>
+ <curve note="The second curve" path="curve/two"/>
</playlist>
<BLANKLINE>
>>> print p.flatten(absolute_paths=True) # doctest: +NORMALIZE_WHITESPACE +REPORT_UDIFF
if absolute_paths == False:
path = os.path.relpath(
path,
- os.path.abspath(os.path.expanduser(self.path)))
+ os.path.dirname(
+ os.path.abspath(
+ os.path.expanduser(self.path))))
curve_element.setAttribute('path', path)
for key,value in curve.info.items():
+ if key in self._ignored_keys:
+ continue
curve_element.setAttribute(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):
+ def _from_xml_doc(self, doc, identify=True):
"""Load a playlist from an :class:`xml.dom.minidom.Document`
instance.
"""
path = curve_element.getAttribute('path')
info = dict(curve_element.attributes.items())
info.pop('path')
- self.append_curve_by_path(path, info, identify=False)
+ self.append_curve_by_path(path, info, identify=identify)
self.jump(self._index) # ensure valid index
- def from_string(self, string):
+ def from_string(self, string, identify=True):
"""Load a playlist from a string.
Examples
... </playlist>
... '''
>>> p = FilePlaylist(drivers=[],
- ... path=os.path.join('path', 'to','playlist'))
- >>> p.from_string(string)
+ ... path=os.path.join('path', 'to', 'my', 'playlist'))
+ >>> p.from_string(string, identify=False)
>>> p._index
1
>>> p.info
path/to/curve/two
"""
doc = xml.dom.minidom.parseString(string)
- self._from_xml_doc(doc)
+ self._from_xml_doc(doc, identify=identify)
- def load(self, path=None):
+ def load(self, path=None, identify=True):
"""Load a playlist from a file.
"""
self.set_path(path)
doc = xml.dom.minidom.parse(self.path)
- self._from_xml_doc(doc)
+ self._from_xml_doc(doc, identify=identify)
self._digest = self.digest()
def save(self, path=None):