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):
60 return hooke.playlists.free_name()
62 PlaylistNameArgument = Argument(
63 name='name', type='string', optional=True, callback=playlist_name_callback,
65 Name of the new playlist (defaults to an auto-generated name).
68 def all_drivers_callback(hooke, command, argument, value):
74 class NextCommand (Command):
75 """Move playlist to the next curve.
77 def __init__(self, plugin):
78 super(NextCommand, self).__init__(
80 arguments=[PlaylistArgument],
81 help=self.__doc__, plugin=plugin)
83 def _run(self, hooke, inqueue, outqueue, params):
84 params['playlist'].next()
86 class PreviousCommand (Command):
87 """Move playlist to the previous curve.
89 def __init__(self, plugin):
90 super(PreviousCommand, self).__init__(
91 name='previous curve',
92 arguments=[PlaylistArgument],
93 help=self.__doc__, plugin=plugin)
95 def _run(self, hooke, inqueue, outqueue, params):
96 params['playlist'].previous()
98 class JumpCommand (Command):
99 """Move playlist to a given curve.
101 def __init__(self, plugin):
102 super(JumpCommand, self).__init__(
103 name='jump to curve',
106 Argument(name='index', type='int', optional=False, help="""
107 Index of target curve.
110 help=self.__doc__, plugin=plugin)
112 def _run(self, hooke, inqueue, outqueue, params):
113 params['playlist'].jump(params['index'])
115 class IndexCommand (Command):
116 """Print the index of the current curve.
118 The first curve has index 0.
120 def __init__(self, plugin):
121 super(IndexCommand, self).__init__(
126 help=self.__doc__, plugin=plugin)
128 def _run(self, hooke, inqueue, outqueue, params):
129 outqueue.put(params['playlist']._index)
131 class CurveListCommand (Command):
132 """Get the curves in a playlist.
134 def __init__(self, plugin):
135 super(CurveListCommand, self).__init__(
136 name='playlist curves',
140 help=self.__doc__, plugin=plugin)
142 def _run(self, hooke, inqueue, outqueue, params):
143 outqueue.put([c for c in params['playlist']])
145 class SaveCommand (Command):
148 def __init__(self, plugin):
149 super(SaveCommand, self).__init__(
150 name='save playlist',
153 Argument(name='output', type='file',
155 File name for the output playlist. Defaults to overwriting the input
159 help=self.__doc__, plugin=plugin)
161 def _run(self, hooke, inqueue, outqueue, params):
162 params['playlist'].save(params['output'])
164 class LoadCommand (Command):
167 def __init__(self, plugin):
168 super(LoadCommand, self).__init__(
169 name='load playlist',
171 Argument(name='input', type='file', optional=False,
173 File name for the input playlist.
175 Argument(name='drivers', type='driver', optional=True,
176 count=-1, callback=all_drivers_callback,
178 Drivers for loading curves.
181 help=self.__doc__, plugin=plugin)
183 def _run(self, hooke, inqueue, outqueue, params):
184 p = FilePlaylist(drivers=params['drivers'], path=params['input'])
186 hooke.playlists.append(p)
189 class AddCommand (Command):
190 """Add a curve to a playlist.
192 def __init__(self, plugin):
193 super(AddCommand, self).__init__(
194 name='add curve to playlist',
197 Argument(name='input', type='file', optional=False,
199 File name for the input :class:`hooke.curve.Curve`.
201 Argument(name='info', type='dict', optional=True,
203 Additional information for the input :class:`hooke.curve.Curve`.
206 help=self.__doc__, plugin=plugin)
208 def _run(self, hooke, inqueue, outqueue, params):
209 params['playlist'].append_curve_by_path(params['input'],
212 class AddGlobCommand (Command):
213 """Add curves to a playlist with file globbing.
215 Adding lots of files one at a time can be tedious. With this
216 command you can use globs (`data/curves/*.dat`) to add curves
217 for all matching files at once.
219 def __init__(self, plugin):
220 super(AddGlobCommand, self).__init__(
221 name='glob curves to playlist',
224 Argument(name='input', type='glob', optional=False,
226 File name glob for the input :class:`hooke.curve.Curve`.
228 Argument(name='info', type='dict', optional=True,
230 Additional information for the input :class:`hooke.curve.Curve`.
233 help=self.__doc__, plugin=plugin)
235 def _run(self, hooke, inqueue, outqueue, params):
236 for path in sorted(glob.glob(params['input'])):
237 params['playlist'].append_curve_by_path(path, params['info'])
239 class RemoveCommand (Command):
240 """Remove a curve from a playlist.
242 def __init__(self, plugin):
243 super(RemoveCommand, self).__init__(
244 name='remove curve from playlist',
247 Argument(name='index', type='int', optional=False, help="""
248 Index of target curve.
251 help=self.__doc__, plugin=plugin)
253 def _run(self, hooke, inqueue, outqueue, params):
254 params['playlist'].pop(params['index'])
255 params['playlist'].jump(params._index)
257 class FilterCommand (Command):
258 """Create a subset playlist via a selection function.
260 Removing lots of curves one at a time can be tedious. With this
261 command you can use a function `filter` to select the curves you
266 There are issues with pickling functions bound to class
267 attributes, because the pickle module doesn't know where those
268 functions were originally defined (where it should point the
269 loader). Because of this, subclasses with hard-coded filter
270 functions are encouraged to define their filter function as a
271 method of their subclass. See, for example,
272 :meth:`NoteFilterCommand.filter`.
274 def __init__(self, plugin, name='filter playlist'):
275 super(FilterCommand, self).__init__(
279 PlaylistNameArgument,
281 help=self.__doc__, plugin=plugin)
282 if not hasattr(self, 'filter'):
283 self.arguments.append(
284 Argument(name='filter', type='function', optional=False,
286 Function returning `True` for "good" curves.
287 `filter(curve, hooke, inqueue, outqueue, params) -> True/False`.
290 def _run(self, hooke, inqueue, outqueue, params):
291 if not hasattr(self, 'filter'):
292 filter_fn = params['filter']
294 filter_fn = self.filter
295 p = params['playlist'].filter(filter_fn,
296 hooke=hooke, inqueue=inqueue, outqueue=outqueue, params=params)
297 hooke.playlists.add(p)
300 class NoteFilterCommand (FilterCommand):
301 """Create a subset playlist of curves with `.info['note'] != None`.
303 def __init__(self, plugin):
304 super(NoteFilterCommand, self).__init__(
305 plugin, name='note filter playlist')
307 def filter(self, curve, hooke, inqueue, outqueue, params):
308 return 'note' in curve.info and curve.info['note'] != None