1 # Copyright (C) 2010 W. Trevor King <wking@drexel.edu>
3 # This file is part of Hooke.
5 # Hooke is free software: you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation, either
8 # version 3 of the License, or (at your option) any later version.
10 # Hooke is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with Hooke. If not, see
17 # <http://www.gnu.org/licenses/>.
19 """The ``playlist`` module provides :class:`PlaylistPlugin` and
20 several associated :class:`hooke.command.Command`\s for handling
21 :mod:`hooke.playlist` classes.
26 from ..command import Command, Argument, Failure
27 from ..playlist import FilePlaylist
28 from ..plugin import Builtin
31 class PlaylistPlugin (Builtin):
33 super(PlaylistPlugin, self).__init__(name='playlist')
35 NextCommand(self), PreviousCommand(self), JumpCommand(self),
36 IndexCommand(self), CurveListCommand(self),
37 SaveCommand(self), LoadCommand(self),
38 AddCommand(self), AddGlobCommand(self),
39 RemoveCommand(self), FilterCommand(self), NoteFilterCommand(self)]
42 # Define common or complicated arguments
44 def current_playlist_callback(hooke, command, argument, value):
47 playlist = hooke.playlists.current()
49 raise Failure('No playlists loaded')
52 PlaylistArgument = Argument(
53 name='playlist', type='playlist', callback=current_playlist_callback,
55 :class:`hooke.playlist.Playlist` to act on. Defaults to the current
59 def playlist_name_callback(hooke, command, argument, value):
61 names = [p.name for p in hooke.playlists]
63 name = 'playlist-%d' % i
68 PlaylistNameArgument = Argument(
69 name='name', type='string', optional=True, callback=playlist_name_callback,
71 Name of the new playlist (defaults to an auto-generated name).
74 def all_drivers_callback(hooke, command, argument, value):
80 class NextCommand (Command):
81 """Move playlist to the next curve.
83 def __init__(self, plugin):
84 super(NextCommand, self).__init__(
86 arguments=[PlaylistArgument],
87 help=self.__doc__, plugin=plugin)
89 def _run(self, hooke, inqueue, outqueue, params):
90 params['playlist'].next()
92 class PreviousCommand (Command):
93 """Move playlist to the previous curve.
95 def __init__(self, plugin):
96 super(PreviousCommand, self).__init__(
97 name='previous curve',
98 arguments=[PlaylistArgument],
99 help=self.__doc__, plugin=plugin)
101 def _run(self, hooke, inqueue, outqueue, params):
102 params['playlist'].previous()
104 class JumpCommand (Command):
105 """Move playlist to a given curve.
107 def __init__(self, plugin):
108 super(JumpCommand, self).__init__(
109 name='jump to curve',
112 Argument(name='index', type='int', optional=False, help="""
113 Index of target curve.
116 help=self.__doc__, plugin=plugin)
118 def _run(self, hooke, inqueue, outqueue, params):
119 params['playlist'].jump(params['index'])
121 class IndexCommand (Command):
122 """Print the index of the current curve.
124 The first curve has index 0.
126 def __init__(self, plugin):
127 super(IndexCommand, self).__init__(
132 help=self.__doc__, plugin=plugin)
134 def _run(self, hooke, inqueue, outqueue, params):
135 outqueue.put(params['playlist']._index)
137 class CurveListCommand (Command):
138 """Get the curves in a playlist.
140 def __init__(self, plugin):
141 super(CurveListCommand, self).__init__(
142 name='playlist curves',
146 help=self.__doc__, plugin=plugin)
148 def _run(self, hooke, inqueue, outqueue, params):
149 outqueue.put([c for c in params['playlist']])
151 class SaveCommand (Command):
154 def __init__(self, plugin):
155 super(SaveCommand, self).__init__(
156 name='save playlist',
159 Argument(name='output', type='file',
161 File name for the output playlist. Defaults to overwriting the input
165 help=self.__doc__, plugin=plugin)
167 def _run(self, hooke, inqueue, outqueue, params):
168 params['playlist'].save(params['output'])
170 class LoadCommand (Command):
173 def __init__(self, plugin):
174 super(LoadCommand, self).__init__(
175 name='load playlist',
177 Argument(name='input', type='file', optional=False,
179 File name for the input playlist.
181 Argument(name='drivers', type='driver', optional=True,
182 count=-1, callback=all_drivers_callback,
184 Drivers for loading curves.
187 help=self.__doc__, plugin=plugin)
189 def _run(self, hooke, inqueue, outqueue, params):
190 p = FilePlaylist(drivers=params['drivers'], path=params['input'])
192 hooke.playlists.append(p)
195 class AddCommand (Command):
196 """Add a curve to a playlist.
198 def __init__(self, plugin):
199 super(AddCommand, self).__init__(
200 name='add curve to playlist',
203 Argument(name='input', type='file', optional=False,
205 File name for the input :class:`hooke.curve.Curve`.
207 Argument(name='info', type='dict', optional=True,
209 Additional information for the input :class:`hooke.curve.Curve`.
212 help=self.__doc__, plugin=plugin)
214 def _run(self, hooke, inqueue, outqueue, params):
215 params['playlist'].append_curve_by_path(params['input'],
218 class AddGlobCommand (Command):
219 """Add curves to a playlist with file globbing.
221 Adding lots of files one at a time can be tedious. With this
222 command you can use globs (`data/curves/*.dat`) to add curves
223 for all matching files at once.
225 def __init__(self, plugin):
226 super(AddGlobCommand, self).__init__(
227 name='glob curves to playlist',
230 Argument(name='input', type='glob', optional=False,
232 File name glob for the input :class:`hooke.curve.Curve`.
234 Argument(name='info', type='dict', optional=True,
236 Additional information for the input :class:`hooke.curve.Curve`.
239 help=self.__doc__, plugin=plugin)
241 def _run(self, hooke, inqueue, outqueue, params):
242 for path in sorted(glob.glob(params['input'])):
243 params['playlist'].append_curve_by_path(path, params['info'])
245 class RemoveCommand (Command):
246 """Remove a curve from a playlist.
248 def __init__(self, plugin):
249 super(RemoveCommand, self).__init__(
250 name='remove curve from playlist',
253 Argument(name='index', type='int', optional=False, help="""
254 Index of target curve.
257 help=self.__doc__, plugin=plugin)
259 def _run(self, hooke, inqueue, outqueue, params):
260 params['playlist'].pop(params['index'])
261 params['playlist'].jump(params._index)
263 class FilterCommand (Command):
264 """Create a subset playlist via a selection function.
266 Removing lots of curves one at a time can be tedious. With this
267 command you can use a function `filter` to select the curves you
272 There are issues with pickling functions bound to class
273 attributes, because the pickle module doesn't know where those
274 functions were originally defined (where it should point the
275 loader). Because of this, subclasses with hard-coded filter
276 functions are encouraged to define their filter function as a
277 method of their subclass. See, for example,
278 :meth:`NoteFilterCommand.filter`.
280 def __init__(self, plugin, name='filter playlist'):
281 super(FilterCommand, self).__init__(
285 PlaylistNameArgument,
287 help=self.__doc__, plugin=plugin)
288 if not hasattr(self, 'filter'):
289 self.arguments.append(
290 Argument(name='filter', type='function', optional=False,
292 Function returning `True` for "good" curves.
293 `filter(curve, hooke, inqueue, outqueue, params) -> True/False`.
296 def _run(self, hooke, inqueue, outqueue, params):
297 if not hasattr(self, 'filter'):
298 filter_fn = params['filter']
300 filter_fn = self.filter
301 p = params['playlist'].filter(filter_fn,
302 hooke=hooke, inqueue=inqueue, outqueue=outqueue, params=params)
303 hooke.playlists.add(p)
306 class NoteFilterCommand (FilterCommand):
307 """Create a subset playlist of curves with `.info['note'] != None`.
309 def __init__(self, plugin):
310 super(NoteFilterCommand, self).__init__(
311 plugin, name='note filter playlist')
313 def filter(self, curve, hooke, inqueue, outqueue, params):
314 return 'note' in curve.info and curve.info['note'] != None