diff --git a/beets/ui/__init__.py b/beets/ui/__init__.py index e338e46df..71896ab3b 100644 --- a/beets/ui/__init__.py +++ b/beets/ui/__init__.py @@ -20,7 +20,6 @@ CLI commands are implemented in the ui.commands module. from __future__ import division, absolute_import, print_function -import locale import optparse import textwrap import sys @@ -108,24 +107,12 @@ def _stream_encoding(stream, default='utf8'): return stream.encoding or default -def _arg_encoding(): - """Get the encoding for command-line arguments (and other OS - locale-sensitive strings). - """ - 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 when running under Python 2. """ if six.PY2: - return [s.decode(_arg_encoding()) for s in arglist] + return [s.decode(util.arg_encoding()) for s in arglist] else: return arglist diff --git a/beets/util/__init__.py b/beets/util/__init__.py index 17cfc4f0e..ba3070e82 100644 --- a/beets/util/__init__.py +++ b/beets/util/__init__.py @@ -18,6 +18,7 @@ from __future__ import division, absolute_import, print_function import os import sys +import locale import re import shutil import fnmatch @@ -302,6 +303,18 @@ def components(path): return comps +def arg_encoding(): + """Get the encoding for command-line arguments (and other OS + locale-sensitive strings). + """ + 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 _fsencoding(): """Get the system's filesystem encoding. On Windows, this is always UTF-8 (not MBCS). diff --git a/beetsplug/convert.py b/beetsplug/convert.py index 10d5d9a18..fc1c0588d 100644 --- a/beetsplug/convert.py +++ b/beetsplug/convert.py @@ -185,9 +185,9 @@ class ConvertPlugin(BeetsPlugin): # Substitute $source and $dest in the argument list. if not six.PY2: - command = command.decode(ui._arg_encoding(), 'surrogateescape') - source = source.decode(ui._arg_encoding(), 'surrogateescape') - dest = dest.decode(ui._arg_encoding(), 'surrogateescape') + command = command.decode(util.arg_encoding(), 'surrogateescape') + source = source.decode(util.arg_encoding(), 'surrogateescape') + dest = dest.decode(util.arg_encoding(), 'surrogateescape') args = shlex.split(command) encode_cmd = [] @@ -199,7 +199,7 @@ class ConvertPlugin(BeetsPlugin): if six.PY2: encode_cmd.append(args[i]) else: - encode_cmd.append(args[i].encode(ui._arg_encoding())) + encode_cmd.append(args[i].encode(util.arg_encoding())) if pretend: self._log.info(u' '.join(ui.decargs(args))) diff --git a/beetsplug/hook.py b/beetsplug/hook.py index 596c969d0..ff33f0ae4 100644 --- a/beetsplug/hook.py +++ b/beetsplug/hook.py @@ -20,8 +20,7 @@ import subprocess import six from beets.plugins import BeetsPlugin -from beets.ui import _arg_encoding -from beets.util import shlex_split +from beets.util import shlex_split, arg_encoding class CodingFormatter(string.Formatter): @@ -99,7 +98,7 @@ class HookPlugin(BeetsPlugin): # Use a string formatter that works on Unicode strings. if six.PY2: - formatter = CodingFormatter(_arg_encoding()) + formatter = CodingFormatter(arg_encoding()) else: formatter = string.Formatter() diff --git a/test/helper.py b/test/helper.py index 49216f697..f6b0d5ecc 100644 --- a/test/helper.py +++ b/test/helper.py @@ -51,7 +51,6 @@ from beets.library import Library, Item, Album from beets import importer from beets.autotag.hooks import AlbumInfo, TrackInfo from beets.mediafile import MediaFile, Image -from beets.ui import _arg_encoding from beets import util # TODO Move AutotagMock here @@ -126,10 +125,10 @@ def _convert_args(args): for i, elem in enumerate(args): if six.PY2: if isinstance(elem, six.text_type): - args[i] = elem.encode(_arg_encoding()) + args[i] = elem.encode(util.arg_encoding()) else: if isinstance(elem, bytes): - args[i] = elem.decode(_arg_encoding()) + args[i] = elem.decode(util.arg_encoding()) return args diff --git a/test/test_convert.py b/test/test_convert.py index 1f1b1a7fb..8d75fbb57 100644 --- a/test/test_convert.py +++ b/test/test_convert.py @@ -24,7 +24,6 @@ from test.helper import control_stdin from beets.mediafile import MediaFile from beets import util -from beets import ui class TestHelper(helper.TestHelper): @@ -119,7 +118,7 @@ class ConvertCommand(object): """Run the `convert` command on a given path.""" # The path is currently a filesystem bytestring. Convert it to # an argument bytestring. - path = path.decode(util._fsencoding()).encode(ui._arg_encoding()) + path = path.decode(util._fsencoding()).encode(util.arg_encoding()) args = args + (b'path:' + path,) return self.run_command('convert', *args) diff --git a/test/test_ui.py b/test/test_ui.py index 160d1dfbc..c7de8caab 100644 --- a/test/test_ui.py +++ b/test/test_ui.py @@ -1209,7 +1209,7 @@ class CommonOptionsParserCliTest(unittest.TestCase, TestHelper): def test_format_option_unicode(self): l = self.run_with_output(b'ls', b'-f', - u'caf\xe9'.encode(ui._arg_encoding())) + u'caf\xe9'.encode(util.arg_encoding())) self.assertEqual(l, u'caf\xe9\n') def test_root_format_option(self):