mirror of
https://github.com/beetbox/beets.git
synced 2026-02-15 03:41:45 +01:00
Option parser: add common options with a method
Add a new OptionParser subclass: CommonOptionsOptionParser, which provides facilities for adding --album, --path and --format options. The last one is quite versatile. Update base commands (from beets.ui.commands) to use those.
This commit is contained in:
parent
f14f47f059
commit
6234fee67d
4 changed files with 117 additions and 47 deletions
|
|
@ -233,7 +233,7 @@ class LibModel(dbcore.Model):
|
|||
"""Shared concrete functionality for Items and Albums.
|
||||
"""
|
||||
|
||||
_format_config_key = None
|
||||
format_config_key = None
|
||||
"""Config key that specifies how an instance should be formatted.
|
||||
"""
|
||||
|
||||
|
|
@ -256,7 +256,7 @@ class LibModel(dbcore.Model):
|
|||
|
||||
def __format__(self, spec):
|
||||
if not spec:
|
||||
spec = beets.config[self._format_config_key].get(unicode)
|
||||
spec = beets.config[self.format_config_key].get(unicode)
|
||||
result = self.evaluate_template(spec)
|
||||
if isinstance(spec, bytes):
|
||||
# if spec is a byte string then we must return a one as well
|
||||
|
|
@ -418,7 +418,7 @@ class Item(LibModel):
|
|||
|
||||
_sorts = {'artist': SmartArtistSort}
|
||||
|
||||
_format_config_key = 'format_item'
|
||||
format_config_key = 'format_item'
|
||||
|
||||
@classmethod
|
||||
def _getters(cls):
|
||||
|
|
@ -851,7 +851,7 @@ class Album(LibModel):
|
|||
"""List of keys that are set on an album's items.
|
||||
"""
|
||||
|
||||
_format_config_key = 'format_album'
|
||||
format_config_key = 'format_album'
|
||||
|
||||
@classmethod
|
||||
def _getters(cls):
|
||||
|
|
|
|||
|
|
@ -592,6 +592,103 @@ def show_model_changes(new, old=None, fields=None, always=False):
|
|||
return bool(changes)
|
||||
|
||||
|
||||
class CommonOptionsParser(optparse.OptionParser, object):
|
||||
"""Offers a simple way to add common formatting options.
|
||||
|
||||
Options available include:
|
||||
- matching albums instead of tracks: add_album_option()
|
||||
- showing paths instead of items/albums: add_path_option()
|
||||
- changing the format of displayed items/albums: add_format_option()
|
||||
|
||||
The last one can have several behaviors:
|
||||
- against a special target
|
||||
- with a certain format
|
||||
- autodetected target with the album option
|
||||
|
||||
Each method is fully documented in the related method.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(CommonOptionsParser, self).__init__(*args, **kwargs)
|
||||
self._has_album = False
|
||||
|
||||
def add_album_option(self, flags=('-a', '--album')):
|
||||
"""Add a -a/--album option to match albums instead of tracks.
|
||||
|
||||
If used then the format option can auto-detect whether we're setting
|
||||
the format for items or albums.
|
||||
Sets the album property on the options extracted from the CLI.
|
||||
"""
|
||||
album = optparse.Option(*flags, action='store_true',
|
||||
help='match albums instead of tracks')
|
||||
self.add_option(album)
|
||||
self._has_album = True
|
||||
|
||||
def _set_format(self, option, opt_str, value, parser, target=None,
|
||||
fmt=None):
|
||||
"""Internal callback that sets the correct format while parsing CLI
|
||||
arguments.
|
||||
"""
|
||||
value = fmt or value and unicode(value) or ''
|
||||
parser.values.format = value
|
||||
if target:
|
||||
config[target.format_config_key].set(value)
|
||||
else:
|
||||
if not self._has_album or not parser.values.album:
|
||||
config[library.Item.format_config_key].set(value)
|
||||
if not self._has_album or parser.values.album:
|
||||
config[library.Album.format_config_key].set(value)
|
||||
|
||||
def add_path_option(self, flags=('-p', '--path')):
|
||||
"""Add a -p/--path option to display the path instead of the default
|
||||
format.
|
||||
|
||||
By default this affects both items and albums. If add_album_option()
|
||||
is used then the target will be autodetected.
|
||||
|
||||
Sets the format property to u'$path' on the options extracted from the
|
||||
CLI.
|
||||
"""
|
||||
path = optparse.Option(*flags, nargs=0, action='callback',
|
||||
callback=self._set_format,
|
||||
callback_kwargs={'fmt': '$path'},
|
||||
help='print paths for matched items or albums')
|
||||
self.add_option(path)
|
||||
|
||||
def add_format_option(self, flags=('-f', '--format'), target=None):
|
||||
"""Add -f/--format option to print some LibModel instances with a
|
||||
custom format.
|
||||
|
||||
`target` is optional and can be one of ``library.Item``, 'item',
|
||||
``library.Album`` and 'album'.
|
||||
|
||||
Several behaviors are available:
|
||||
- if `target` is given then the format is only applied to that
|
||||
LibModel
|
||||
- if the album option is used then the target will be autodetected
|
||||
- otherwise the format is applied to both items and albums.
|
||||
|
||||
Sets the format property on the options extracted from the CLI.
|
||||
"""
|
||||
kwargs = {}
|
||||
if target:
|
||||
if isinstance(target, basestring):
|
||||
target = {'item': library.Item,
|
||||
'album': library.Album}[target]
|
||||
kwargs['target'] = target
|
||||
|
||||
opt = optparse.Option(*flags, action='callback',
|
||||
callback=self._set_format,
|
||||
callback_kwargs=kwargs,
|
||||
help='print with custom format')
|
||||
self.add_option(opt)
|
||||
|
||||
def add_all_common_options(self):
|
||||
"""Add album, path and format options.
|
||||
"""
|
||||
self.add_album_option()
|
||||
self.add_path_option()
|
||||
self.add_format_option()
|
||||
|
||||
# Subcommand parsing infrastructure.
|
||||
#
|
||||
# This is a fairly generic subcommand parser for optparse. It is
|
||||
|
|
@ -600,6 +697,7 @@ def show_model_changes(new, old=None, fields=None, always=False):
|
|||
# There you will also find a better description of the code and a more
|
||||
# succinct example program.
|
||||
|
||||
|
||||
class Subcommand(object):
|
||||
"""A subcommand of a root command-line application that may be
|
||||
invoked by a SubcommandOptionParser.
|
||||
|
|
@ -609,10 +707,10 @@ class Subcommand(object):
|
|||
the subcommand; aliases are alternate names. parser is an
|
||||
OptionParser responsible for parsing the subcommand's options.
|
||||
help is a short description of the command. If no parser is
|
||||
given, it defaults to a new, empty OptionParser.
|
||||
given, it defaults to a new, empty CommonOptionsParser.
|
||||
"""
|
||||
self.name = name
|
||||
self.parser = parser or optparse.OptionParser()
|
||||
self.parser = parser or CommonOptionsParser()
|
||||
self.aliases = aliases
|
||||
self.help = help
|
||||
self.hide = hide
|
||||
|
|
@ -635,7 +733,7 @@ class Subcommand(object):
|
|||
root_parser.get_prog_name().decode('utf8'), self.name)
|
||||
|
||||
|
||||
class SubcommandsOptionParser(optparse.OptionParser, object):
|
||||
class SubcommandsOptionParser(CommonOptionsParser):
|
||||
"""A variant of OptionParser that parses subcommands and their
|
||||
arguments.
|
||||
"""
|
||||
|
|
@ -924,6 +1022,8 @@ def _raw_main(args, lib=None):
|
|||
handling.
|
||||
"""
|
||||
parser = SubcommandsOptionParser()
|
||||
parser.add_format_option(flags=('--format-item',), target=library.Item)
|
||||
parser.add_format_option(flags=('--format-album',), target=library.Album)
|
||||
parser.add_option('-l', '--library', dest='library',
|
||||
help='library database file to use')
|
||||
parser.add_option('-d', '--directory', dest='directory',
|
||||
|
|
|
|||
|
|
@ -957,7 +957,7 @@ default_commands.append(import_cmd)
|
|||
|
||||
# list: Query and show library contents.
|
||||
|
||||
def list_items(lib, query, album, fmt):
|
||||
def list_items(lib, query, album, fmt=''):
|
||||
"""Print out items in lib matching query. If album, then search for
|
||||
albums instead of single items.
|
||||
"""
|
||||
|
|
@ -970,23 +970,11 @@ def list_items(lib, query, album, fmt):
|
|||
|
||||
|
||||
def list_func(lib, opts, args):
|
||||
fmt = '$path' if opts.path else opts.format
|
||||
list_items(lib, decargs(args), opts.album, fmt)
|
||||
list_items(lib, decargs(args), opts.album)
|
||||
|
||||
|
||||
list_cmd = ui.Subcommand('list', help='query the library', aliases=('ls',))
|
||||
list_cmd.parser.add_option(
|
||||
'-a', '--album', action='store_true',
|
||||
help='show matching albums instead of tracks'
|
||||
)
|
||||
list_cmd.parser.add_option(
|
||||
'-p', '--path', action='store_true',
|
||||
help='print paths for matched items or albums'
|
||||
)
|
||||
list_cmd.parser.add_option(
|
||||
'-f', '--format', action='store',
|
||||
help='print with custom format', default=''
|
||||
)
|
||||
list_cmd.parser.add_all_common_options()
|
||||
list_cmd.func = list_func
|
||||
default_commands.append(list_cmd)
|
||||
|
||||
|
|
@ -1087,10 +1075,8 @@ def update_func(lib, opts, args):
|
|||
update_cmd = ui.Subcommand(
|
||||
'update', help='update the library', aliases=('upd', 'up',)
|
||||
)
|
||||
update_cmd.parser.add_option(
|
||||
'-a', '--album', action='store_true',
|
||||
help='match albums instead of tracks'
|
||||
)
|
||||
update_cmd.parser.add_album_option()
|
||||
update_cmd.parser.add_format_option()
|
||||
update_cmd.parser.add_option(
|
||||
'-M', '--nomove', action='store_false', default=True, dest='move',
|
||||
help="don't move files in library"
|
||||
|
|
@ -1099,10 +1085,6 @@ update_cmd.parser.add_option(
|
|||
'-p', '--pretend', action='store_true',
|
||||
help="show all changes but do nothing"
|
||||
)
|
||||
update_cmd.parser.add_option(
|
||||
'-f', '--format', action='store',
|
||||
help='print with custom format', default=''
|
||||
)
|
||||
update_cmd.func = update_func
|
||||
default_commands.append(update_cmd)
|
||||
|
||||
|
|
@ -1151,10 +1133,7 @@ remove_cmd.parser.add_option(
|
|||
"-d", "--delete", action="store_true",
|
||||
help="also remove files from disk"
|
||||
)
|
||||
remove_cmd.parser.add_option(
|
||||
'-a', '--album', action='store_true',
|
||||
help='match albums instead of tracks'
|
||||
)
|
||||
remove_cmd.parser.add_album_option()
|
||||
remove_cmd.func = remove_func
|
||||
default_commands.append(remove_cmd)
|
||||
|
||||
|
|
@ -1348,18 +1327,12 @@ modify_cmd.parser.add_option(
|
|||
'-W', '--nowrite', action='store_false', dest='write',
|
||||
help="don't write metadata (opposite of -w)"
|
||||
)
|
||||
modify_cmd.parser.add_option(
|
||||
'-a', '--album', action='store_true',
|
||||
help='modify whole albums instead of tracks'
|
||||
)
|
||||
modify_cmd.parser.add_album_option()
|
||||
modify_cmd.parser.add_format_option(target='item')
|
||||
modify_cmd.parser.add_option(
|
||||
'-y', '--yes', action='store_true',
|
||||
help='skip confirmation'
|
||||
)
|
||||
modify_cmd.parser.add_option(
|
||||
'-f', '--format', action='store',
|
||||
help='print with custom format', default=''
|
||||
)
|
||||
modify_cmd.func = modify_func
|
||||
default_commands.append(modify_cmd)
|
||||
|
||||
|
|
@ -1405,10 +1378,7 @@ move_cmd.parser.add_option(
|
|||
'-c', '--copy', default=False, action='store_true',
|
||||
help='copy instead of moving'
|
||||
)
|
||||
move_cmd.parser.add_option(
|
||||
'-a', '--album', default=False, action='store_true',
|
||||
help='match whole albums instead of tracks'
|
||||
)
|
||||
move_cmd.parser.add_album_option()
|
||||
move_cmd.func = move_func
|
||||
default_commands.append(move_cmd)
|
||||
|
||||
|
|
|
|||
|
|
@ -359,7 +359,7 @@ class ConvertPlugin(BeetsPlugin):
|
|||
self.config['pretend'].get(bool)
|
||||
|
||||
if not pretend:
|
||||
ui.commands.list_items(lib, ui.decargs(args), opts.album, '')
|
||||
ui.commands.list_items(lib, ui.decargs(args), opts.album)
|
||||
|
||||
if not (opts.yes or ui.input_yn("Convert? (Y/n)")):
|
||||
return
|
||||
|
|
|
|||
Loading…
Reference in a new issue