From 200a98d4df9f07365dcdf5087d1236ec3cb3c058 Mon Sep 17 00:00:00 2001 From: Philippe Mongeau Date: Wed, 29 Feb 2012 18:55:44 -0500 Subject: [PATCH] add format option to list_items command you can provide a custom format option to the list command. Example: $ beet ls -f '$title - $album' --- beets/ui/commands.py | 16 +++++++++++++-- beets/util/functemplate.py | 3 ++- test/test_ui.py | 40 ++++++++++++++++++++++++++++++-------- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/beets/ui/commands.py b/beets/ui/commands.py index c4b55bfed..0e5855136 100644 --- a/beets/ui/commands.py +++ b/beets/ui/commands.py @@ -30,6 +30,7 @@ import beets.autotag.art from beets import plugins from beets import importer from beets.util import syspath, normpath, ancestry, displayable_path +from beets.util.functemplate import Template from beets import library # Global logger. @@ -743,7 +744,7 @@ default_commands.append(import_cmd) # list: Query and show library contents. -def list_items(lib, query, album, path): +def list_items(lib, query, album, path, format): """Print out items in lib matching query. If album, then search for albums instead of single items. If path, print the matched objects' paths instead of human-readable information about them. @@ -752,12 +753,21 @@ def list_items(lib, query, album, path): for album in lib.albums(query): if path: print_(album.item_dir()) + elif format is not None: + template = Template(format) + out = template.substitute(album._record) + print_(out) else: print_(album.albumartist + u' - ' + album.album) else: for item in lib.items(query): if path: print_(item.path) + elif format is not None: + template = Template(format) + out = template.substitute(item.record) + print_(out) + else: print_(item.artist + u' - ' + item.album + u' - ' + item.title) @@ -766,8 +776,10 @@ 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 (WIP)') def list_func(lib, config, opts, args): - list_items(lib, decargs(args), opts.album, opts.path) + list_items(lib, decargs(args), opts.album, opts.path, opts.format) list_cmd.func = list_func default_commands.append(list_cmd) diff --git a/beets/util/functemplate.py b/beets/util/functemplate.py index 1c2384a4c..3f7c088ee 100644 --- a/beets/util/functemplate.py +++ b/beets/util/functemplate.py @@ -109,7 +109,8 @@ class Expression(object): out.append(part) else: out.append(part.evaluate(env)) - return u''.join(out) + #return u''.join(out) + return u''.join([unicode(i) for i in out]) class ParseError(Exception): pass diff --git a/test/test_ui.py b/test/test_ui.py index 6130fbd9b..a14145330 100644 --- a/test/test_ui.py +++ b/test/test_ui.py @@ -47,7 +47,7 @@ class ListTest(unittest.TestCase): self.io.restore() def test_list_outputs_item(self): - commands.list_items(self.lib, '', False, False) + commands.list_items(self.lib, '', False, False, None) out = self.io.getoutput() self.assertTrue(u'the title' in out) @@ -56,42 +56,66 @@ class ListTest(unittest.TestCase): self.lib.store(self.item) self.lib.save() - commands.list_items(self.lib, [u'na\xefve'], False, False) + commands.list_items(self.lib, [u'na\xefve'], False, False, None) out = self.io.getoutput() self.assertTrue(u'na\xefve' in out.decode(self.io.stdout.encoding)) def test_list_item_path(self): - commands.list_items(self.lib, '', False, True) + commands.list_items(self.lib, '', False, True, None) out = self.io.getoutput() self.assertEqual(out.strip(), u'xxx/yyy') def test_list_album_outputs_something(self): - commands.list_items(self.lib, '', True, False) + commands.list_items(self.lib, '', True, False, None) out = self.io.getoutput() self.assertGreater(len(out), 0) def test_list_album_path(self): - commands.list_items(self.lib, '', True, True) + commands.list_items(self.lib, '', True, True, None) out = self.io.getoutput() self.assertEqual(out.strip(), u'xxx') def test_list_album_omits_title(self): - commands.list_items(self.lib, '', True, False) + commands.list_items(self.lib, '', True, False, None) out = self.io.getoutput() self.assertTrue(u'the title' not in out) def test_list_uses_track_artist(self): - commands.list_items(self.lib, '', False, False) + commands.list_items(self.lib, '', False, False, None) out = self.io.getoutput() self.assertTrue(u'the artist' in out) self.assertTrue(u'the album artist' not in out) def test_list_album_uses_album_artist(self): - commands.list_items(self.lib, '', True, False) + commands.list_items(self.lib, '', True, False, None) out = self.io.getoutput() self.assertTrue(u'the artist' not in out) self.assertTrue(u'the album artist' in out) + def test_list_item_format_artist(self): + commands.list_items(self.lib, '', False, False, '$artist') + out = self.io.getoutput() + self.assertTrue(u'the artist' in out) + + def test_list_item_format_multiple(self): + commands.list_items(self.lib, '', False, False, '$artist - $album - $year') + out = self.io.getoutput() + self.assertTrue(u'1' in out) + self.assertTrue(u'the album' in out) + self.assertTrue(u'the artist' in out) + self.assertEqual(u'the artist - the album - 1', out.strip()) + + def test_list_album_format(self): + commands.list_items(self.lib, '', True, False, '$genre') + out = self.io.getoutput() + self.assertTrue(u'the genre' in out) + self.assertTrue(u'the album' not in out) + + def test_list_item_path_ignores_format(self): + commands.list_items(self.lib, '', False, True, '$year - $artist') + out = self.io.getoutput() + self.assertEqual(out.strip(), u'xxx/yyy') + class RemoveTest(unittest.TestCase): def setUp(self): self.io = _common.DummyIO()