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 modify it
6 # under the terms of the GNU Lesser General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
10 # Hooke is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
13 # 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.
27 from ..command import Command, Argument, Failure
28 from ..playlist import FilePlaylist
29 from ..plugin import Builtin
32 class PlaylistPlugin (Builtin):
34 super(PlaylistPlugin, self).__init__(name='playlist')
36 NextCommand(self), PreviousCommand(self), JumpCommand(self),
37 GetCommand(self), IndexCommand(self), CurveListCommand(self),
38 SaveCommand(self), LoadCommand(self),
39 AddCommand(self), AddGlobCommand(self),
40 RemoveCommand(self), FilterCommand(self), NoteFilterCommand(self)]
43 # Define common or complicated arguments
45 def current_playlist_callback(hooke, command, argument, value):
48 playlist = hooke.playlists.current()
50 raise Failure('No playlists loaded')
53 PlaylistArgument = Argument(
54 name='playlist', type='playlist', callback=current_playlist_callback,
56 :class:`hooke.playlist.Playlist` to act on. Defaults to the current
60 def playlist_name_callback(hooke, command, argument, value):
62 names = [p.name for p in hooke.playlists]
64 name = 'playlist-%d' % i
69 PlaylistNameArgument = Argument(
70 name='name', type='string', optional=True, callback=playlist_name_callback,
72 Name of the new playlist (defaults to an auto-generated name).
75 def all_drivers_callback(hooke, command, argument, value):
81 class NextCommand (Command):
82 """Move playlist to the next curve.
84 def __init__(self, plugin):
85 super(NextCommand, self).__init__(
87 arguments=[PlaylistArgument],
88 help=self.__doc__, plugin=plugin)
90 def _run(self, hooke, inqueue, outqueue, params):
91 params['playlist'].next()
93 class PreviousCommand (Command):
94 """Move playlist to the previous curve.
96 def __init__(self, plugin):
97 super(PreviousCommand, self).__init__(
98 name='previous curve',
99 arguments=[PlaylistArgument],
100 help=self.__doc__, plugin=plugin)
102 def _run(self, hooke, inqueue, outqueue, params):
103 params['playlist'].previous()
105 class JumpCommand (Command):
106 """Move playlist to a given curve.
108 def __init__(self, plugin):
109 super(JumpCommand, self).__init__(
110 name='jump to curve',
113 Argument(name='index', type='int', optional=False, help="""
114 Index of target curve.
117 help=self.__doc__, plugin=plugin)
119 def _run(self, hooke, inqueue, outqueue, params):
120 params['playlist'].jump(int(params['index'])) # HACK, int() should be handled by ui
122 class IndexCommand (Command):
123 """Print the index of the current curve.
125 The first curve has index 0.
127 def __init__(self, plugin):
128 super(IndexCommand, self).__init__(
133 help=self.__doc__, plugin=plugin)
135 def _run(self, hooke, inqueue, outqueue, params):
136 outqueue.put(params['playlist'].index())
138 class GetCommand (Command):
139 """Return a :class:`hooke.playlist.Playlist`.
141 def __init__(self, plugin):
142 super(GetCommand, self).__init__(
144 arguments=[PlaylistArgument],
145 help=self.__doc__, plugin=plugin)
147 def _run(self, hooke, inqueue, outqueue, params):
148 outqueue.put(params['playlist'])
150 class CurveListCommand (Command):
151 """Get the curves in a playlist.
153 def __init__(self, plugin):
154 super(CurveListCommand, self).__init__(
155 name='playlist curves',
156 arguments=[PlaylistArgument],
157 help=self.__doc__, plugin=plugin)
159 def _run(self, hooke, inqueue, outqueue, params):
160 outqueue.put(list(params['playlist']))
162 class SaveCommand (Command):
165 def __init__(self, plugin):
166 super(SaveCommand, self).__init__(
167 name='save playlist',
170 Argument(name='output', type='file',
172 File name for the output playlist. Defaults to overwriting the input
176 help=self.__doc__, plugin=plugin)
178 def _run(self, hooke, inqueue, outqueue, params):
179 params['playlist'].save(params['output'])
181 class LoadCommand (Command):
184 def __init__(self, plugin):
185 super(LoadCommand, self).__init__(
186 name='load playlist',
188 Argument(name='input', type='file', optional=False,
190 File name for the input playlist.
192 Argument(name='drivers', type='driver', optional=True,
193 count=-1, callback=all_drivers_callback,
195 Drivers for loading curves.
198 help=self.__doc__, plugin=plugin)
200 def _run(self, hooke, inqueue, outqueue, params):
201 p = FilePlaylist(drivers=params['drivers'], path=params['input'])
203 hooke.playlists.append(p)
206 class AddCommand (Command):
207 """Add a curve to a playlist.
209 def __init__(self, plugin):
210 super(AddCommand, self).__init__(
211 name='add curve to playlist',
214 Argument(name='input', type='file', optional=False,
216 File name for the input :class:`hooke.curve.Curve`.
218 Argument(name='info', type='dict', optional=True,
220 Additional information for the input :class:`hooke.curve.Curve`.
223 help=self.__doc__, plugin=plugin)
225 def _run(self, hooke, inqueue, outqueue, params):
226 params['playlist'].append_curve_by_path(params['input'],
229 class AddGlobCommand (Command):
230 """Add curves to a playlist with file globbing.
232 Adding lots of files one at a time can be tedious. With this
233 command you can use globs (`data/curves/*.dat`) to add curves
234 for all matching files at once.
236 def __init__(self, plugin):
237 super(AddGlobCommand, self).__init__(
238 name='glob curves to playlist',
241 Argument(name='input', type='string', optional=False,
243 File name glob for the input :class:`hooke.curve.Curve`.
245 Argument(name='info', type='dict', optional=True,
247 Additional information for the input :class:`hooke.curve.Curve`.
250 help=self.__doc__, plugin=plugin)
252 def _run(self, hooke, inqueue, outqueue, params):
253 for path in sorted(glob.glob(params['input'])):
254 params['playlist'].append_curve_by_path(path, params['info'])
256 class RemoveCommand (Command):
257 """Remove a curve from a playlist.
259 def __init__(self, plugin):
260 super(RemoveCommand, self).__init__(
261 name='remove curve from playlist',
264 Argument(name='index', type='int', optional=False, help="""
265 Index of target curve.
268 help=self.__doc__, plugin=plugin)
270 def _run(self, hooke, inqueue, outqueue, params):
271 params['playlist'].pop(params['index'])
272 params['playlist'].jump(params.index())
274 class FilterCommand (Command):
275 """Create a subset playlist via a selection function.
277 Removing lots of curves one at a time can be tedious. With this
278 command you can use a function `filter` to select the curves you
283 There are issues with pickling functions bound to class
284 attributes, because the pickle module doesn't know where those
285 functions were originally defined (where it should point the
286 loader). Because of this, subclasses with hard-coded filter
287 functions are encouraged to define their filter function as a
288 method of their subclass. See, for example,
289 :meth:`NoteFilterCommand.filter`.
291 def __init__(self, plugin, name='filter playlist'):
292 super(FilterCommand, self).__init__(
296 PlaylistNameArgument,
298 help=self.__doc__, plugin=plugin)
299 if not hasattr(self, 'filter'):
300 self.arguments.append(
301 Argument(name='filter', type='function', optional=False,
303 Function returning `True` for "good" curves.
304 `filter(curve, hooke, inqueue, outqueue, params) -> True/False`.
307 def _run(self, hooke, inqueue, outqueue, params):
308 if not hasattr(self, 'filter'):
309 filter_fn = params['filter']
311 filter_fn = self.filter
312 p = params['playlist'].filter(filter_fn,
313 hooke=hooke, inqueue=inqueue, outqueue=outqueue, params=params)
314 p.name = params['name']
315 if hasattr(p, 'path') and p.path != None:
316 p.set_path(os.path.join(os.path.dirname(p.path), p.name))
317 hooke.playlists.append(p)
320 class NoteFilterCommand (FilterCommand):
321 """Create a subset playlist of curves with `.info['note'] != None`.
323 def __init__(self, plugin):
324 super(NoteFilterCommand, self).__init__(
325 plugin, name='note filter playlist')
327 def filter(self, curve, hooke, inqueue, outqueue, params):
328 return 'note' in curve.info and curve.info['note'] != None