This commit is contained in:
Adrian Sampson 2011-07-07 08:33:33 -07:00
commit f53a06ddf1
7 changed files with 46 additions and 15 deletions

1
NEWS
View file

@ -62,6 +62,7 @@
reuse by plugins (e.g., the FUSE plugin).
* Singleton imports ("beet import -s") can now take individual files as
arguments as well as directories.
* Fix Unicode queries given on the command line.
* Fix crasher in quiet singleton imports (import -qs).
* Fix crash when autotagging files with no metadata.
* Fix a rare deadlock when finishing the import pipeline.

View file

@ -52,6 +52,21 @@ class UserError(Exception):
# Utilities.
def _encoding():
"""Tries to guess the encoding uses by the terminal."""
try:
return locale.getdefaultlocale()[1] or 'utf8'
except ValueError:
# Invalid locale environment variable setting. To avoid
# failing entirely for no good reason, assume UTF-8.
return 'utf8'
def decargs(arglist):
"""Given a list of command-line argument bytestrings, attempts to
decode them to Unicode strings.
"""
return [s.decode(_encoding()) for s in arglist]
def print_(*strings):
"""Like print, but rather than raising an error when a character
is not in the terminal's encoding's character set, just silently
@ -65,13 +80,7 @@ def print_(*strings):
else:
txt = u''
if isinstance(txt, unicode):
try:
encoding = locale.getdefaultlocale()[1] or 'utf8'
except ValueError:
# Invalid locale environment variable setting. To avoid
# failing entirely for no good reason, assume UTF-8.
encoding = 'utf8'
txt = txt.encode(encoding, 'replace')
txt = txt.encode(_encoding(), 'replace')
print txt
def input_options(options, require=False, prompt=None, fallback_prompt=None,

View file

@ -22,7 +22,7 @@ import os
import time
from beets import ui
from beets.ui import print_
from beets.ui import print_, decargs
from beets import autotag
import beets.autotag.art
from beets import plugins
@ -622,7 +622,7 @@ list_cmd.parser.add_option('-a', '--album', action='store_true',
list_cmd.parser.add_option('-p', '--path', action='store_true',
help='print paths for matched items or albums')
def list_func(lib, config, opts, args):
list_items(lib, args, opts.album, opts.path)
list_items(lib, decargs(args), opts.album, opts.path)
list_cmd.func = list_func
default_commands.append(list_cmd)
@ -677,7 +677,7 @@ remove_cmd.parser.add_option("-d", "--delete", action="store_true",
remove_cmd.parser.add_option('-a', '--album', action='store_true',
help='match albums instead of tracks')
def remove_func(lib, config, opts, args):
remove_items(lib, args, opts.album, opts.delete)
remove_items(lib, decargs(args), opts.album, opts.delete)
remove_cmd.func = remove_func
default_commands.append(remove_cmd)
@ -718,7 +718,7 @@ Albums: %i""" % (
stats_cmd = ui.Subcommand('stats',
help='show statistics about the library or a query')
def stats_func(lib, config, opts, args):
show_stats(lib, args)
show_stats(lib, decargs(args))
stats_cmd.func = stats_func
default_commands.append(stats_cmd)

View file

@ -4,6 +4,7 @@ import imghdr
from beets.plugins import BeetsPlugin
from beets import mediafile
from beets import ui
from beets.ui import decargs
from beets.util import syspath, normpath
log = logging.getLogger('beets')
@ -41,7 +42,7 @@ class EmbedCoverArtPlugin(BeetsPlugin):
if not args:
raise ui.UserError('specify an image file')
imagepath = normpath(args.pop(0))
embed(lib, imagepath, args)
embed(lib, imagepath, decargs(args))
embed_cmd.func = embed_func
# Extract command.
@ -51,14 +52,14 @@ class EmbedCoverArtPlugin(BeetsPlugin):
help='image output file')
def extract_func(lib, config, opts, args):
outpath = normpath(opts.outpath or 'cover')
extract(lib, outpath, args)
extract(lib, outpath, decargs(args))
extract_cmd.func = extract_func
# Clear command.
clear_cmd = ui.Subcommand('clearart',
help='remove images from file metadata')
def clear_func(lib, config, opts, args):
clear(lib, args)
clear(lib, decargs(args))
clear_cmd.func = clear_func
return [embed_cmd, extract_cmd, clear_cmd]

View file

@ -1,4 +1,3 @@
"""Some common functionality for beets' test cases."""
# This file is part of beets.
# Copyright 2011, Adrian Sampson.
#
@ -13,6 +12,7 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
"""Some common functionality for beets' test cases."""
import time
import sys
import os

View file

@ -215,6 +215,16 @@ class MemoryGetTest(unittest.TestCase, AssertsMixin):
names = [a.album for a in results]
self.assertEqual(names, ['the album'])
def test_unicode_query(self):
self.single_item.title = u'caf\xe9'
self.lib.store(self.single_item)
self.lib.save()
q = u'title:caf\xe9'
results = self.lib.items(q)
self.assert_matched(results, u'caf\xe9')
self.assert_done(results)
class PathQueryTest(unittest.TestCase, AssertsMixin):
def setUp(self):
self.lib = beets.library.Library(':memory:')

View file

@ -37,6 +37,7 @@ class ListTest(unittest.TestCase):
i.path = 'xxx/yyy'
self.lib.add(i)
self.lib.add_album([i])
self.item = i
def tearDown(self):
self.io.restore()
@ -46,6 +47,15 @@ class ListTest(unittest.TestCase):
out = self.io.getoutput()
self.assertTrue(u'the title' in out)
def test_list_unicode_query(self):
self.item.title = u'na\xefve'
self.lib.store(self.item)
self.lib.save()
commands.list_items(self.lib, [u'na\xefve'], False, False)
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)
out = self.io.getoutput()