From e8afcbe7ec4bc37bb080f6f466b98807d020753b Mon Sep 17 00:00:00 2001 From: Johnny Robeson Date: Mon, 20 Jun 2016 04:34:24 -0400 Subject: [PATCH] replace unicode with six.text_type --- beets/autotag/hooks.py | 5 +-- beets/autotag/mb.py | 8 +++-- beets/dbcore/db.py | 3 +- beets/dbcore/query.py | 7 ++-- beets/dbcore/types.py | 9 ++--- beets/importer.py | 3 +- beets/library.py | 23 ++++++------ beets/logging.py | 5 +-- beets/mediafile.py | 48 +++++++++++++------------ beets/ui/__init__.py | 20 ++++++----- beets/ui/commands.py | 7 ++-- beets/util/__init__.py | 17 ++++----- beets/util/confit.py | 3 +- beets/util/functemplate.py | 9 ++--- beets/util/hidden.py | 3 +- beetsplug/badfiles.py | 3 +- beetsplug/beatport.py | 19 +++++----- beetsplug/bpd/__init__.py | 64 +++++++++++++++++---------------- beetsplug/bpd/gstplayer.py | 3 +- beetsplug/chroma.py | 3 +- beetsplug/convert.py | 13 +++---- beetsplug/discogs.py | 7 ++-- beetsplug/duplicates.py | 3 +- beetsplug/edit.py | 5 +-- beetsplug/fetchart.py | 3 +- beetsplug/fromfilename.py | 3 +- beetsplug/ftintitle.py | 3 +- beetsplug/hook.py | 5 +-- beetsplug/importfeeds.py | 3 +- beetsplug/inline.py | 7 ++-- beetsplug/keyfinder.py | 3 +- beetsplug/lastgenre/__init__.py | 10 +++--- beetsplug/lastimport.py | 3 +- beetsplug/lyrics.py | 11 +++--- beetsplug/mbcollection.py | 5 +-- beetsplug/mpdstats.py | 9 ++--- beetsplug/mpdupdate.py | 7 ++-- beetsplug/replaygain.py | 7 ++-- beetsplug/rewrite.py | 3 +- beetsplug/spotify.py | 3 +- beetsplug/the.py | 3 +- beetsplug/thumbnails.py | 4 ++- beetsplug/web/__init__.py | 3 +- beetsplug/zero.py | 3 +- test/helper.py | 5 +-- test/test_config_command.py | 5 +-- test/test_dbcore.py | 3 +- test/test_library.py | 8 +++-- test/test_lyrics.py | 3 +- test/test_mediafile.py | 5 +-- test/test_mediafile_edge.py | 9 ++--- test/test_query.py | 8 +++-- test/test_template.py | 3 +- test/test_ui.py | 27 +++++++------- test/test_ui_importer.py | 3 +- test/test_util.py | 5 +-- 56 files changed, 269 insertions(+), 203 deletions(-) diff --git a/beets/autotag/hooks.py b/beets/autotag/hooks.py index 0b8a6f6bf..154896da7 100644 --- a/beets/autotag/hooks.py +++ b/beets/autotag/hooks.py @@ -27,6 +27,7 @@ from beets.util import as_string from beets.autotag import mb from jellyfish import levenshtein_distance from unidecode import unidecode +import six log = logging.getLogger('beets') @@ -205,8 +206,8 @@ def _string_dist_basic(str1, str2): transliteration/lowering to ASCII characters. Normalized by string length. """ - assert isinstance(str1, unicode) - assert isinstance(str2, unicode) + assert isinstance(str1, six.text_type) + assert isinstance(str2, six.text_type) str1 = as_string(unidecode(str1)) str2 = as_string(unidecode(str2)) str1 = re.sub(r'[^a-z0-9]', '', str1.lower()) diff --git a/beets/autotag/mb.py b/beets/autotag/mb.py index 4df0187e4..8aafe36e2 100644 --- a/beets/autotag/mb.py +++ b/beets/autotag/mb.py @@ -27,6 +27,7 @@ import beets.autotag.hooks import beets from beets import util from beets import config +import six VARIOUS_ARTISTS_ID = '89ad4ac3-39f7-470e-963a-56509c546377' BASE_URL = 'http://musicbrainz.org/' @@ -69,7 +70,8 @@ def configure(): """Set up the python-musicbrainz-ngs module according to settings from the beets configuration. This should be called at startup. """ - musicbrainzngs.set_hostname(config['musicbrainz']['host'].get(unicode)) + hostname = config['musicbrainz']['host'].get(six.text_type) + musicbrainzngs.set_hostname(hostname) musicbrainzngs.set_rate_limit( config['musicbrainz']['ratelimit_interval'].as_number(), config['musicbrainz']['ratelimit'].get(int), @@ -260,7 +262,7 @@ def album_info(release): ) info.va = info.artist_id == VARIOUS_ARTISTS_ID if info.va: - info.artist = config['va_name'].get(unicode) + info.artist = config['va_name'].get(six.text_type) info.asin = release.get('asin') info.releasegroup_id = release['release-group']['id'] info.country = release.get('country') @@ -329,7 +331,7 @@ def match_album(artist, album, tracks=None): # Various Artists search. criteria['arid'] = VARIOUS_ARTISTS_ID if tracks is not None: - criteria['tracks'] = unicode(tracks) + criteria['tracks'] = six.text_type(tracks) # Abort if we have no search terms. if not any(criteria.itervalues()): diff --git a/beets/dbcore/db.py b/beets/dbcore/db.py index a07a19997..19d5c51e6 100644 --- a/beets/dbcore/db.py +++ b/beets/dbcore/db.py @@ -29,6 +29,7 @@ import beets from beets.util.functemplate import Template from beets.dbcore import types from .query import MatchQuery, NullSort, TrueQuery +import six class FormattedMapping(collections.Mapping): @@ -69,7 +70,7 @@ class FormattedMapping(collections.Mapping): value = value.decode('utf8', 'ignore') if self.for_path: - sep_repl = beets.config['path_sep_replace'].get(unicode) + sep_repl = beets.config['path_sep_replace'].get(six.text_type) for sep in (os.path.sep, os.path.altsep): if sep: value = value.replace(sep, sep_repl) diff --git a/beets/dbcore/query.py b/beets/dbcore/query.py index 8e2075f37..f95e4ac60 100644 --- a/beets/dbcore/query.py +++ b/beets/dbcore/query.py @@ -23,6 +23,7 @@ from beets import util from datetime import datetime, timedelta import unicodedata from functools import reduce +import six class ParsingError(ValueError): @@ -246,8 +247,8 @@ class BytesQuery(MatchQuery): # Use a buffer representation of the pattern for SQLite # matching. This instructs SQLite to treat the blob as binary # rather than encoded Unicode. - if isinstance(self.pattern, (unicode, bytes)): - if isinstance(self.pattern, unicode): + if isinstance(self.pattern, (six.text_type, bytes)): + if isinstance(self.pattern, six.text_type): self.pattern = self.pattern.encode('utf8') self.buf_pattern = buffer(self.pattern) elif isinstance(self.pattern, buffer): @@ -793,7 +794,7 @@ class FieldSort(Sort): def key(item): field_val = item.get(self.field, '') - if self.case_insensitive and isinstance(field_val, unicode): + if self.case_insensitive and isinstance(field_val, six.text_type): field_val = field_val.lower() return field_val diff --git a/beets/dbcore/types.py b/beets/dbcore/types.py index 2726969dd..2270d7c13 100644 --- a/beets/dbcore/types.py +++ b/beets/dbcore/types.py @@ -19,6 +19,7 @@ from __future__ import division, absolute_import, print_function from . import query from beets.util import str2bool +import six # Abstract base. @@ -37,7 +38,7 @@ class Type(object): """The `Query` subclass to be used when querying the field. """ - model_type = unicode + model_type = six.text_type """The Python type that is used to represent the value in the model. The model is guaranteed to return a value of this type if the field @@ -63,7 +64,7 @@ class Type(object): if isinstance(value, bytes): value = value.decode('utf8', 'ignore') - return unicode(value) + return six.text_type(value) def parse(self, string): """Parse a (possibly human-written) string and return the @@ -102,7 +103,7 @@ class Type(object): """ if isinstance(sql_value, buffer): sql_value = bytes(sql_value).decode('utf8', 'ignore') - if isinstance(sql_value, unicode): + if isinstance(sql_value, six.text_type): return self.parse(sql_value) else: return self.normalize(sql_value) @@ -194,7 +195,7 @@ class Boolean(Type): model_type = bool def format(self, value): - return unicode(bool(value)) + return six.text_type(bool(value)) def parse(self, string): return str2bool(string) diff --git a/beets/importer.py b/beets/importer.py index 072c2ad5b..598dd36d7 100644 --- a/beets/importer.py +++ b/beets/importer.py @@ -14,6 +14,7 @@ # included in all copies or substantial portions of the Software. from __future__ import division, absolute_import, print_function +import six """Provides the basic, interface-agnostic workflow for importing and autotagging music files. @@ -640,7 +641,7 @@ class ImportTask(BaseImportTask): changes['comp'] = False else: # VA. - changes['albumartist'] = config['va_name'].get(unicode) + changes['albumartist'] = config['va_name'].get(six.text_type) changes['comp'] = True elif self.choice_flag in (action.APPLY, action.RETAG): diff --git a/beets/library.py b/beets/library.py index f268694cb..e672187a8 100644 --- a/beets/library.py +++ b/beets/library.py @@ -124,14 +124,15 @@ class DateType(types.Float): query = dbcore.query.DateQuery def format(self, value): - return time.strftime(beets.config['time_format'].get(unicode), + return time.strftime(beets.config['time_format'].get(six.text_type), time.localtime(value or 0)) def parse(self, string): try: # Try a formatted date string. return time.mktime( - time.strptime(string, beets.config['time_format'].get(unicode)) + time.strptime(string, + beets.config['time_format'].get(six.text_type)) ) except ValueError: # Fall back to a plain timestamp number. @@ -153,7 +154,7 @@ class PathType(types.Type): return normpath(bytestring_path(string)) def normalize(self, value): - if isinstance(value, unicode): + if isinstance(value, six.text_type): # Paths stored internally as encoded bytes. return bytestring_path(value) @@ -281,11 +282,11 @@ class FileOperationError(Exception): """ return u'{0}: {1}'.format( util.displayable_path(self.path), - unicode(self.reason) + six.text_type(self.reason) ) def __str__(self): - return unicode(self).encode('utf8') + return six.text_type(self).encode('utf8') class ReadError(FileOperationError): @@ -331,7 +332,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(six.text_type) result = self.evaluate_template(spec) if isinstance(spec, bytes): # if spec is a byte string then we must return a one as well @@ -517,7 +518,7 @@ class Item(LibModel): """ # Encode unicode paths and read buffers. if key == 'path': - if isinstance(value, unicode): + if isinstance(value, six.text_type): value = bytestring_path(value) elif isinstance(value, buffer): value = bytes(value) @@ -1061,7 +1062,8 @@ class Album(LibModel): image = bytestring_path(image) item_dir = item_dir or self.item_dir() - filename_tmpl = Template(beets.config['art_filename'].get(unicode)) + filename_tmpl = Template( + beets.config['art_filename'].get(six.text_type)) subpath = self.evaluate_template(filename_tmpl, True) if beets.config['asciify_paths']: subpath = unidecode(subpath) @@ -1179,7 +1181,8 @@ def parse_query_string(s, model_cls): The string is split into components using shell-like syntax. """ - assert isinstance(s, unicode), u"Query is not unicode: {0!r}".format(s) + message = u"Query is not unicode: {0!r}".format(s) + assert isinstance(s, six.text_type), message try: parts = util.shlex_split(s) except ValueError as exc: @@ -1405,7 +1408,7 @@ class DefaultTemplateFunctions(object): def tmpl_time(s, fmt): """Format a time value using `strftime`. """ - cur_fmt = beets.config['time_format'].get(unicode) + cur_fmt = beets.config['time_format'].get(six.text_type) return time.strftime(fmt, time.strptime(s, cur_fmt)) def tmpl_aunique(self, keys=None, disam=None): diff --git a/beets/logging.py b/beets/logging.py index a94da1c62..f7b46bd60 100644 --- a/beets/logging.py +++ b/beets/logging.py @@ -27,6 +27,7 @@ from copy import copy from logging import * # noqa import subprocess import threading +import six def logsafe(val): @@ -42,7 +43,7 @@ def logsafe(val): example. """ # Already Unicode. - if isinstance(val, unicode): + if isinstance(val, six.text_type): return val # Bytestring: needs decoding. @@ -56,7 +57,7 @@ def logsafe(val): # A "problem" object: needs a workaround. elif isinstance(val, subprocess.CalledProcessError): try: - return unicode(val) + return six.text_type(val) except UnicodeDecodeError: # An object with a broken __unicode__ formatter. Use __str__ # instead. diff --git a/beets/mediafile.py b/beets/mediafile.py index 556b41bb8..278e848b8 100644 --- a/beets/mediafile.py +++ b/beets/mediafile.py @@ -59,6 +59,7 @@ import enum from beets import logging from beets.util import displayable_path, syspath, as_string +import six __all__ = ['UnreadableFileError', 'FileTypeError', 'MediaFile'] @@ -131,7 +132,7 @@ def _safe_cast(out_type, val): else: # Process any other type as a string. if not isinstance(val, basestring): - val = unicode(val) + val = six.text_type(val) # Get a number from the front of the string. val = re.match(r'[0-9]*', val.strip()).group(0) if not val: @@ -146,13 +147,13 @@ def _safe_cast(out_type, val): except ValueError: return False - elif out_type == unicode: + elif out_type == six.text_type: if isinstance(val, bytes): return val.decode('utf8', 'ignore') - elif isinstance(val, unicode): + elif isinstance(val, six.text_type): return val else: - return unicode(val) + return six.text_type(val) elif out_type == float: if isinstance(val, int) or isinstance(val, float): @@ -161,7 +162,7 @@ def _safe_cast(out_type, val): if isinstance(val, bytes): val = val.decode('utf8', 'ignore') else: - val = unicode(val) + val = six.text_type(val) match = re.match(r'[\+-]?([0-9]+\.?[0-9]*|[0-9]*\.[0-9]+)', val.strip()) if match: @@ -220,7 +221,7 @@ def _sc_decode(soundcheck): """ # We decode binary data. If one of the formats gives us a text # string, interpret it as UTF-8. - if isinstance(soundcheck, unicode): + if isinstance(soundcheck, six.text_type): soundcheck = soundcheck.encode('utf8') # SoundCheck tags consist of 10 numbers, each represented by 8 @@ -407,7 +408,8 @@ class StorageStyle(object): """List of mutagen classes the StorageStyle can handle. """ - def __init__(self, key, as_type=unicode, suffix=None, float_places=2): + def __init__(self, key, as_type=six.text_type, suffix=None, + float_places=2): """Create a basic storage strategy. Parameters: - `key`: The key on the Mutagen file object used to access the @@ -426,8 +428,8 @@ class StorageStyle(object): self.float_places = float_places # Convert suffix to correct string type. - if self.suffix and self.as_type is unicode \ - and not isinstance(self.suffix, unicode): + if self.suffix and self.as_type is six.text_type \ + and not isinstance(self.suffix, six.text_type): self.suffix = self.suffix.decode('utf8') # Getter. @@ -450,7 +452,7 @@ class StorageStyle(object): """Given a raw value stored on a Mutagen object, decode and return the represented value. """ - if self.suffix and isinstance(mutagen_value, unicode) \ + if self.suffix and isinstance(mutagen_value, six.text_type) \ and mutagen_value.endswith(self.suffix): return mutagen_value[:-len(self.suffix)] else: @@ -472,17 +474,17 @@ class StorageStyle(object): """Convert the external Python value to a type that is suitable for storing in a Mutagen file object. """ - if isinstance(value, float) and self.as_type is unicode: + if isinstance(value, float) and self.as_type is six.text_type: value = u'{0:.{1}f}'.format(value, self.float_places) value = self.as_type(value) - elif self.as_type is unicode: + elif self.as_type is six.text_type: if isinstance(value, bool): # Store bools as 1/0 instead of True/False. - value = unicode(int(bool(value))) + value = six.text_type(int(bool(value))) elif isinstance(value, bytes): value = value.decode('utf8', 'ignore') else: - value = unicode(value) + value = six.text_type(value) else: value = self.as_type(value) @@ -592,7 +594,7 @@ class MP4StorageStyle(StorageStyle): def serialize(self, value): value = super(MP4StorageStyle, self).serialize(value) - if self.key.startswith('----:') and isinstance(value, unicode): + if self.key.startswith('----:') and isinstance(value, six.text_type): value = value.encode('utf8') return value @@ -807,7 +809,7 @@ class MP3SlashPackStorageStyle(MP3StorageStyle): def _fetch_unpacked(self, mutagen_file): data = self.fetch(mutagen_file) if data: - items = unicode(data).split('/') + items = six.text_type(data).split('/') else: items = [] packing_length = 2 @@ -823,7 +825,7 @@ class MP3SlashPackStorageStyle(MP3StorageStyle): items[0] = '' if items[1] is None: items.pop() # Do not store last value - self.store(mutagen_file, '/'.join(map(unicode, items))) + self.store(mutagen_file, '/'.join(map(six.text_type, items))) def delete(self, mutagen_file): if self.pack_pos == 0: @@ -1074,7 +1076,7 @@ class MediaField(object): getting this property. """ - self.out_type = kwargs.get('out_type', unicode) + self.out_type = kwargs.get('out_type', six.text_type) self._styles = styles def styles(self, mutagen_file): @@ -1113,7 +1115,7 @@ class MediaField(object): return 0.0 elif self.out_type == bool: return False - elif self.out_type == unicode: + elif self.out_type == six.text_type: return u'' @@ -1195,8 +1197,8 @@ class DateField(MediaField): # Get the underlying data and split on hyphens and slashes. datestring = super(DateField, self).__get__(mediafile, None) if isinstance(datestring, basestring): - datestring = re.sub(r'[Tt ].*$', '', unicode(datestring)) - items = re.split('[-/]', unicode(datestring)) + datestring = re.sub(r'[Tt ].*$', '', six.text_type(datestring)) + items = re.split('[-/]', six.text_type(datestring)) else: items = [] @@ -1233,7 +1235,7 @@ class DateField(MediaField): date.append(u'{0:02d}'.format(int(month))) if month and day: date.append(u'{0:02d}'.format(int(day))) - date = map(unicode, date) + date = map(six.text_type, date) super(DateField, self).__set__(mediafile, u'-'.join(date)) if hasattr(self, '_year_field'): @@ -1360,7 +1362,7 @@ class MediaFile(object): try: self.mgfile = mutagen.File(path) except unreadable_exc as exc: - log.debug(u'header parsing failed: {0}', unicode(exc)) + log.debug(u'header parsing failed: {0}', six.text_type(exc)) raise UnreadableFileError(path) except IOError as exc: if type(exc) == IOError: diff --git a/beets/ui/__init__.py b/beets/ui/__init__.py index 9cebf7a28..61176307f 100644 --- a/beets/ui/__init__.py +++ b/beets/ui/__init__.py @@ -42,6 +42,7 @@ from beets import config from beets.util import confit, as_string from beets.autotag import mb from beets.dbcore import query as db_query +import six # On Windows platforms, use colorama to support "ANSI" terminal colors. if sys.platform == 'win32': @@ -140,7 +141,7 @@ def print_(*strings, **kwargs): """ end = kwargs.get('end') - if not strings or isinstance(strings[0], unicode): + if not strings or isinstance(strings[0], six.text_type): txt = u' '.join(strings) txt += u'\n' if end is None else end else: @@ -148,7 +149,7 @@ def print_(*strings, **kwargs): txt += b'\n' if end is None else end # Always send bytes to the stdout stream. - if isinstance(txt, unicode): + if isinstance(txt, six.text_type): txt = txt.encode(_out_encoding(), 'replace') sys.stdout.write(txt) @@ -298,11 +299,11 @@ def input_options(options, require=False, prompt=None, fallback_prompt=None, prompt_part_lengths = [] if numrange: if isinstance(default, int): - default_name = unicode(default) + default_name = six.text_type(default) default_name = colorize('action_default', default_name) tmpl = '# selection (default %s)' prompt_parts.append(tmpl % default_name) - prompt_part_lengths.append(len(tmpl % unicode(default))) + prompt_part_lengths.append(len(tmpl % six.text_type(default))) else: prompt_parts.append('# selection') prompt_part_lengths.append(len(prompt_parts[-1])) @@ -522,7 +523,8 @@ def colorize(color_name, text): if config['ui']['color']: global COLORS if not COLORS: - COLORS = dict((name, config['ui']['colors'][name].get(unicode)) + COLORS = dict((name, + config['ui']['colors'][name].get(six.text_type)) for name in COLOR_NAMES) # In case a 3rd party plugin is still passing the actual color ('red') # instead of the abstract color name ('text_error') @@ -544,8 +546,8 @@ def _colordiff(a, b, highlight='text_highlight', """ if not isinstance(a, basestring) or not isinstance(b, basestring): # Non-strings: use ordinary equality. - a = unicode(a) - b = unicode(b) + a = six.text_type(a) + b = six.text_type(b) if a == b: return a, b else: @@ -593,7 +595,7 @@ def colordiff(a, b, highlight='text_highlight'): if config['ui']['color']: return _colordiff(a, b, highlight) else: - return unicode(a), unicode(b) + return six.text_type(a), six.text_type(b) def get_path_formats(subview=None): @@ -604,7 +606,7 @@ def get_path_formats(subview=None): subview = subview or config['paths'] for query, view in subview.items(): query = PF_KEY_QUERIES.get(query, query) # Expand common queries. - path_formats.append((query, Template(view.get(unicode)))) + path_formats.append((query, Template(view.get(six.text_type)))) return path_formats diff --git a/beets/ui/commands.py b/beets/ui/commands.py index d2270c662..9b23eafd4 100644 --- a/beets/ui/commands.py +++ b/beets/ui/commands.py @@ -38,6 +38,7 @@ from beets import library from beets import config from beets import logging from beets.util.confit import _package_path +import six VARIOUS_ARTISTS = u'Various Artists' PromptChoice = namedtuple('ExtraChoice', ['short', 'long', 'callback']) @@ -163,7 +164,7 @@ def disambig_string(info): else: disambig.append(info.media) if info.year: - disambig.append(unicode(info.year)) + disambig.append(six.text_type(info.year)) if info.country: disambig.append(info.country) if info.label: @@ -236,9 +237,9 @@ def show_change(cur_artist, cur_album, match): if mediums > 1: return u'{0}-{1}'.format(medium, medium_index) else: - return unicode(medium_index) + return six.text_type(medium_index) else: - return unicode(index) + return six.text_type(index) # Identify the album in question. if cur_artist != match.info.artist or \ diff --git a/beets/util/__init__.py b/beets/util/__init__.py index 0628f324b..5fe52d7b8 100644 --- a/beets/util/__init__.py +++ b/beets/util/__init__.py @@ -27,6 +27,7 @@ import subprocess import platform import shlex from beets.util import hidden +import six MAX_FILENAME_LENGTH = 200 @@ -65,14 +66,14 @@ class HumanReadableException(Exception): def _reasonstr(self): """Get the reason as a string.""" - if isinstance(self.reason, unicode): + if isinstance(self.reason, six.text_type): return self.reason elif isinstance(self.reason, bytes): return self.reason.decode('utf8', 'ignore') elif hasattr(self.reason, 'strerror'): # i.e., EnvironmentError return self.reason.strerror else: - return u'"{0}"'.format(unicode(self.reason)) + return u'"{0}"'.format(six.text_type(self.reason)) def get_message(self): """Create the human-readable description of the error, sans @@ -346,11 +347,11 @@ def displayable_path(path, separator=u'; '): """ if isinstance(path, (list, tuple)): return separator.join(displayable_path(p) for p in path) - elif isinstance(path, unicode): + elif isinstance(path, six.text_type): return path elif not isinstance(path, bytes): # A non-string object: just get its unicode representation. - return unicode(path) + return six.text_type(path) try: return path.decode(_fsencoding(), 'ignore') @@ -369,7 +370,7 @@ def syspath(path, prefix=True): if os.path.__name__ != 'ntpath': return path - if not isinstance(path, unicode): + if not isinstance(path, six.text_type): # Beets currently represents Windows paths internally with UTF-8 # arbitrarily. But earlier versions used MBCS because it is # reported as the FS encoding by Windows. Try both. @@ -639,7 +640,7 @@ def as_string(value): elif isinstance(value, bytes): return value.decode('utf8', 'ignore') else: - return unicode(value) + return six.text_type(value) def plurality(objs): @@ -765,7 +766,7 @@ def shlex_split(s): # Shlex works fine. return shlex.split(s) - elif isinstance(s, unicode): + elif isinstance(s, six.text_type): # Work around a Python bug. # http://bugs.python.org/issue6988 bs = s.encode('utf8') @@ -801,7 +802,7 @@ def _windows_long_path_name(short_path): """Use Windows' `GetLongPathNameW` via ctypes to get the canonical, long path given a short filename. """ - if not isinstance(short_path, unicode): + if not isinstance(short_path, six.text_type): short_path = short_path.decode(_fsencoding()) import ctypes diff --git a/beets/util/confit.py b/beets/util/confit.py index 057f85a1f..7994a0b3e 100644 --- a/beets/util/confit.py +++ b/beets/util/confit.py @@ -25,6 +25,7 @@ import yaml import collections import re from collections import OrderedDict +import six UNIX_DIR_VAR = 'XDG_CONFIG_HOME' UNIX_DIR_FALLBACK = '~/.config' @@ -44,7 +45,7 @@ REDACTED_TOMBSTONE = 'REDACTED' # Utilities. PY3 = sys.version_info[0] == 3 -STRING = str if PY3 else unicode # noqa +STRING = str if PY3 else six.text_type # noqa BASESTRING = str if PY3 else basestring # noqa NUMERIC_TYPES = (int, float) if PY3 else (int, float, long) # noqa diff --git a/beets/util/functemplate.py b/beets/util/functemplate.py index 05f0892c2..3a07df5bd 100644 --- a/beets/util/functemplate.py +++ b/beets/util/functemplate.py @@ -35,6 +35,7 @@ import dis import types from .confit import NUMERIC_TYPES +import six SYMBOL_DELIM = u'$' FUNC_DELIM = u'%' @@ -190,8 +191,8 @@ class Call(object): except Exception as exc: # Function raised exception! Maybe inlining the name of # the exception will help debug. - return u'<%s>' % unicode(exc) - return unicode(out) + return u'<%s>' % six.text_type(exc) + return six.text_type(out) else: return self.original @@ -246,7 +247,7 @@ class Expression(object): out.append(part) else: out.append(part.evaluate(env)) - return u''.join(map(unicode, out)) + return u''.join(map(six.text_type, out)) def translate(self): """Compile the expression to a list of Python AST expressions, a @@ -563,7 +564,7 @@ if __name__ == '__main__': import timeit _tmpl = Template(u'foo $bar %baz{foozle $bar barzle} $bar') _vars = {'bar': 'qux'} - _funcs = {'baz': unicode.upper} + _funcs = {'baz': six.text_type.upper} interp_time = timeit.timeit('_tmpl.interpret(_vars, _funcs)', 'from __main__ import _tmpl, _vars, _funcs', number=10000) diff --git a/beets/util/hidden.py b/beets/util/hidden.py index 262d371ea..11e3691d6 100644 --- a/beets/util/hidden.py +++ b/beets/util/hidden.py @@ -20,6 +20,7 @@ import os import stat import ctypes import sys +import six def _is_hidden_osx(path): @@ -74,7 +75,7 @@ def is_hidden(path): work out if a file is hidden. """ # Convert the path to unicode if it is not already. - if not isinstance(path, unicode): + if not isinstance(path, six.text_type): path = path.decode('utf-8') # Run platform specific functions depending on the platform diff --git a/beetsplug/badfiles.py b/beetsplug/badfiles.py index f9704d484..bb14c7762 100644 --- a/beetsplug/badfiles.py +++ b/beetsplug/badfiles.py @@ -27,6 +27,7 @@ import shlex import os import errno import sys +import six class BadFiles(BeetsPlugin): @@ -97,7 +98,7 @@ class BadFiles(BeetsPlugin): if not checker: continue path = item.path - if not isinstance(path, unicode): + if not isinstance(path, six.text_type): path = item.path.decode(sys.getfilesystemencoding()) status, errors, output = checker(path) if status > 0: diff --git a/beetsplug/beatport.py b/beetsplug/beatport.py index c1425ad9e..530bf5184 100644 --- a/beetsplug/beatport.py +++ b/beetsplug/beatport.py @@ -18,6 +18,7 @@ from __future__ import division, absolute_import, print_function import json import re +import six from datetime import datetime, timedelta from requests_oauthlib import OAuth1Session @@ -42,15 +43,15 @@ class BeatportAPIError(Exception): class BeatportObject(object): def __init__(self, data): self.beatport_id = data['id'] - self.name = unicode(data['name']) + self.name = six.text_type(data['name']) if 'releaseDate' in data: self.release_date = datetime.strptime(data['releaseDate'], '%Y-%m-%d') if 'artists' in data: - self.artists = [(x['id'], unicode(x['name'])) + self.artists = [(x['id'], six.text_type(x['name'])) for x in data['artists']] if 'genres' in data: - self.genres = [unicode(x['name']) + self.genres = [six.text_type(x['name']) for x in data['genres']] @@ -209,7 +210,7 @@ class BeatportRelease(BeatportObject): ) def __repr__(self): - return unicode(self).encode('utf8') + return six.text_type(self).encode('utf8') def __init__(self, data): BeatportObject.__init__(self, data) @@ -231,14 +232,14 @@ class BeatportTrack(BeatportObject): .format(artist_str, self.name, self.mix_name)) def __repr__(self): - return unicode(self).encode('utf8') + return six.text_type(self).encode('utf8') def __init__(self, data): BeatportObject.__init__(self, data) if 'title' in data: - self.title = unicode(data['title']) + self.title = six.text_type(data['title']) if 'mixName' in data: - self.mix_name = unicode(data['mixName']) + self.mix_name = six.text_type(data['mixName']) self.length = timedelta(milliseconds=data.get('lengthMs', 0) or 0) if not self.length: try: @@ -266,8 +267,8 @@ class BeatportPlugin(BeetsPlugin): self.register_listener('import_begin', self.setup) def setup(self, session=None): - c_key = self.config['apikey'].get(unicode) - c_secret = self.config['apisecret'].get(unicode) + c_key = self.config['apikey'].get(six.text_type) + c_secret = self.config['apisecret'].get(six.text_type) # Get the OAuth token from a file or log in. try: diff --git a/beetsplug/bpd/__init__.py b/beetsplug/bpd/__init__.py index ea1b0082e..ee41ad164 100644 --- a/beetsplug/bpd/__init__.py +++ b/beetsplug/bpd/__init__.py @@ -35,6 +35,7 @@ from beets.util import bluelet from beets.library import Item from beets import dbcore from beets.mediafile import MediaFile +import six PROTOCOL_VERSION = '0.13.0' BUFSIZE = 1024 @@ -305,12 +306,12 @@ class BaseServer(object): playlist, playlistlength, and xfade. """ yield ( - u'volume: ' + unicode(self.volume), - u'repeat: ' + unicode(int(self.repeat)), - u'random: ' + unicode(int(self.random)), - u'playlist: ' + unicode(self.playlist_version), - u'playlistlength: ' + unicode(len(self.playlist)), - u'xfade: ' + unicode(self.crossfade), + u'volume: ' + six.text_type(self.volume), + u'repeat: ' + six.text_type(int(self.repeat)), + u'random: ' + six.text_type(int(self.random)), + u'playlist: ' + six.text_type(self.playlist_version), + u'playlistlength: ' + six.text_type(len(self.playlist)), + u'xfade: ' + six.text_type(self.crossfade), ) if self.current_index == -1: @@ -323,8 +324,8 @@ class BaseServer(object): if self.current_index != -1: # i.e., paused or playing current_id = self._item_id(self.playlist[self.current_index]) - yield u'song: ' + unicode(self.current_index) - yield u'songid: ' + unicode(current_id) + yield u'song: ' + six.text_type(self.current_index) + yield u'songid: ' + six.text_type(current_id) if self.error: yield u'error: ' + self.error @@ -468,8 +469,8 @@ class BaseServer(object): Also a dummy implementation. """ for idx, track in enumerate(self.playlist): - yield u'cpos: ' + unicode(idx) - yield u'Id: ' + unicode(track.id) + yield u'cpos: ' + six.text_type(idx) + yield u'Id: ' + six.text_type(track.id) def cmd_currentsong(self, conn): """Sends information about the currently-playing song. @@ -573,7 +574,7 @@ class Connection(object): lines = [lines] out = NEWLINE.join(lines) + NEWLINE log.debug('{}', out[:-1]) # Don't log trailing newline. - if isinstance(out, unicode): + if isinstance(out, six.text_type): out = out.encode('utf8') return self.sock.sendall(out) @@ -771,28 +772,28 @@ class Server(BaseServer): def _item_info(self, item): info_lines = [ u'file: ' + item.destination(fragment=True), - u'Time: ' + unicode(int(item.length)), + u'Time: ' + six.text_type(int(item.length)), u'Title: ' + item.title, u'Artist: ' + item.artist, u'Album: ' + item.album, u'Genre: ' + item.genre, ] - track = unicode(item.track) + track = six.text_type(item.track) if item.tracktotal: - track += u'/' + unicode(item.tracktotal) + track += u'/' + six.text_type(item.tracktotal) info_lines.append(u'Track: ' + track) - info_lines.append(u'Date: ' + unicode(item.year)) + info_lines.append(u'Date: ' + six.text_type(item.year)) try: pos = self._id_to_index(item.id) - info_lines.append(u'Pos: ' + unicode(pos)) + info_lines.append(u'Pos: ' + six.text_type(pos)) except ArgumentNotFoundError: # Don't include position if not in playlist. pass - info_lines.append(u'Id: ' + unicode(item.id)) + info_lines.append(u'Id: ' + six.text_type(item.id)) return info_lines @@ -917,7 +918,7 @@ class Server(BaseServer): for item in self._all_items(self._resolve_path(path)): self.playlist.append(item) if send_id: - yield u'Id: ' + unicode(item.id) + yield u'Id: ' + six.text_type(item.id) self.playlist_version += 1 def cmd_add(self, conn, path): @@ -938,11 +939,11 @@ class Server(BaseServer): if self.current_index > -1: item = self.playlist[self.current_index] - yield u'bitrate: ' + unicode(item.bitrate / 1000) + yield u'bitrate: ' + six.text_type(item.bitrate / 1000) # Missing 'audio'. (pos, total) = self.player.time() - yield u'time: ' + unicode(pos) + u':' + unicode(total) + yield u'time: ' + six.text_type(pos) + u':' + six.text_type(total) # Also missing 'updating_db'. @@ -957,13 +958,13 @@ class Server(BaseServer): artists, albums, songs, totaltime = tx.query(statement)[0] yield ( - u'artists: ' + unicode(artists), - u'albums: ' + unicode(albums), - u'songs: ' + unicode(songs), - u'uptime: ' + unicode(int(time.time() - self.startup_time)), + u'artists: ' + six.text_type(artists), + u'albums: ' + six.text_type(albums), + u'songs: ' + six.text_type(songs), + u'uptime: ' + six.text_type(int(time.time() - self.startup_time)), u'playtime: ' + u'0', # Missing. - u'db_playtime: ' + unicode(int(totaltime)), - u'db_update: ' + unicode(int(self.updated_time)), + u'db_playtime: ' + six.text_type(int(totaltime)), + u'db_update: ' + six.text_type(int(self.updated_time)), ) # Searching. @@ -1059,7 +1060,7 @@ class Server(BaseServer): rows = tx.query(statement, subvals) for row in rows: - yield show_tag_canon + u': ' + unicode(row[0]) + yield show_tag_canon + u': ' + six.text_type(row[0]) def cmd_count(self, conn, tag, value): """Returns the number and total time of songs matching the @@ -1071,8 +1072,8 @@ class Server(BaseServer): for item in self.lib.items(dbcore.query.MatchQuery(key, value)): songs += 1 playtime += item.length - yield u'songs: ' + unicode(songs) - yield u'playtime: ' + unicode(int(playtime)) + yield u'songs: ' + six.text_type(songs) + yield u'playtime: ' + six.text_type(int(playtime)) # "Outputs." Just a dummy implementation because we don't control # any outputs. @@ -1180,11 +1181,12 @@ class BPDPlugin(BeetsPlugin): ) def func(lib, opts, args): - host = args.pop(0) if args else self.config['host'].get(unicode) + host = self.config['host'].get(six.text_type) + host = args.pop(0) if args else host port = args.pop(0) if args else self.config['port'].get(int) if args: raise beets.ui.UserError(u'too many arguments') - password = self.config['password'].get(unicode) + password = self.config['password'].get(six.text_type) volume = self.config['volume'].get(int) debug = opts.debug or False self.start_bpd(lib, host, int(port), password, volume, debug) diff --git a/beetsplug/bpd/gstplayer.py b/beetsplug/bpd/gstplayer.py index e90a5a44e..8fa0f7a81 100644 --- a/beetsplug/bpd/gstplayer.py +++ b/beetsplug/bpd/gstplayer.py @@ -19,6 +19,7 @@ music player. from __future__ import division, absolute_import, print_function +import six import sys import time from six.moves import _thread @@ -128,7 +129,7 @@ class GstPlayer(object): path. """ self.player.set_state(Gst.State.NULL) - if isinstance(path, unicode): + if isinstance(path, six.text_type): path = path.encode('utf8') uri = 'file://' + urllib.parse.quote(path) self.player.set_property("uri", uri) diff --git a/beetsplug/chroma.py b/beetsplug/chroma.py index 148e9c20c..4881113a4 100644 --- a/beetsplug/chroma.py +++ b/beetsplug/chroma.py @@ -26,6 +26,7 @@ from beets.util import confit from beets.autotag import hooks import acoustid from collections import defaultdict +import six API_KEY = '1vOwZtEn' SCORE_THRESH = 0.5 @@ -181,7 +182,7 @@ class AcoustidPlugin(plugins.BeetsPlugin): def submit_cmd_func(lib, opts, args): try: - apikey = config['acoustid']['apikey'].get(unicode) + apikey = config['acoustid']['apikey'].get(six.text_type) except confit.NotFoundError: raise ui.UserError(u'no Acoustid user API key provided') submit_items(self._log, apikey, lib.items(ui.decargs(args))) diff --git a/beetsplug/convert.py b/beetsplug/convert.py index 21a348bab..63057b46f 100644 --- a/beetsplug/convert.py +++ b/beetsplug/convert.py @@ -29,6 +29,7 @@ from beets.plugins import BeetsPlugin from beets.util.confit import ConfigTypeError from beets import art from beets.util.artresizer import ArtResizer +import six _fs_lock = threading.Lock() _temp_files = [] # Keep track of temporary transcoded files for deletion. @@ -55,7 +56,7 @@ def get_format(fmt=None): """Return the command template and the extension from the config. """ if not fmt: - fmt = config['convert']['format'].get(unicode).lower() + fmt = config['convert']['format'].get(six.text_type).lower() fmt = ALIASES.get(fmt, fmt) try: @@ -74,14 +75,14 @@ def get_format(fmt=None): # Convenience and backwards-compatibility shortcuts. keys = config['convert'].keys() if 'command' in keys: - command = config['convert']['command'].get(unicode) + command = config['convert']['command'].get(six.text_type) elif 'opts' in keys: # Undocumented option for backwards compatibility with < 1.3.1. command = u'ffmpeg -i $source -y {0} $dest'.format( - config['convert']['opts'].get(unicode) + config['convert']['opts'].get(six.text_type) ) if 'extension' in keys: - extension = config['convert']['extension'].get(unicode) + extension = config['convert']['extension'].get(six.text_type) return (command.encode('utf8'), extension.encode('utf8')) @@ -389,7 +390,7 @@ class ConvertPlugin(BeetsPlugin): path_formats = ui.get_path_formats() if not opts.format: - opts.format = self.config['format'].get(unicode).lower() + opts.format = self.config['format'].get(six.text_type).lower() pretend = opts.pretend if opts.pretend is not None else \ self.config['pretend'].get(bool) @@ -422,7 +423,7 @@ class ConvertPlugin(BeetsPlugin): """Transcode a file automatically after it is imported into the library. """ - fmt = self.config['format'].get(unicode).lower() + fmt = self.config['format'].get(six.text_type).lower() if should_transcode(item, fmt): command, ext = get_format() diff --git a/beetsplug/discogs.py b/beetsplug/discogs.py index 4252900e0..b33dec7ed 100644 --- a/beetsplug/discogs.py +++ b/beetsplug/discogs.py @@ -34,6 +34,7 @@ import time import json import socket import os +import six # Silence spurious INFO log lines generated by urllib3. @@ -66,8 +67,8 @@ class DiscogsPlugin(BeetsPlugin): def setup(self, session=None): """Create the `discogs_client` field. Authenticate if necessary. """ - c_key = self.config['apikey'].get(unicode) - c_secret = self.config['apisecret'].get(unicode) + c_key = self.config['apikey'].get(six.text_type) + c_secret = self.config['apisecret'].get(six.text_type) # Get the OAuth token from a file or log in. try: @@ -225,7 +226,7 @@ class DiscogsPlugin(BeetsPlugin): result.data['formats'][0].get('descriptions', [])) or None va = result.data['artists'][0]['name'].lower() == 'various' if va: - artist = config['va_name'].get(unicode) + artist = config['va_name'].get(six.text_type) year = result.data['year'] label = result.data['labels'][0]['name'] mediums = len(set(t.medium for t in tracks)) diff --git a/beetsplug/duplicates.py b/beetsplug/duplicates.py index 4f0397171..f9b089e0f 100644 --- a/beetsplug/duplicates.py +++ b/beetsplug/duplicates.py @@ -23,6 +23,7 @@ from beets.plugins import BeetsPlugin from beets.ui import decargs, print_, vararg_callback, Subcommand, UserError from beets.util import command_output, displayable_path, subprocess from beets.library import Item, Album +import six PLUGIN = 'duplicates' @@ -264,7 +265,7 @@ class DuplicatesPlugin(BeetsPlugin): # between a bytes object and the empty Unicode # string ''. return v is not None and \ - (v != '' if isinstance(v, unicode) else True) + (v != '' if isinstance(v, six.text_type) else True) fields = kind.all_keys() key = lambda x: sum(1 for f in fields if truthy(getattr(x, f))) else: diff --git a/beetsplug/edit.py b/beetsplug/edit.py index c8522849d..4a55e59ed 100644 --- a/beetsplug/edit.py +++ b/beetsplug/edit.py @@ -27,6 +27,7 @@ import subprocess import yaml from tempfile import NamedTemporaryFile import os +import six # These "safe" types can avoid the format/parse cycle that most fields go @@ -82,7 +83,7 @@ def load(s): # Convert all keys to strings. They started out as strings, # but the user may have inadvertently messed this up. - out.append({unicode(k): v for k, v in d.items()}) + out.append({six.text_type(k): v for k, v in d.items()}) except yaml.YAMLError as e: raise ParseError(u'invalid YAML: {}'.format(e)) @@ -141,7 +142,7 @@ def apply_(obj, data): else: # Either the field was stringified originally or the user changed # it from a safe type to an unsafe one. Parse it as a string. - obj.set_parse(key, unicode(value)) + obj.set_parse(key, six.text_type(value)) class EditPlugin(plugins.BeetsPlugin): diff --git a/beetsplug/fetchart.py b/beetsplug/fetchart.py index a2ce1661d..3109bce65 100644 --- a/beetsplug/fetchart.py +++ b/beetsplug/fetchart.py @@ -32,6 +32,7 @@ from beets import config from beets.util.artresizer import ArtResizer from beets.util import confit from beets.util import syspath, bytestring_path +import six try: import itunes @@ -696,7 +697,7 @@ class FetchArtPlugin(plugins.BeetsPlugin, RequestMixin): confit.String(pattern=self.PAT_PERCENT)])) self.margin_px = None self.margin_percent = None - if type(self.enforce_ratio) is unicode: + if type(self.enforce_ratio) is six.text_type: if self.enforce_ratio[-1] == u'%': self.margin_percent = float(self.enforce_ratio[:-1]) / 100 elif self.enforce_ratio[-2:] == u'px': diff --git a/beetsplug/fromfilename.py b/beetsplug/fromfilename.py index e9c49bee3..648df6258 100644 --- a/beetsplug/fromfilename.py +++ b/beetsplug/fromfilename.py @@ -22,6 +22,7 @@ from beets import plugins from beets.util import displayable_path import os import re +import six # Filename field extraction patterns. @@ -132,7 +133,7 @@ def apply_matches(d): # Apply the title and track. for item in d: if bad_title(item.title): - item.title = unicode(d[item][title_field]) + item.title = six.text_type(d[item][title_field]) if 'track' in d[item] and item.track == 0: item.track = int(d[item]['track']) diff --git a/beetsplug/ftintitle.py b/beetsplug/ftintitle.py index eefdfcf15..4e415b48d 100644 --- a/beetsplug/ftintitle.py +++ b/beetsplug/ftintitle.py @@ -22,6 +22,7 @@ import re from beets import plugins from beets import ui from beets.util import displayable_path +import six def split_on_feat(artist): @@ -137,7 +138,7 @@ class FtInTitlePlugin(plugins.BeetsPlugin): # Only update the title if it does not already contain a featured # artist and if we do not drop featuring information. if not drop_feat and not contains_feat(item.title): - feat_format = self.config['format'].get(unicode) + feat_format = self.config['format'].get(six.text_type) new_format = feat_format.format(feat_part) new_title = u"{0} {1}".format(item.title, new_format) self._log.info(u'title: {0} -> {1}', item.title, new_title) diff --git a/beetsplug/hook.py b/beetsplug/hook.py index 4f2b8f0e2..80daad68c 100644 --- a/beetsplug/hook.py +++ b/beetsplug/hook.py @@ -21,6 +21,7 @@ import subprocess from beets.plugins import BeetsPlugin from beets.ui import _arg_encoding from beets.util import shlex_split +import six class CodingFormatter(string.Formatter): @@ -79,8 +80,8 @@ class HookPlugin(BeetsPlugin): for hook_index in range(len(hooks)): hook = self.config['hooks'][hook_index] - hook_event = hook['event'].get(unicode) - hook_command = hook['command'].get(unicode) + hook_event = hook['event'].get(six.text_type) + hook_command = hook['command'].get(six.text_type) self.create_and_register_hook(hook_event, hook_command) diff --git a/beetsplug/importfeeds.py b/beetsplug/importfeeds.py index 0d9e50616..e02c5793f 100644 --- a/beetsplug/importfeeds.py +++ b/beetsplug/importfeeds.py @@ -14,6 +14,7 @@ # included in all copies or substantial portions of the Software. from __future__ import division, absolute_import, print_function +import six """Write paths of imported files in various formats to ease later import in a music player. Also allow printing the new file locations to stdout in case @@ -119,7 +120,7 @@ class ImportFeedsPlugin(BeetsPlugin): if 'm3u' in formats: m3u_basename = bytestring_path( - self.config['m3u_name'].get(unicode)) + self.config['m3u_name'].get(six.text_type)) m3u_path = os.path.join(feedsdir, m3u_basename) _write_m3u(m3u_path, paths) diff --git a/beetsplug/inline.py b/beetsplug/inline.py index 6e3771f2a..5787b739e 100644 --- a/beetsplug/inline.py +++ b/beetsplug/inline.py @@ -22,6 +22,7 @@ import itertools from beets.plugins import BeetsPlugin from beets import config +import six FUNC_NAME = u'__INLINE_FUNC__' @@ -32,7 +33,7 @@ class InlineError(Exception): def __init__(self, code, exc): super(InlineError, self).__init__( (u"error in inline path field code:\n" - u"%s\n%s: %s") % (code, type(exc).__name__, unicode(exc)) + u"%s\n%s: %s") % (code, type(exc).__name__, six.text_type(exc)) ) @@ -64,14 +65,14 @@ class InlinePlugin(BeetsPlugin): for key, view in itertools.chain(config['item_fields'].items(), config['pathfields'].items()): self._log.debug(u'adding item field {0}', key) - func = self.compile_inline(view.get(unicode), False) + func = self.compile_inline(view.get(six.text_type), False) if func is not None: self.template_fields[key] = func # Album fields. for key, view in config['album_fields'].items(): self._log.debug(u'adding album field {0}', key) - func = self.compile_inline(view.get(unicode), True) + func = self.compile_inline(view.get(six.text_type), True) if func is not None: self.album_template_fields[key] = func diff --git a/beetsplug/keyfinder.py b/beetsplug/keyfinder.py index b6131a4b0..dad62487f 100644 --- a/beetsplug/keyfinder.py +++ b/beetsplug/keyfinder.py @@ -23,6 +23,7 @@ import subprocess from beets import ui from beets import util from beets.plugins import BeetsPlugin +import six class KeyFinderPlugin(BeetsPlugin): @@ -52,7 +53,7 @@ class KeyFinderPlugin(BeetsPlugin): def find_key(self, items, write=False): overwrite = self.config['overwrite'].get(bool) - bin = util.bytestring_path(self.config['bin'].get(unicode)) + bin = util.bytestring_path(self.config['bin'].get(six.text_type)) for item in items: if item['initial_key'] and not overwrite: diff --git a/beetsplug/lastgenre/__init__.py b/beetsplug/lastgenre/__init__.py index 97daafb6b..abda7ed6b 100644 --- a/beetsplug/lastgenre/__init__.py +++ b/beetsplug/lastgenre/__init__.py @@ -14,6 +14,7 @@ # included in all copies or substantial portions of the Software. from __future__ import division, absolute_import, print_function +import six """Gets genres for imported music based on Last.fm tags. @@ -71,7 +72,7 @@ def flatten_tree(elem, path, branches): for sub in elem: flatten_tree(sub, path, branches) else: - branches.append(path + [unicode(elem)]) + branches.append(path + [six.text_type(elem)]) def find_parents(candidate, branches): @@ -186,7 +187,7 @@ class LastGenrePlugin(plugins.BeetsPlugin): # the original tags list tags = [x.title() for x in tags if self._is_allowed(x)] - return self.config['separator'].get(unicode).join( + return self.config['separator'].get(six.text_type).join( tags[:self.config['count'].get(int)] ) @@ -221,7 +222,8 @@ class LastGenrePlugin(plugins.BeetsPlugin): if any(not s for s in args): return None - key = u'{0}.{1}'.format(entity, u'-'.join(unicode(a) for a in args)) + key = u'{0}.{1}'.format(entity, + u'-'.join(six.text_type(a) for a in args)) if key in self._genre_cache: return self._genre_cache[key] else: @@ -297,7 +299,7 @@ class LastGenrePlugin(plugins.BeetsPlugin): result = None if isinstance(obj, library.Item): result = self.fetch_artist_genre(obj) - elif obj.albumartist != config['va_name'].get(unicode): + elif obj.albumartist != config['va_name'].get(six.text_type): result = self.fetch_album_artist_genre(obj) else: # For "Various Artists", pick the most popular track genre. diff --git a/beetsplug/lastimport.py b/beetsplug/lastimport.py index e31863da7..4d0557331 100644 --- a/beetsplug/lastimport.py +++ b/beetsplug/lastimport.py @@ -23,6 +23,7 @@ from beets import dbcore from beets import config from beets import plugins from beets.dbcore import types +import six API_URL = 'http://ws.audioscrobbler.com/2.0/' @@ -111,7 +112,7 @@ class CustomUser(pylast.User): def import_lastfm(lib, log): - user = config['lastfm']['user'].get(unicode) + user = config['lastfm']['user'].get(six.text_type) per_page = config['lastimport']['per_page'].get(int) if not user: diff --git a/beetsplug/lyrics.py b/beetsplug/lyrics.py index f7bc674fb..5d19b1dca 100644 --- a/beetsplug/lyrics.py +++ b/beetsplug/lyrics.py @@ -27,6 +27,7 @@ import unicodedata import warnings from six.moves.html_parser import HTMLParseError from six.moves import urllib +import six try: from bs4 import SoupStrainer, BeautifulSoup @@ -177,7 +178,7 @@ class Backend(object): @staticmethod def _encode(s): """Encode the string for inclusion in a URL""" - if isinstance(s, unicode): + if isinstance(s, six.text_type): for char, repl in URL_CHARACTERS.items(): s = s.replace(char, repl) s = s.encode('utf8', 'ignore') @@ -250,7 +251,7 @@ class Genius(Backend): """Fetch lyrics from Genius via genius-api.""" def __init__(self, config, log): super(Genius, self).__init__(config, log) - self.api_key = config['genius_api_key'].get(unicode) + self.api_key = config['genius_api_key'].get(six.text_type) self.headers = {'Authorization': "Bearer %s" % self.api_key} def search_genius(self, artist, title): @@ -461,8 +462,8 @@ class Google(Backend): """Fetch lyrics from Google search results.""" def __init__(self, config, log): super(Google, self).__init__(config, log) - self.api_key = config['google_API_key'].get(unicode) - self.engine_id = config['google_engine_ID'].get(unicode) + self.api_key = config['google_API_key'].get(six.text_type) + self.engine_id = config['google_engine_ID'].get(six.text_type) def is_lyrics(self, text, artist=None): """Determine whether the text seems to be valid lyrics. @@ -503,7 +504,7 @@ class Google(Backend): try: text = unicodedata.normalize('NFKD', text).encode('ascii', 'ignore') - text = unicode(re.sub('[-\s]+', ' ', text.decode('utf-8'))) + text = six.text_type(re.sub('[-\s]+', ' ', text.decode('utf-8'))) except UnicodeDecodeError: self._log.exception(u"Failing to normalize '{0}'", text) return text diff --git a/beetsplug/mbcollection.py b/beetsplug/mbcollection.py index b95ba6fed..0760be0e5 100644 --- a/beetsplug/mbcollection.py +++ b/beetsplug/mbcollection.py @@ -22,6 +22,7 @@ from beets import config import musicbrainzngs import re +import six SUBMISSION_CHUNK_SIZE = 200 UUID_REGEX = r'^[a-f0-9]{8}(-[a-f0-9]{4}){3}-[a-f0-9]{12}$' @@ -57,8 +58,8 @@ class MusicBrainzCollectionPlugin(BeetsPlugin): super(MusicBrainzCollectionPlugin, self).__init__() config['musicbrainz']['pass'].redact = True musicbrainzngs.auth( - config['musicbrainz']['user'].get(unicode), - config['musicbrainz']['pass'].get(unicode), + config['musicbrainz']['user'].get(six.text_type), + config['musicbrainz']['pass'].get(six.text_type), ) self.config.add({'auto': False}) if self.config['auto']: diff --git a/beetsplug/mpdstats.py b/beetsplug/mpdstats.py index fedf3276c..ca8dc9c7b 100644 --- a/beetsplug/mpdstats.py +++ b/beetsplug/mpdstats.py @@ -27,6 +27,7 @@ from beets import plugins from beets import library from beets.util import displayable_path from beets.dbcore import types +import six # If we lose the connection, how many times do we want to retry and how # much time should we wait between retries? @@ -49,7 +50,7 @@ def is_url(path): # see http://www.tarmack.eu/code/mpdunicode.py for the general idea class MPDClient(mpd.MPDClient): def _write_command(self, command, args=[]): - args = [unicode(arg).encode('utf-8') for arg in args] + args = [six.text_type(arg).encode('utf-8') for arg in args] super(MPDClient, self)._write_command(command, args) def _read_line(self): @@ -64,14 +65,14 @@ class MPDClientWrapper(object): self._log = log self.music_directory = ( - mpd_config['music_directory'].get(unicode)) + mpd_config['music_directory'].get(six.text_type)) self.client = MPDClient() def connect(self): """Connect to the MPD. """ - host = mpd_config['host'].get(unicode) + host = mpd_config['host'].get(six.text_type) port = mpd_config['port'].get(int) if host[0] in ['/', '~']: @@ -83,7 +84,7 @@ class MPDClientWrapper(object): except socket.error as e: raise ui.UserError(u'could not connect to MPD: {0}'.format(e)) - password = mpd_config['password'].get(unicode) + password = mpd_config['password'].get(six.text_type) if password: try: self.client.password(password) diff --git a/beetsplug/mpdupdate.py b/beetsplug/mpdupdate.py index f828ba5d7..36449a5ac 100644 --- a/beetsplug/mpdupdate.py +++ b/beetsplug/mpdupdate.py @@ -27,6 +27,7 @@ from beets.plugins import BeetsPlugin import os import socket from beets import config +import six # No need to introduce a dependency on an MPD library for such a @@ -86,9 +87,9 @@ class MPDUpdatePlugin(BeetsPlugin): def update(self, lib): self.update_mpd( - config['mpd']['host'].get(unicode), + config['mpd']['host'].get(six.text_type), config['mpd']['port'].get(int), - config['mpd']['password'].get(unicode), + config['mpd']['password'].get(six.text_type), ) def update_mpd(self, host='localhost', port=6600, password=None): @@ -101,7 +102,7 @@ class MPDUpdatePlugin(BeetsPlugin): s = BufferedSocket(host, port) except socket.error as e: self._log.warning(u'MPD connection failed: {0}', - unicode(e.strerror)) + six.text_type(e.strerror)) return resp = s.readline() diff --git a/beetsplug/replaygain.py b/beetsplug/replaygain.py index e06407037..27659ca27 100644 --- a/beetsplug/replaygain.py +++ b/beetsplug/replaygain.py @@ -27,6 +27,7 @@ from beets import logging from beets import ui from beets.plugins import BeetsPlugin from beets.util import syspath, command_output, displayable_path +import six # Utilities. @@ -102,7 +103,7 @@ class Bs1770gainBackend(Backend): 'method': 'replaygain', }) self.chunk_at = config['chunk_at'].as_number() - self.method = b'--' + bytes(config['method'].get(unicode)) + self.method = b'--' + bytes(config['method'].get(six.text_type)) cmd = b'bs1770gain' try: @@ -256,7 +257,7 @@ class CommandBackend(Backend): 'noclip': True, }) - self.command = config["command"].get(unicode) + self.command = config["command"].get(six.text_type) if self.command: # Explicit executable path. @@ -809,7 +810,7 @@ class ReplayGainPlugin(BeetsPlugin): }) self.overwrite = self.config['overwrite'].get(bool) - backend_name = self.config['backend'].get(unicode) + backend_name = self.config['backend'].get(six.text_type) if backend_name not in self.backends: raise ui.UserError( u"Selected ReplayGain backend {0} is not supported. " diff --git a/beetsplug/rewrite.py b/beetsplug/rewrite.py index b0104a118..ef9aa0c9a 100644 --- a/beetsplug/rewrite.py +++ b/beetsplug/rewrite.py @@ -24,6 +24,7 @@ from collections import defaultdict from beets.plugins import BeetsPlugin from beets import ui from beets import library +import six def rewriter(field, rules): @@ -51,7 +52,7 @@ class RewritePlugin(BeetsPlugin): # Gather all the rewrite rules for each field. rules = defaultdict(list) for key, view in self.config.items(): - value = view.get(unicode) + value = view.get(six.text_type) try: fieldname, pattern = key.split(None, 1) except ValueError: diff --git a/beetsplug/spotify.py b/beetsplug/spotify.py index 77df15790..33570b5e4 100644 --- a/beetsplug/spotify.py +++ b/beetsplug/spotify.py @@ -9,6 +9,7 @@ from beets.plugins import BeetsPlugin from beets.ui import decargs from beets import ui from requests.exceptions import HTTPError +import six class SpotifyPlugin(BeetsPlugin): @@ -170,6 +171,6 @@ class SpotifyPlugin(BeetsPlugin): else: for item in ids: - print(unicode.encode(self.open_url + item)) + print(six.text_type.encode(self.open_url + item)) else: self._log.warn(u'No Spotify tracks found from beets query') diff --git a/beetsplug/the.py b/beetsplug/the.py index 6bed4c6ed..149233c45 100644 --- a/beetsplug/the.py +++ b/beetsplug/the.py @@ -19,6 +19,7 @@ from __future__ import division, absolute_import, print_function import re from beets.plugins import BeetsPlugin +import six __author__ = 'baobab@heresiarch.info' __version__ = '1.1' @@ -81,7 +82,7 @@ class ThePlugin(BeetsPlugin): if self.config['strip']: return r else: - fmt = self.config['format'].get(unicode) + fmt = self.config['format'].get(six.text_type) return fmt.format(r, t.strip()).strip() else: return u'' diff --git a/beetsplug/thumbnails.py b/beetsplug/thumbnails.py index ce0a9490e..1ea90f01e 100644 --- a/beetsplug/thumbnails.py +++ b/beetsplug/thumbnails.py @@ -35,6 +35,7 @@ from beets.plugins import BeetsPlugin from beets.ui import Subcommand, decargs from beets import util from beets.util.artresizer import ArtResizer, get_im_version, get_pil_version +import six BASE_DIR = os.path.join(BaseDirectory.xdg_cache_home, "thumbnails") @@ -169,8 +170,9 @@ class ThumbnailsPlugin(BeetsPlugin): """Write required metadata to the thumbnail See http://standards.freedesktop.org/thumbnail-spec/latest/x142.html """ + mtime = os.stat(album.artpath).st_mtime metadata = {"Thumb::URI": self.get_uri(album.artpath), - "Thumb::MTime": unicode(os.stat(album.artpath).st_mtime)} + "Thumb::MTime": six.text_type(mtime)} try: self.write_metadata(image_path, metadata) except Exception: diff --git a/beetsplug/web/__init__.py b/beetsplug/web/__init__.py index 67d99db67..6f480fb36 100644 --- a/beetsplug/web/__init__.py +++ b/beetsplug/web/__init__.py @@ -25,6 +25,7 @@ from flask import g from werkzeug.routing import BaseConverter, PathConverter import os import json +import six # Utilities. @@ -321,7 +322,7 @@ class WebPlugin(BeetsPlugin): } CORS(app) # Start the web application. - app.run(host=self.config['host'].get(unicode), + app.run(host=self.config['host'].get(six.text_type), port=self.config['port'].get(int), debug=opts.debug, threaded=True) cmd.func = func diff --git a/beetsplug/zero.py b/beetsplug/zero.py index d20f76166..80925741b 100644 --- a/beetsplug/zero.py +++ b/beetsplug/zero.py @@ -22,6 +22,7 @@ from beets.plugins import BeetsPlugin from beets.mediafile import MediaFile from beets.importer import action from beets.util import confit +import six __author__ = 'baobab@heresiarch.info' __version__ = '0.10' @@ -113,7 +114,7 @@ class ZeroPlugin(BeetsPlugin): if patterns is True: return True for p in patterns: - if re.search(p, unicode(field), flags=re.IGNORECASE): + if re.search(p, six.text_type(field), flags=re.IGNORECASE): return True return False diff --git a/test/helper.py b/test/helper.py index d2fe5cc81..0d37e90eb 100644 --- a/test/helper.py +++ b/test/helper.py @@ -56,6 +56,7 @@ from beets import util # TODO Move AutotagMock here from test import _common +import six class LogCapture(logging.Handler): @@ -65,7 +66,7 @@ class LogCapture(logging.Handler): self.messages = [] def emit(self, record): - self.messages.append(unicode(record.msg)) + self.messages.append(six.text_type(record.msg)) @contextmanager @@ -121,7 +122,7 @@ def has_program(cmd, args=['--version']): """ full_cmd = [cmd] + args for i, elem in enumerate(full_cmd): - if isinstance(elem, unicode): + if isinstance(elem, six.text_type): full_cmd[i] = elem.encode(_arg_encoding()) try: with open(os.devnull, 'wb') as devnull: diff --git a/test/test_config_command.py b/test/test_config_command.py index 77a370ce3..d59181373 100644 --- a/test/test_config_command.py +++ b/test/test_config_command.py @@ -14,6 +14,7 @@ from beets import config from test._common import unittest from test.helper import TestHelper, capture_stdout from beets.library import Library +import six class ConfigCommandTest(unittest.TestCase, TestHelper): @@ -114,8 +115,8 @@ class ConfigCommandTest(unittest.TestCase, TestHelper): execlp.side_effect = OSError('here is problem') self.run_command('config', '-e') self.assertIn('Could not edit configuration', - unicode(user_error.exception)) - self.assertIn('here is problem', unicode(user_error.exception)) + six.text_type(user_error.exception)) + self.assertIn('here is problem', six.text_type(user_error.exception)) def test_edit_invalid_config_file(self): self.lib = Library(':memory:') diff --git a/test/test_dbcore.py b/test/test_dbcore.py index 67a96e4f2..8fc8532c6 100644 --- a/test/test_dbcore.py +++ b/test/test_dbcore.py @@ -26,6 +26,7 @@ from test import _common from test._common import unittest from beets import dbcore from tempfile import mkstemp +import six # Fixture: concrete database and model classes. For migration tests, we @@ -350,7 +351,7 @@ class FormatTest(unittest.TestCase): model = TestModel1() model.other_field = u'caf\xe9'.encode('utf8') value = model.formatted().get('other_field') - self.assertTrue(isinstance(value, unicode)) + self.assertTrue(isinstance(value, six.text_type)) self.assertEqual(value, u'caf\xe9') def test_format_unset_field(self): diff --git a/test/test_library.py b/test/test_library.py index 4cd922910..b1ac76c25 100644 --- a/test/test_library.py +++ b/test/test_library.py @@ -38,6 +38,7 @@ from beets import config from beets.mediafile import MediaFile from beets.util import syspath, bytestring_path from test.helper import TestHelper +import six # Shortcut to path normalization. np = util.normpath @@ -964,7 +965,7 @@ class PathStringTest(_common.TestCase): def test_sanitize_path_returns_unicode(self): path = u'b\xe1r?' new_path = util.sanitize_path(path) - self.assertTrue(isinstance(new_path, unicode)) + self.assertTrue(isinstance(new_path, six.text_type)) def test_unicode_artpath_becomes_bytestring(self): alb = self.lib.add_album([self.i]) @@ -1051,7 +1052,7 @@ class TemplateTest(_common.LibTestCase): album.tagada = u'togodo' self.assertEqual(u"{0}".format(album), u"foö bar") self.assertEqual(u"{0:$tagada}".format(album), u"togodo") - self.assertEqual(unicode(album), u"foö bar") + self.assertEqual(six.text_type(album), u"foö bar") self.assertEqual(bytes(album), b"fo\xc3\xb6 bar") config['format_item'] = 'bar $foo' @@ -1174,7 +1175,8 @@ class LibraryFieldTypesTest(unittest.TestCase): t = beets.library.DateType() # format - time_local = time.strftime(beets.config['time_format'].get(unicode), + time_format = beets.config['time_format'].get(six.text_type) + time_local = time.strftime(time_format, time.localtime(123456789)) self.assertEqual(time_local, t.format(123456789)) # parse diff --git a/test/test_lyrics.py b/test/test_lyrics.py index 9136131c1..d49c4d980 100644 --- a/test/test_lyrics.py +++ b/test/test_lyrics.py @@ -29,6 +29,7 @@ from beetsplug import lyrics from beets.library import Item from beets.util import confit, bytestring_path from beets import logging +import six log = logging.getLogger('beets.test_lyrics') raw_backend = lyrics.Backend({}, log) @@ -354,7 +355,7 @@ class LyricsGooglePluginTest(unittest.TestCase): present in the title.""" from bs4 import SoupStrainer, BeautifulSoup s = self.source - url = unicode(s['url'] + s['path']) + url = six.text_type(s['url'] + s['path']) html = raw_backend.fetch_url(url) soup = BeautifulSoup(html, "html.parser", parse_only=SoupStrainer('title')) diff --git a/test/test_mediafile.py b/test/test_mediafile.py index 2405e7fd3..258e03896 100644 --- a/test/test_mediafile.py +++ b/test/test_mediafile.py @@ -33,6 +33,7 @@ from beets.mediafile import MediaFile, MediaField, Image, \ from beets.library import Item from beets.plugins import BeetsPlugin from beets.util import bytestring_path +import six class ArtTestMixin(object): @@ -353,13 +354,13 @@ class ExtendedFieldTestMixin(object): with self.assertRaises(ValueError) as cm: MediaFile.add_field('somekey', True) self.assertIn(u'must be an instance of MediaField', - unicode(cm.exception)) + six.text_type(cm.exception)) def test_overwrite_property(self): with self.assertRaises(ValueError) as cm: MediaFile.add_field('artist', MediaField()) self.assertIn(u'property "artist" already exists', - unicode(cm.exception)) + six.text_type(cm.exception)) class ReadWriteTestBase(ArtTestMixin, GenreListTestMixin, diff --git a/test/test_mediafile_edge.py b/test/test_mediafile_edge.py index 26d88ae74..9fbf4e2bb 100644 --- a/test/test_mediafile_edge.py +++ b/test/test_mediafile_edge.py @@ -26,6 +26,7 @@ from test.helper import TestHelper from beets.util import bytestring_path import beets.mediafile +import six _sc = beets.mediafile._safe_cast @@ -127,8 +128,8 @@ class InvalidValueToleranceTest(unittest.TestCase): self.assertAlmostEqual(_sc(float, u'-1.234'), -1.234) def test_safe_cast_special_chars_to_unicode(self): - us = _sc(unicode, 'caf\xc3\xa9') - self.assertTrue(isinstance(us, unicode)) + us = _sc(six.text_type, 'caf\xc3\xa9') + self.assertTrue(isinstance(us, six.text_type)) self.assertTrue(us.startswith(u'caf')) def test_safe_cast_float_with_no_numbers(self): @@ -350,7 +351,7 @@ class ID3v23Test(unittest.TestCase, TestHelper): mf.year = 2013 mf.save() frame = mf.mgfile['TDRC'] - self.assertTrue('2013' in unicode(frame)) + self.assertTrue('2013' in six.text_type(frame)) self.assertTrue('TYER' not in mf.mgfile) finally: self._delete_test() @@ -361,7 +362,7 @@ class ID3v23Test(unittest.TestCase, TestHelper): mf.year = 2013 mf.save() frame = mf.mgfile['TYER'] - self.assertTrue('2013' in unicode(frame)) + self.assertTrue('2013' in six.text_type(frame)) self.assertTrue('TDRC' not in mf.mgfile) finally: self._delete_test() diff --git a/test/test_query.py b/test/test_query.py index 707d9d182..d9b181930 100644 --- a/test/test_query.py +++ b/test/test_query.py @@ -33,6 +33,7 @@ from beets.dbcore.query import (NoneQuery, ParsingError, from beets.library import Library, Item from beets import util import platform +import six class TestHelper(helper.TestHelper): @@ -301,12 +302,13 @@ class GetTest(DummyDataTestCase): def test_invalid_query(self): with self.assertRaises(InvalidQueryArgumentTypeError) as raised: dbcore.query.NumericQuery('year', u'199a') - self.assertIn(u'not an int', unicode(raised.exception)) + self.assertIn(u'not an int', six.text_type(raised.exception)) with self.assertRaises(InvalidQueryArgumentTypeError) as raised: dbcore.query.RegexpQuery('year', u'199(') - self.assertIn(u'not a regular expression', unicode(raised.exception)) - self.assertIn(u'unbalanced parenthesis', unicode(raised.exception)) + exception = six.text_type(raised.exception) + self.assertIn(u'not a regular expression', exception) + self.assertIn(u'unbalanced parenthesis', exception) self.assertIsInstance(raised.exception, ParsingError) diff --git a/test/test_template.py b/test/test_template.py index 3ec97bea4..868696a67 100644 --- a/test/test_template.py +++ b/test/test_template.py @@ -21,6 +21,7 @@ import warnings from test._common import unittest from beets.util import functemplate +import six def _normexpr(expr): @@ -227,7 +228,7 @@ class EvalTest(unittest.TestCase): u'baz': u'BaR', } functions = { - u'lower': unicode.lower, + u'lower': six.text_type.lower, u'len': len, } return functemplate.Template(template).substitute(values, functions) diff --git a/test/test_ui.py b/test/test_ui.py index d14febbff..78d777f9e 100644 --- a/test/test_ui.py +++ b/test/test_ui.py @@ -39,6 +39,7 @@ from beets import config from beets import plugins from beets.util.confit import ConfigError from beets import util +import six class ListTest(unittest.TestCase): @@ -1257,15 +1258,15 @@ class CommonOptionsParserTest(unittest.TestCase, TestHelper): config['format_item'].set('$foo') self.assertEqual(parser.parse_args([]), ({'path': None}, [])) - self.assertEqual(config['format_item'].get(unicode), u'$foo') + self.assertEqual(config['format_item'].get(six.text_type), u'$foo') self.assertEqual(parser.parse_args([u'-p']), ({'path': True, 'format': u'$path'}, [])) self.assertEqual(parser.parse_args(['--path']), ({'path': True, 'format': u'$path'}, [])) - self.assertEqual(config['format_item'].get(unicode), u'$path') - self.assertEqual(config['format_album'].get(unicode), u'$path') + self.assertEqual(config['format_item'].get(six.text_type), u'$path') + self.assertEqual(config['format_album'].get(six.text_type), u'$path') def test_format_option(self): parser = ui.CommonOptionsParser() @@ -1274,15 +1275,15 @@ class CommonOptionsParserTest(unittest.TestCase, TestHelper): config['format_item'].set('$foo') self.assertEqual(parser.parse_args([]), ({'format': None}, [])) - self.assertEqual(config['format_item'].get(unicode), u'$foo') + self.assertEqual(config['format_item'].get(six.text_type), u'$foo') self.assertEqual(parser.parse_args([u'-f', u'$bar']), ({'format': u'$bar'}, [])) self.assertEqual(parser.parse_args([u'--format', u'$baz']), ({'format': u'$baz'}, [])) - self.assertEqual(config['format_item'].get(unicode), u'$baz') - self.assertEqual(config['format_album'].get(unicode), u'$baz') + self.assertEqual(config['format_item'].get(six.text_type), u'$baz') + self.assertEqual(config['format_album'].get(six.text_type), u'$baz') def test_format_option_with_target(self): with self.assertRaises(KeyError): @@ -1297,8 +1298,8 @@ class CommonOptionsParserTest(unittest.TestCase, TestHelper): self.assertEqual(parser.parse_args([u'-f', u'$bar']), ({'format': u'$bar'}, [])) - self.assertEqual(config['format_item'].get(unicode), u'$bar') - self.assertEqual(config['format_album'].get(unicode), u'$album') + self.assertEqual(config['format_item'].get(six.text_type), u'$bar') + self.assertEqual(config['format_album'].get(six.text_type), u'$album') def test_format_option_with_album(self): parser = ui.CommonOptionsParser() @@ -1309,15 +1310,15 @@ class CommonOptionsParserTest(unittest.TestCase, TestHelper): config['format_album'].set('$album') parser.parse_args([u'-f', u'$bar']) - self.assertEqual(config['format_item'].get(unicode), u'$bar') - self.assertEqual(config['format_album'].get(unicode), u'$album') + self.assertEqual(config['format_item'].get(six.text_type), u'$bar') + self.assertEqual(config['format_album'].get(six.text_type), u'$album') parser.parse_args([u'-a', u'-f', u'$foo']) - self.assertEqual(config['format_item'].get(unicode), u'$bar') - self.assertEqual(config['format_album'].get(unicode), u'$foo') + self.assertEqual(config['format_item'].get(six.text_type), u'$bar') + self.assertEqual(config['format_album'].get(six.text_type), u'$foo') parser.parse_args([u'-f', u'$foo2', u'-a']) - self.assertEqual(config['format_album'].get(unicode), u'$foo2') + self.assertEqual(config['format_album'].get(six.text_type), u'$foo2') def test_add_all_common_options(self): parser = ui.CommonOptionsParser() diff --git a/test/test_ui_importer.py b/test/test_ui_importer.py index 4596e781a..cc2938ad3 100644 --- a/test/test_ui_importer.py +++ b/test/test_ui_importer.py @@ -26,6 +26,7 @@ from test import test_importer from beets.ui.commands import TerminalImportSession from beets import importer from beets import config +import six class TestTerminalImportSession(TerminalImportSession): @@ -69,7 +70,7 @@ class TestTerminalImportSession(TerminalImportSession): self.io.addinput(u'S') elif isinstance(choice, int): self.io.addinput(u'M') - self.io.addinput(unicode(choice)) + self.io.addinput(six.text_type(choice)) self._add_choice_input() else: raise Exception(u'Unknown choice %s' % choice) diff --git a/test/test_util.py b/test/test_util.py index 32028c9fb..f4c2eca80 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -26,6 +26,7 @@ from mock import patch, Mock from test._common import unittest from test import _common from beets import util +import six class UtilTest(unittest.TestCase): @@ -122,7 +123,7 @@ class PathConversionTest(_common.TestCase): with _common.platform_windows(): path = os.path.join(u'a', u'b', u'c') outpath = util.syspath(path) - self.assertTrue(isinstance(outpath, unicode)) + self.assertTrue(isinstance(outpath, six.text_type)) self.assertTrue(outpath.startswith(u'\\\\?\\')) def test_syspath_windows_format_unc_path(self): @@ -131,7 +132,7 @@ class PathConversionTest(_common.TestCase): path = '\\\\server\\share\\file.mp3' with _common.platform_windows(): outpath = util.syspath(path) - self.assertTrue(isinstance(outpath, unicode)) + self.assertTrue(isinstance(outpath, six.text_type)) self.assertEqual(outpath, u'\\\\?\\UNC\\server\\share\\file.mp3') def test_syspath_posix_unchanged(self):