diff --git a/beets/library.py b/beets/library.py index 186a674e7..cad39c232 100644 --- a/beets/library.py +++ b/beets/library.py @@ -19,7 +19,6 @@ from __future__ import (division, absolute_import, print_function, import os import sys -import shlex import unicodedata import time import re @@ -1139,13 +1138,8 @@ def parse_query_string(s, model_cls): The string is split into components using shell-like syntax. """ assert isinstance(s, unicode), "Query is not unicode: {0!r}".format(s) - - # A bug in Python < 2.7.3 prevents correct shlex splitting of - # Unicode strings. - # http://bugs.python.org/issue6988 - s = s.encode('utf8') try: - parts = [p.decode('utf8') for p in shlex.split(s)] + parts = util.shlex_split(s) except ValueError as exc: raise dbcore.InvalidQueryError(s, exc) return parse_query_parts(parts, model_cls) diff --git a/beets/util/__init__.py b/beets/util/__init__.py index a2a5688b5..2a861ce88 100644 --- a/beets/util/__init__.py +++ b/beets/util/__init__.py @@ -749,6 +749,26 @@ def editor_command(): return open_anything() +def shlex_split(s): + """Split a Unicode or bytes string according to shell lexing rules. + + Raise `ValueError` if the string is not a well-formed shell string. + This is a workaround for a bug in some versions of Python. + """ + if isinstance(s, bytes): + # Shlex works fine. + return shlex.split(s) + + elif isinstance(s, unicode): + # Work around a Python bug. + # http://bugs.python.org/issue6988 + bs = s.encode('utf8') + return [c.decode('utf8') for c in shlex.split(bs)] + + else: + raise TypeError('shlex_split called with non-string') + + def interactive_open(targets, command): """Open the files in `targets` by `exec`ing a new `command`, given as a Unicode string. (The new program takes over, and Python @@ -757,15 +777,12 @@ def interactive_open(targets, command): Can raise `OSError`. """ # Split the command string into its arguments. - command = command.encode('utf8') try: - command = [c.decode('utf8') - for c in shlex.split(command)] + command = shlex_split(command) except ValueError: # Malformed shell tokens. command = [command] command.insert(0, command[0]) # for argv[0] - # Add the explicit arguments. command += targets return os.execlp(*command)