mirror of
https://github.com/beetbox/beets.git
synced 2025-12-28 19:42:42 +01:00
Merge pull request #2066 from beetbox/use-six
Use the six package to handle py2/p3 compatibility
This commit is contained in:
commit
736ad66518
84 changed files with 479 additions and 369 deletions
|
|
@ -25,6 +25,7 @@ from beets import config
|
|||
from .hooks import AlbumInfo, TrackInfo, AlbumMatch, TrackMatch # noqa
|
||||
from .match import tag_item, tag_album # noqa
|
||||
from .match import Recommendation # noqa
|
||||
import six
|
||||
|
||||
# Global logger.
|
||||
log = logging.getLogger('beets')
|
||||
|
|
@ -52,7 +53,7 @@ def apply_metadata(album_info, mapping):
|
|||
"""Set the items' metadata to match an AlbumInfo object using a
|
||||
mapping from Items to TrackInfo objects.
|
||||
"""
|
||||
for item, track_info in mapping.iteritems():
|
||||
for item, track_info in six.iteritems(mapping):
|
||||
# Album, artist, track count.
|
||||
if track_info.artist:
|
||||
item.artist = track_info.artist
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
@ -291,6 +292,7 @@ class LazyClassProperty(object):
|
|||
|
||||
|
||||
@total_ordering
|
||||
@six.python_2_unicode_compatible
|
||||
class Distance(object):
|
||||
"""Keeps track of multiple distance penalties. Provides a single
|
||||
weighted distance for all penalties as well as a weighted distance
|
||||
|
|
@ -326,7 +328,7 @@ class Distance(object):
|
|||
"""Return the maximum distance penalty (normalization factor).
|
||||
"""
|
||||
dist_max = 0.0
|
||||
for key, penalty in self._penalties.iteritems():
|
||||
for key, penalty in six.iteritems(self._penalties):
|
||||
dist_max += len(penalty) * self._weights[key]
|
||||
return dist_max
|
||||
|
||||
|
|
@ -335,7 +337,7 @@ class Distance(object):
|
|||
"""Return the raw (denormalized) distance.
|
||||
"""
|
||||
dist_raw = 0.0
|
||||
for key, penalty in self._penalties.iteritems():
|
||||
for key, penalty in six.iteritems(self._penalties):
|
||||
dist_raw += sum(penalty) * self._weights[key]
|
||||
return dist_raw
|
||||
|
||||
|
|
@ -377,7 +379,9 @@ class Distance(object):
|
|||
def __rsub__(self, other):
|
||||
return other - self.distance
|
||||
|
||||
def __unicode__(self):
|
||||
# Behave like a string
|
||||
|
||||
def __str__(self):
|
||||
return "{0:.2f}".format(self.distance)
|
||||
|
||||
# Behave like a dict.
|
||||
|
|
@ -407,7 +411,7 @@ class Distance(object):
|
|||
raise ValueError(
|
||||
u'`dist` must be a Distance object, not {0}'.format(type(dist))
|
||||
)
|
||||
for key, penalties in dist._penalties.iteritems():
|
||||
for key, penalties in six.iteritems(dist._penalties):
|
||||
self._penalties.setdefault(key, []).extend(penalties)
|
||||
|
||||
# Adding components.
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ from beets.util import plurality
|
|||
from beets.autotag import hooks
|
||||
from beets.util.enumeration import OrderedEnum
|
||||
from functools import reduce
|
||||
import six
|
||||
|
||||
# Artist signals that indicate "various artists". These are used at the
|
||||
# album level to determine whether a given release is likely a VA
|
||||
|
|
@ -238,7 +239,7 @@ def distance(items, album_info, mapping):
|
|||
|
||||
# Tracks.
|
||||
dist.tracks = {}
|
||||
for item, track in mapping.iteritems():
|
||||
for item, track in six.iteritems(mapping):
|
||||
dist.tracks[track] = track_distance(item, track, album_info.va)
|
||||
dist.add('tracks', dist.tracks[track].distance)
|
||||
|
||||
|
|
@ -312,10 +313,10 @@ def _recommendation(results):
|
|||
keys = set(min_dist.keys())
|
||||
if isinstance(results[0], hooks.AlbumMatch):
|
||||
for track_dist in min_dist.tracks.values():
|
||||
keys.update(track_dist.keys())
|
||||
keys.update(list(track_dist.keys()))
|
||||
max_rec_view = config['match']['max_rec']
|
||||
for key in keys:
|
||||
if key in max_rec_view.keys():
|
||||
if key in list(max_rec_view.keys()):
|
||||
max_rec = max_rec_view[key].as_choice({
|
||||
'strong': Recommendation.strong,
|
||||
'medium': Recommendation.medium,
|
||||
|
|
@ -443,7 +444,7 @@ def tag_album(items, search_artist=None, search_album=None,
|
|||
_add_candidate(items, candidates, info)
|
||||
|
||||
# Sort and get the recommendation.
|
||||
candidates = sorted(candidates.itervalues())
|
||||
candidates = sorted(six.itervalues(candidates))
|
||||
rec = _recommendation(candidates)
|
||||
return cur_artist, cur_album, candidates, rec
|
||||
|
||||
|
|
@ -471,16 +472,16 @@ def tag_item(item, search_artist=None, search_title=None,
|
|||
candidates[track_info.track_id] = \
|
||||
hooks.TrackMatch(dist, track_info)
|
||||
# If this is a good match, then don't keep searching.
|
||||
rec = _recommendation(sorted(candidates.itervalues()))
|
||||
rec = _recommendation(sorted(six.itervalues(candidates)))
|
||||
if rec == Recommendation.strong and \
|
||||
not config['import']['timid']:
|
||||
log.debug(u'Track ID match.')
|
||||
return sorted(candidates.itervalues()), rec
|
||||
return sorted(six.itervalues(candidates)), rec
|
||||
|
||||
# If we're searching by ID, don't proceed.
|
||||
if search_ids:
|
||||
if candidates:
|
||||
return sorted(candidates.itervalues()), rec
|
||||
return sorted(six.itervalues(candidates)), rec
|
||||
else:
|
||||
return [], Recommendation.none
|
||||
|
||||
|
|
@ -496,6 +497,6 @@ def tag_item(item, search_artist=None, search_title=None,
|
|||
|
||||
# Sort by distance and return with recommendation.
|
||||
log.debug(u'Found {0} candidates.', len(candidates))
|
||||
candidates = sorted(candidates.itervalues())
|
||||
candidates = sorted(six.itervalues(candidates))
|
||||
rec = _recommendation(candidates)
|
||||
return candidates, rec
|
||||
|
|
|
|||
|
|
@ -20,13 +20,14 @@ from __future__ import division, absolute_import, print_function
|
|||
import musicbrainzngs
|
||||
import re
|
||||
import traceback
|
||||
from urlparse import urljoin
|
||||
from six.moves.urllib.parse import urljoin
|
||||
|
||||
from beets import logging
|
||||
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),
|
||||
|
|
@ -108,7 +110,7 @@ def _flatten_artist_credit(credit):
|
|||
artist_sort_parts = []
|
||||
artist_credit_parts = []
|
||||
for el in credit:
|
||||
if isinstance(el, basestring):
|
||||
if isinstance(el, six.string_types):
|
||||
# Join phrase.
|
||||
artist_parts.append(el)
|
||||
artist_credit_parts.append(el)
|
||||
|
|
@ -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,10 +331,10 @@ 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()):
|
||||
if not any(six.itervalues(criteria)):
|
||||
return
|
||||
|
||||
try:
|
||||
|
|
@ -358,7 +360,7 @@ def match_track(artist, title):
|
|||
'recording': title.lower().strip(),
|
||||
}
|
||||
|
||||
if not any(criteria.itervalues()):
|
||||
if not any(six.itervalues(criteria)):
|
||||
return
|
||||
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -176,9 +177,9 @@ class Model(object):
|
|||
ordinary construction are bypassed.
|
||||
"""
|
||||
obj = cls(db)
|
||||
for key, value in fixed_values.iteritems():
|
||||
for key, value in six.iteritems(fixed_values):
|
||||
obj._values_fixed[key] = cls._type(key).from_sql(value)
|
||||
for key, value in flex_values.iteritems():
|
||||
for key, value in six.iteritems(flex_values):
|
||||
obj._values_flex[key] = cls._type(key).from_sql(value)
|
||||
return obj
|
||||
|
||||
|
|
@ -452,7 +453,7 @@ class Model(object):
|
|||
separators will be added to the template.
|
||||
"""
|
||||
# Perform substitution.
|
||||
if isinstance(template, basestring):
|
||||
if isinstance(template, six.string_types):
|
||||
template = Template(template)
|
||||
return template.substitute(self.formatted(for_path),
|
||||
self._template_funcs())
|
||||
|
|
@ -463,7 +464,7 @@ class Model(object):
|
|||
def _parse(cls, key, string):
|
||||
"""Parse a string as a value for the given key.
|
||||
"""
|
||||
if not isinstance(string, basestring):
|
||||
if not isinstance(string, six.string_types):
|
||||
raise TypeError(u"_parse() argument must be a string")
|
||||
|
||||
return cls._type(key).parse(string)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,10 @@ from beets import util
|
|||
from datetime import datetime, timedelta
|
||||
import unicodedata
|
||||
from functools import reduce
|
||||
import six
|
||||
|
||||
if not six.PY2:
|
||||
buffer = memoryview # sqlite won't accept memoryview in python 2
|
||||
|
||||
|
||||
class ParsingError(ValueError):
|
||||
|
|
@ -229,7 +233,7 @@ class BooleanQuery(MatchQuery):
|
|||
"""
|
||||
def __init__(self, field, pattern, fast=True):
|
||||
super(BooleanQuery, self).__init__(field, pattern, fast)
|
||||
if isinstance(pattern, basestring):
|
||||
if isinstance(pattern, six.string_types):
|
||||
self.pattern = util.str2bool(pattern)
|
||||
self.pattern = int(self.pattern)
|
||||
|
||||
|
|
@ -243,11 +247,11 @@ class BytesQuery(MatchQuery):
|
|||
def __init__(self, field, pattern):
|
||||
super(BytesQuery, self).__init__(field, pattern)
|
||||
|
||||
# Use a buffer representation of the pattern for SQLite
|
||||
# Use a buffer/memoryview 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):
|
||||
|
|
@ -302,7 +306,7 @@ class NumericQuery(FieldQuery):
|
|||
if self.field not in item:
|
||||
return False
|
||||
value = item[self.field]
|
||||
if isinstance(value, basestring):
|
||||
if isinstance(value, six.string_types):
|
||||
value = self._convert(value)
|
||||
|
||||
if self.point is not None:
|
||||
|
|
@ -793,7 +797,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
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ from __future__ import division, absolute_import, print_function
|
|||
|
||||
from . import query
|
||||
from beets.util import str2bool
|
||||
import six
|
||||
|
||||
if not six.PY2:
|
||||
buffer = memoryview # sqlite won't accept memoryview in python 2
|
||||
|
||||
|
||||
# Abstract base.
|
||||
|
|
@ -37,7 +41,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 +67,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
|
||||
|
|
@ -97,12 +101,12 @@ class Type(object):
|
|||
https://docs.python.org/2/library/sqlite3.html#sqlite-and-python-types
|
||||
|
||||
Flexible fields have the type affinity `TEXT`. This means the
|
||||
`sql_value` is either a `buffer` or a `unicode` object` and the
|
||||
method must handle these in addition.
|
||||
`sql_value` is either a `buffer`/`memoryview` or a `unicode` object`
|
||||
and the method must handle these in addition.
|
||||
"""
|
||||
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 +198,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)
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import sys
|
|||
import unicodedata
|
||||
import time
|
||||
import re
|
||||
import six
|
||||
from unidecode import unidecode
|
||||
|
||||
from beets import logging
|
||||
|
|
@ -34,6 +35,8 @@ from beets import dbcore
|
|||
from beets.dbcore import types
|
||||
import beets
|
||||
|
||||
if not six.PY2:
|
||||
buffer = memoryview # sqlite won't accept memoryview in python 2
|
||||
|
||||
log = logging.getLogger('beets')
|
||||
|
||||
|
|
@ -123,14 +126,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.
|
||||
|
|
@ -152,13 +156,13 @@ 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)
|
||||
|
||||
elif isinstance(value, buffer):
|
||||
# SQLite must store bytestings as buffers to avoid decoding.
|
||||
# We unwrap buffers to bytes.
|
||||
# SQLite must store bytestings as buffers/memoryview
|
||||
# to avoid decoding. We unwrap buffers to bytes.
|
||||
return bytes(value)
|
||||
|
||||
else:
|
||||
|
|
@ -260,7 +264,7 @@ PF_KEY_DEFAULT = 'default'
|
|||
|
||||
|
||||
# Exceptions.
|
||||
|
||||
@six.python_2_unicode_compatible
|
||||
class FileOperationError(Exception):
|
||||
"""Indicates an error when interacting with a file on disk.
|
||||
Possibilities include an unsupported media type, a permissions
|
||||
|
|
@ -274,35 +278,39 @@ class FileOperationError(Exception):
|
|||
self.path = path
|
||||
self.reason = reason
|
||||
|
||||
def __unicode__(self):
|
||||
def text(self):
|
||||
"""Get a string representing the error. Describes both the
|
||||
underlying reason and the file path in question.
|
||||
"""
|
||||
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')
|
||||
# define __str__ as text to avoid infinite loop on super() calls
|
||||
# with @six.python_2_unicode_compatible
|
||||
__str__ = text
|
||||
|
||||
|
||||
@six.python_2_unicode_compatible
|
||||
class ReadError(FileOperationError):
|
||||
"""An error while reading a file (i.e. in `Item.read`).
|
||||
"""
|
||||
def __unicode__(self):
|
||||
return u'error reading ' + super(ReadError, self).__unicode__()
|
||||
def __str__(self):
|
||||
return u'error reading ' + super(ReadError, self).text()
|
||||
|
||||
|
||||
@six.python_2_unicode_compatible
|
||||
class WriteError(FileOperationError):
|
||||
"""An error while writing a file (i.e. in `Item.write`).
|
||||
"""
|
||||
def __unicode__(self):
|
||||
return u'error writing ' + super(WriteError, self).__unicode__()
|
||||
def __str__(self):
|
||||
return u'error writing ' + super(WriteError, self).text()
|
||||
|
||||
|
||||
# Item and Album model classes.
|
||||
|
||||
@six.python_2_unicode_compatible
|
||||
class LibModel(dbcore.Model):
|
||||
"""Shared concrete functionality for Items and Albums.
|
||||
"""
|
||||
|
|
@ -330,7 +338,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
|
||||
|
|
@ -339,9 +347,6 @@ class LibModel(dbcore.Model):
|
|||
return result
|
||||
|
||||
def __str__(self):
|
||||
return format(self).encode('utf8')
|
||||
|
||||
def __unicode__(self):
|
||||
return format(self)
|
||||
|
||||
|
||||
|
|
@ -516,7 +521,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)
|
||||
|
|
@ -565,7 +570,7 @@ class Item(LibModel):
|
|||
|
||||
for key in self._media_fields:
|
||||
value = getattr(mediafile, key)
|
||||
if isinstance(value, (int, long)):
|
||||
if isinstance(value, six.integer_types):
|
||||
if value.bit_length() > 63:
|
||||
value = 0
|
||||
self[key] = value
|
||||
|
|
@ -1060,7 +1065,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)
|
||||
|
|
@ -1178,7 +1184,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:
|
||||
|
|
@ -1254,7 +1261,7 @@ class Library(dbcore.Database):
|
|||
# Parse the query, if necessary.
|
||||
try:
|
||||
parsed_sort = None
|
||||
if isinstance(query, basestring):
|
||||
if isinstance(query, six.string_types):
|
||||
query, parsed_sort = parse_query_string(query, model_cls)
|
||||
elif isinstance(query, (list, tuple)):
|
||||
query, parsed_sort = parse_query_parts(query, model_cls)
|
||||
|
|
@ -1404,7 +1411,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):
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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']
|
||||
|
|
@ -130,8 +131,8 @@ def _safe_cast(out_type, val):
|
|||
return int(val)
|
||||
else:
|
||||
# Process any other type as a string.
|
||||
if not isinstance(val, basestring):
|
||||
val = unicode(val)
|
||||
if not isinstance(val, six.string_types):
|
||||
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''
|
||||
|
||||
|
||||
|
|
@ -1194,9 +1196,9 @@ 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))
|
||||
if isinstance(datestring, six.string_types):
|
||||
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:
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ from functools import wraps
|
|||
import beets
|
||||
from beets import logging
|
||||
from beets import mediafile
|
||||
import six
|
||||
|
||||
PLUGIN_NAMESPACE = 'beetsplug'
|
||||
|
||||
|
|
@ -54,10 +55,10 @@ class PluginLogFilter(logging.Filter):
|
|||
|
||||
def filter(self, record):
|
||||
if hasattr(record.msg, 'msg') and isinstance(record.msg.msg,
|
||||
basestring):
|
||||
six.string_types):
|
||||
# A _LogMessage from our hacked-up Logging replacement.
|
||||
record.msg.msg = self.prefix + record.msg.msg
|
||||
elif isinstance(record.msg, basestring):
|
||||
elif isinstance(record.msg, six.string_types):
|
||||
record.msg = self.prefix + record.msg
|
||||
return True
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import re
|
|||
import struct
|
||||
import traceback
|
||||
import os.path
|
||||
from six.moves import input
|
||||
|
||||
from beets import logging
|
||||
from beets import library
|
||||
|
|
@ -41,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':
|
||||
|
|
@ -139,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:
|
||||
|
|
@ -147,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)
|
||||
|
|
@ -193,7 +195,7 @@ def should_move(move_opt=None):
|
|||
# Input prompts.
|
||||
|
||||
def input_(prompt=None):
|
||||
"""Like `raw_input`, but decodes the result to a Unicode string.
|
||||
"""Like `input`, but decodes the result to a Unicode string.
|
||||
Raises a UserError if stdin is not available. The prompt is sent to
|
||||
stdout rather than stderr. A printed between the prompt and the
|
||||
input cursor.
|
||||
|
|
@ -205,7 +207,7 @@ def input_(prompt=None):
|
|||
print_(prompt, end=' ')
|
||||
|
||||
try:
|
||||
resp = raw_input()
|
||||
resp = input()
|
||||
except EOFError:
|
||||
raise UserError(u'stdin stream ended while input required')
|
||||
|
||||
|
|
@ -261,7 +263,7 @@ def input_options(options, require=False, prompt=None, fallback_prompt=None,
|
|||
# Mark the option's shortcut letter for display.
|
||||
if not require and (
|
||||
(default is None and not numrange and first) or
|
||||
(isinstance(default, basestring) and
|
||||
(isinstance(default, six.string_types) and
|
||||
found_letter.lower() == default.lower())):
|
||||
# The first option is the default; mark it.
|
||||
show_letter = '[%s]' % found_letter.upper()
|
||||
|
|
@ -297,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]))
|
||||
|
|
@ -521,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')
|
||||
|
|
@ -541,10 +544,11 @@ def _colordiff(a, b, highlight='text_highlight',
|
|||
highlighted intelligently to show differences; other values are
|
||||
stringified and highlighted in their entirety.
|
||||
"""
|
||||
if not isinstance(a, basestring) or not isinstance(b, basestring):
|
||||
if not isinstance(a, six.string_types) \
|
||||
or not isinstance(b, six.string_types):
|
||||
# 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:
|
||||
|
|
@ -592,7 +596,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):
|
||||
|
|
@ -603,7 +607,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
|
||||
|
||||
|
||||
|
|
@ -671,7 +675,7 @@ def _field_diff(field, old, new):
|
|||
|
||||
# For strings, highlight changes. For others, colorize the whole
|
||||
# thing.
|
||||
if isinstance(oldval, basestring):
|
||||
if isinstance(oldval, six.string_types):
|
||||
oldstr, newstr = colordiff(oldval, newstr)
|
||||
else:
|
||||
oldstr = colorize('text_error', oldstr)
|
||||
|
|
@ -864,7 +868,7 @@ class CommonOptionsParser(optparse.OptionParser, object):
|
|||
"""
|
||||
kwargs = {}
|
||||
if target:
|
||||
if isinstance(target, basestring):
|
||||
if isinstance(target, six.string_types):
|
||||
target = {'item': library.Item,
|
||||
'album': library.Album}[target]
|
||||
kwargs['target'] = target
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
@ -806,7 +807,7 @@ class TerminalImportSession(importer.ImportSession):
|
|||
if search_id:
|
||||
candidates, rec = autotag.tag_item(
|
||||
task.item, search_ids=search_id.split())
|
||||
elif choice in extra_ops.keys():
|
||||
elif choice in list(extra_ops.keys()):
|
||||
# Allow extra ops to automatically set the post-choice.
|
||||
post_choice = extra_ops[choice](self, task)
|
||||
if isinstance(post_choice, importer.action):
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -632,14 +633,18 @@ def as_string(value):
|
|||
"""Convert a value to a Unicode object for matching with a query.
|
||||
None becomes the empty string. Bytestrings are silently decoded.
|
||||
"""
|
||||
buffer_types = memoryview
|
||||
if six.PY2:
|
||||
buffer_types = (buffer, memoryview)
|
||||
|
||||
if value is None:
|
||||
return u''
|
||||
elif isinstance(value, buffer):
|
||||
elif isinstance(value, buffer_types):
|
||||
return bytes(value).decode('utf8', 'ignore')
|
||||
elif isinstance(value, bytes):
|
||||
return value.decode('utf8', 'ignore')
|
||||
else:
|
||||
return unicode(value)
|
||||
return six.text_type(value)
|
||||
|
||||
|
||||
def plurality(objs):
|
||||
|
|
@ -765,7 +770,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 +806,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
|
||||
|
|
|
|||
|
|
@ -18,14 +18,14 @@ public resizing proxy if neither is available.
|
|||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import urllib
|
||||
import subprocess
|
||||
import os
|
||||
import re
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
from six.moves.urllib.parse import urlencode
|
||||
from beets import logging
|
||||
from beets import util
|
||||
import six
|
||||
|
||||
# Resizing methods
|
||||
PIL = 1
|
||||
|
|
@ -41,7 +41,7 @@ def resize_url(url, maxwidth):
|
|||
"""Return a proxied image URL that resizes the original image to
|
||||
maxwidth (preserving aspect ratio).
|
||||
"""
|
||||
return '{0}?{1}'.format(PROXY_URL, urllib.urlencode({
|
||||
return '{0}?{1}'.format(PROXY_URL, urlencode({
|
||||
'url': url.replace('http://', ''),
|
||||
'w': bytes(maxwidth),
|
||||
}))
|
||||
|
|
@ -160,10 +160,9 @@ class Shareable(type):
|
|||
return self._instance
|
||||
|
||||
|
||||
class ArtResizer(object):
|
||||
class ArtResizer(six.with_metaclass(Shareable, object)):
|
||||
"""A singleton class that performs image resizes.
|
||||
"""
|
||||
__metaclass__ = Shareable
|
||||
|
||||
def __init__(self):
|
||||
"""Create a resizer object with an inferred method.
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ Bluelet: easy concurrency without all the messy parallelism.
|
|||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import six
|
||||
import socket
|
||||
import select
|
||||
import sys
|
||||
|
|
@ -19,20 +20,6 @@ import time
|
|||
import collections
|
||||
|
||||
|
||||
# A little bit of "six" (Python 2/3 compatibility): cope with PEP 3109 syntax
|
||||
# changes.
|
||||
|
||||
PY3 = sys.version_info[0] == 3
|
||||
if PY3:
|
||||
def _reraise(typ, exc, tb):
|
||||
raise exc.with_traceback(tb)
|
||||
else:
|
||||
exec("""
|
||||
def _reraise(typ, exc, tb):
|
||||
raise typ, exc, tb
|
||||
""")
|
||||
|
||||
|
||||
# Basic events used for thread scheduling.
|
||||
|
||||
class Event(object):
|
||||
|
|
@ -214,7 +201,7 @@ class ThreadException(Exception):
|
|||
self.exc_info = exc_info
|
||||
|
||||
def reraise(self):
|
||||
_reraise(self.exc_info[0], self.exc_info[1], self.exc_info[2])
|
||||
six.reraise(self.exc_info[0], self.exc_info[1], self.exc_info[2])
|
||||
|
||||
|
||||
SUSPENDED = Event() # Special sentinel placeholder for suspended threads.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ import ast
|
|||
import dis
|
||||
import types
|
||||
|
||||
from .confit import NUMERIC_TYPES
|
||||
import six
|
||||
|
||||
SYMBOL_DELIM = u'$'
|
||||
FUNC_DELIM = u'%'
|
||||
|
|
@ -74,11 +74,11 @@ def ex_literal(val):
|
|||
"""
|
||||
if val is None:
|
||||
return ast.Name('None', ast.Load())
|
||||
elif isinstance(val, NUMERIC_TYPES):
|
||||
elif isinstance(val, six.integer_types):
|
||||
return ast.Num(val)
|
||||
elif isinstance(val, bool):
|
||||
return ast.Name(bytes(val), ast.Load())
|
||||
elif isinstance(val, basestring):
|
||||
elif isinstance(val, six.string_types):
|
||||
return ast.Str(val)
|
||||
raise TypeError(u'no literal for {0}'.format(type(val)))
|
||||
|
||||
|
|
@ -97,7 +97,7 @@ def ex_call(func, args):
|
|||
function may be an expression or the name of a function. Each
|
||||
argument may be an expression or a value to be used as a literal.
|
||||
"""
|
||||
if isinstance(func, basestring):
|
||||
if isinstance(func, six.string_types):
|
||||
func = ex_rvalue(func)
|
||||
|
||||
args = list(args)
|
||||
|
|
@ -190,8 +190,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
|
||||
|
||||
|
|
@ -242,11 +242,11 @@ class Expression(object):
|
|||
"""
|
||||
out = []
|
||||
for part in self.parts:
|
||||
if isinstance(part, basestring):
|
||||
if isinstance(part, six.string_types):
|
||||
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
|
||||
|
|
@ -256,7 +256,7 @@ class Expression(object):
|
|||
varnames = set()
|
||||
funcnames = set()
|
||||
for part in self.parts:
|
||||
if isinstance(part, basestring):
|
||||
if isinstance(part, six.string_types):
|
||||
expressions.append(ex_literal(part))
|
||||
else:
|
||||
e, v, f = part.translate()
|
||||
|
|
@ -508,7 +508,8 @@ class Template(object):
|
|||
def __init__(self, template):
|
||||
self.expr = _parse(template)
|
||||
self.original = template
|
||||
self.compiled = self.translate()
|
||||
if six.PY2:
|
||||
self.compiled = self.translate()
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.original == other.original
|
||||
|
|
@ -524,9 +525,12 @@ class Template(object):
|
|||
def substitute(self, values={}, functions={}):
|
||||
"""Evaluate the template given the values and functions.
|
||||
"""
|
||||
try:
|
||||
res = self.compiled(values, functions)
|
||||
except: # Handle any exceptions thrown by compiled version.
|
||||
if six.PY2:
|
||||
try:
|
||||
res = self.compiled(values, functions)
|
||||
except: # Handle any exceptions thrown by compiled version.
|
||||
res = self.interpret(values, functions)
|
||||
else:
|
||||
res = self.interpret(values, functions)
|
||||
return res
|
||||
|
||||
|
|
@ -563,7 +567,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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -34,9 +34,10 @@ in place of any single coroutine.
|
|||
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import Queue
|
||||
from six.moves import queue
|
||||
from threading import Thread, Lock
|
||||
import sys
|
||||
import six
|
||||
|
||||
BUBBLE = '__PIPELINE_BUBBLE__'
|
||||
POISON = '__PIPELINE_POISON__'
|
||||
|
|
@ -75,13 +76,13 @@ def _invalidate_queue(q, val=None, sync=True):
|
|||
q.mutex.release()
|
||||
|
||||
|
||||
class CountedQueue(Queue.Queue):
|
||||
class CountedQueue(queue.Queue):
|
||||
"""A queue that keeps track of the number of threads that are
|
||||
still feeding into it. The queue is poisoned when all threads are
|
||||
finished with the queue.
|
||||
"""
|
||||
def __init__(self, maxsize=0):
|
||||
Queue.Queue.__init__(self, maxsize)
|
||||
queue.Queue.__init__(self, maxsize)
|
||||
self.nthreads = 0
|
||||
self.poisoned = False
|
||||
|
||||
|
|
@ -431,7 +432,7 @@ class Pipeline(object):
|
|||
exc_info = thread.exc_info
|
||||
if exc_info:
|
||||
# Make the exception appear as it was raised originally.
|
||||
raise exc_info[0], exc_info[1], exc_info[2]
|
||||
six.reraise(exc_info[0], exc_info[1], exc_info[2])
|
||||
|
||||
def pull(self):
|
||||
"""Yield elements from the end of the pipeline. Runs the stages
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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']]
|
||||
|
||||
|
||||
|
|
@ -196,8 +197,9 @@ class BeatportClient(object):
|
|||
return response.json()['results']
|
||||
|
||||
|
||||
@six.python_2_unicode_compatible
|
||||
class BeatportRelease(BeatportObject):
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
if len(self.artists) < 4:
|
||||
artist_str = ", ".join(x[1] for x in self.artists)
|
||||
else:
|
||||
|
|
@ -209,7 +211,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)
|
||||
|
|
@ -224,21 +226,22 @@ class BeatportRelease(BeatportObject):
|
|||
data['slug'], data['id'])
|
||||
|
||||
|
||||
@six.python_2_unicode_compatible
|
||||
class BeatportTrack(BeatportObject):
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
artist_str = ", ".join(x[1] for x in self.artists)
|
||||
return (u"<BeatportTrack: {0} - {1} ({2})>"
|
||||
.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 +269,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:
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -569,11 +570,11 @@ class Connection(object):
|
|||
added after every string. Returns a Bluelet event that sends
|
||||
the data.
|
||||
"""
|
||||
if isinstance(lines, basestring):
|
||||
if isinstance(lines, six.string_types):
|
||||
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
|
||||
|
||||
|
|
@ -852,7 +853,7 @@ class Server(BaseServer):
|
|||
for name, itemid in iter(sorted(node.files.items())):
|
||||
item = self.lib.get_item(itemid)
|
||||
yield self._item_info(item)
|
||||
for name, _ in iter(sorted(node.dirs.iteritems())):
|
||||
for name, _ in iter(sorted(six.iteritems(node.dirs))):
|
||||
dirpath = self._path_join(path, name)
|
||||
if dirpath.startswith(u"/"):
|
||||
# Strip leading slash (libmpc rejects this).
|
||||
|
|
@ -872,12 +873,12 @@ class Server(BaseServer):
|
|||
yield u'file: ' + basepath
|
||||
else:
|
||||
# List a directory. Recurse into both directories and files.
|
||||
for name, itemid in sorted(node.files.iteritems()):
|
||||
for name, itemid in sorted(six.iteritems(node.files)):
|
||||
newpath = self._path_join(basepath, name)
|
||||
# "yield from"
|
||||
for v in self._listall(newpath, itemid, info):
|
||||
yield v
|
||||
for name, subdir in sorted(node.dirs.iteritems()):
|
||||
for name, subdir in sorted(six.iteritems(node.dirs)):
|
||||
newpath = self._path_join(basepath, name)
|
||||
yield u'directory: ' + newpath
|
||||
for v in self._listall(newpath, subdir, info):
|
||||
|
|
@ -902,11 +903,11 @@ class Server(BaseServer):
|
|||
yield self.lib.get_item(node)
|
||||
else:
|
||||
# Recurse into a directory.
|
||||
for name, itemid in sorted(node.files.iteritems()):
|
||||
for name, itemid in sorted(six.iteritems(node.files)):
|
||||
# "yield from"
|
||||
for v in self._all_items(itemid):
|
||||
yield v
|
||||
for name, subdir in sorted(node.dirs.iteritems()):
|
||||
for name, subdir in sorted(six.iteritems(node.dirs)):
|
||||
for v in self._all_items(subdir):
|
||||
yield v
|
||||
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -19,12 +19,13 @@ music player.
|
|||
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import six
|
||||
import sys
|
||||
import time
|
||||
import thread
|
||||
from six.moves import _thread
|
||||
import os
|
||||
import copy
|
||||
import urllib
|
||||
from six.moves import urllib
|
||||
from beets import ui
|
||||
|
||||
import gi
|
||||
|
|
@ -128,9 +129,9 @@ 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.quote(path)
|
||||
uri = 'file://' + urllib.parse.quote(path)
|
||||
self.player.set_property("uri", uri)
|
||||
self.player.set_state(Gst.State.PLAYING)
|
||||
self.playing = True
|
||||
|
|
@ -164,7 +165,7 @@ class GstPlayer(object):
|
|||
loop = GLib.MainLoop()
|
||||
loop.run()
|
||||
|
||||
thread.start_new_thread(start, ())
|
||||
_thread.start_new_thread(start, ())
|
||||
|
||||
def time(self):
|
||||
"""Returns a tuple containing (position, length) where both
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import time
|
||||
from six.moves import input
|
||||
|
||||
from beets import ui
|
||||
from beets.plugins import BeetsPlugin
|
||||
|
|
@ -31,7 +32,7 @@ def bpm(max_strokes):
|
|||
dt = []
|
||||
for i in range(max_strokes):
|
||||
# Press enter to the rhythm...
|
||||
s = raw_input()
|
||||
s = input()
|
||||
if s == '':
|
||||
t1 = time.time()
|
||||
# Only start measuring at the second stroke
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ from __future__ import division, absolute_import, print_function
|
|||
from datetime import datetime
|
||||
import re
|
||||
import string
|
||||
from itertools import tee, izip
|
||||
from six.moves import zip
|
||||
from itertools import tee
|
||||
|
||||
from beets import plugins, ui
|
||||
|
||||
|
|
@ -37,7 +38,7 @@ def pairwise(iterable):
|
|||
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
|
||||
a, b = tee(iterable)
|
||||
next(b, None)
|
||||
return izip(a, b)
|
||||
return zip(a, b)
|
||||
|
||||
|
||||
def span_from_str(span_str):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -121,7 +122,7 @@ def _all_releases(items):
|
|||
for release_id in release_ids:
|
||||
relcounts[release_id] += 1
|
||||
|
||||
for release_id, count in relcounts.iteritems():
|
||||
for release_id, count in six.iteritems(relcounts):
|
||||
if float(count) / len(items) > COMMON_REL_THRESH:
|
||||
yield release_id
|
||||
|
||||
|
|
@ -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)))
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -27,13 +27,14 @@ from beets.util import confit
|
|||
from discogs_client import Release, Client
|
||||
from discogs_client.exceptions import DiscogsAPIError
|
||||
from requests.exceptions import ConnectionError
|
||||
from six.moves import http_client
|
||||
import beets
|
||||
import re
|
||||
import time
|
||||
import json
|
||||
import socket
|
||||
import httplib
|
||||
import os
|
||||
import six
|
||||
|
||||
|
||||
# Silence spurious INFO log lines generated by urllib3.
|
||||
|
|
@ -43,7 +44,7 @@ urllib3_logger.setLevel(logging.CRITICAL)
|
|||
USER_AGENT = u'beets/{0} +http://beets.io/'.format(beets.__version__)
|
||||
|
||||
# Exceptions that discogs_client should really handle but does not.
|
||||
CONNECTION_ERRORS = (ConnectionError, socket.error, httplib.HTTPException,
|
||||
CONNECTION_ERRORS = (ConnectionError, socket.error, http_client.HTTPException,
|
||||
ValueError, # JSON decoding raises a ValueError.
|
||||
DiscogsAPIError)
|
||||
|
||||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -329,7 +330,7 @@ class DuplicatesPlugin(BeetsPlugin):
|
|||
"""Generate triples of keys, duplicate counts, and constituent objects.
|
||||
"""
|
||||
offset = 0 if full else 1
|
||||
for k, objs in self._group_by(objs, keys, strict).iteritems():
|
||||
for k, objs in six.iteritems(self._group_by(objs, keys, strict)):
|
||||
if len(objs) > 1:
|
||||
objs = self._order(objs, tiebreak)
|
||||
if merge:
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ from __future__ import division, absolute_import, print_function
|
|||
|
||||
from beets import config
|
||||
from beets.plugins import BeetsPlugin
|
||||
from urllib import urlencode
|
||||
from urlparse import urljoin, parse_qs, urlsplit, urlunsplit
|
||||
from six.moves.urllib.parse import urlencode
|
||||
from six.moves.urllib.parse import urljoin, parse_qs, urlsplit, urlunsplit
|
||||
import hashlib
|
||||
import requests
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ from beets.mediafile import _image_mime_type
|
|||
from beets.util.artresizer import ArtResizer
|
||||
from beets.util import confit
|
||||
from beets.util import syspath, bytestring_path
|
||||
import six
|
||||
|
||||
try:
|
||||
import itunes
|
||||
|
|
@ -600,7 +601,7 @@ class Wikipedia(RemoteArtSource):
|
|||
try:
|
||||
data = wikipedia_response.json()
|
||||
results = data['query']['pages']
|
||||
for _, result in results.iteritems():
|
||||
for _, result in six.iteritems(results):
|
||||
image_url = result['imageinfo'][0]['url']
|
||||
yield self._candidate(url=image_url,
|
||||
match=Candidate.MATCH_EXACT)
|
||||
|
|
@ -727,7 +728,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':
|
||||
|
|
|
|||
|
|
@ -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'])
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ from beets.plugins import BeetsPlugin
|
|||
from beets.dbcore.query import StringFieldQuery
|
||||
from beets import config
|
||||
import difflib
|
||||
import six
|
||||
|
||||
|
||||
class FuzzyQuery(StringFieldQuery):
|
||||
|
|
@ -44,5 +45,5 @@ class FuzzyPlugin(BeetsPlugin):
|
|||
})
|
||||
|
||||
def queries(self):
|
||||
prefix = self.config['prefix'].get(basestring)
|
||||
prefix = self.config['prefix'].get(six.string_types)
|
||||
return {prefix: FuzzyQuery}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import os
|
|||
from beets import util
|
||||
from beets import importer
|
||||
from beets.plugins import BeetsPlugin
|
||||
import six
|
||||
|
||||
|
||||
class ImportAddedPlugin(BeetsPlugin):
|
||||
|
|
@ -62,7 +63,7 @@ class ImportAddedPlugin(BeetsPlugin):
|
|||
|
||||
def record_reimported(self, task, session):
|
||||
self.reimported_item_ids = set(item.id for item, replaced_items
|
||||
in task.replaced_items.iteritems()
|
||||
in six.iteritems(task.replaced_items)
|
||||
if replaced_items)
|
||||
self.replaced_album_paths = set(task.replaced_albums.keys())
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ from beets import ui
|
|||
from beets import mediafile
|
||||
from beets.library import Item
|
||||
from beets.util import displayable_path, normpath, syspath
|
||||
import six
|
||||
|
||||
|
||||
def tag_data(lib, args):
|
||||
|
|
@ -73,7 +74,7 @@ def library_data_emitter(item):
|
|||
|
||||
|
||||
def update_summary(summary, tags):
|
||||
for key, value in tags.iteritems():
|
||||
for key, value in six.iteritems(tags):
|
||||
if key not in summary:
|
||||
summary[key] = value
|
||||
elif summary[key] != value:
|
||||
|
|
@ -96,7 +97,7 @@ def print_data(data, item=None, fmt=None):
|
|||
|
||||
path = displayable_path(item.path) if item else None
|
||||
formatted = {}
|
||||
for key, value in data.iteritems():
|
||||
for key, value in six.iteritems(data):
|
||||
if isinstance(value, list):
|
||||
formatted[key] = u'; '.join(value)
|
||||
if value is not None:
|
||||
|
|
@ -123,7 +124,7 @@ def print_data_keys(data, item=None):
|
|||
"""
|
||||
path = displayable_path(item.path) if item else None
|
||||
formatted = []
|
||||
for key, value in data.iteritems():
|
||||
for key, value in six.iteritems(data):
|
||||
formatted.append(key)
|
||||
|
||||
if len(formatted) == 0:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
from six.moves import range
|
||||
import pylast
|
||||
from pylast import TopItem, _extract, _number
|
||||
from beets import ui
|
||||
|
|
@ -22,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/'
|
||||
|
||||
|
|
@ -110,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:
|
||||
|
|
@ -192,7 +194,7 @@ def process_tracks(lib, tracks, log):
|
|||
total_fails = 0
|
||||
log.info(u'Received {0} tracks in this page, processing...', total)
|
||||
|
||||
for num in xrange(0, total):
|
||||
for num in range(0, total):
|
||||
song = None
|
||||
trackid = tracks[num]['mbid'].strip()
|
||||
artist = tracks[num]['artist'].get('name', '').strip()
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ import json
|
|||
import re
|
||||
import requests
|
||||
import unicodedata
|
||||
import urllib
|
||||
import warnings
|
||||
from HTMLParser import HTMLParseError
|
||||
from six.moves import urllib
|
||||
import six
|
||||
|
||||
try:
|
||||
from bs4 import SoupStrainer, BeautifulSoup
|
||||
|
|
@ -40,6 +40,15 @@ try:
|
|||
except ImportError:
|
||||
HAS_LANGDETECT = False
|
||||
|
||||
try:
|
||||
# PY3: HTMLParseError was removed in 3.5 as strict mode
|
||||
# was deprecated in 3.3.
|
||||
# https://docs.python.org/3.3/library/html.parser.html
|
||||
from six.moves.html_parser import HTMLParseError
|
||||
except ImportError:
|
||||
class HTMLParseError(Exception):
|
||||
pass
|
||||
|
||||
from beets import plugins
|
||||
from beets import ui
|
||||
|
||||
|
|
@ -177,11 +186,11 @@ 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')
|
||||
return urllib.quote(s)
|
||||
return urllib.parse.quote(s)
|
||||
|
||||
def build_url(self, artist, title):
|
||||
return self.URL_PATTERN % (self._encode(artist.title()),
|
||||
|
|
@ -223,7 +232,7 @@ class SymbolsReplaced(Backend):
|
|||
|
||||
@classmethod
|
||||
def _encode(cls, s):
|
||||
for old, new in cls.REPLACEMENTS.iteritems():
|
||||
for old, new in six.iteritems(cls.REPLACEMENTS):
|
||||
s = re.sub(old, new, s)
|
||||
|
||||
return super(SymbolsReplaced, cls)._encode(s)
|
||||
|
|
@ -250,13 +259,13 @@ 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):
|
||||
query = u"%s %s" % (artist, title)
|
||||
url = u'https://api.genius.com/search?q=%s' \
|
||||
% (urllib.quote(query.encode('utf8')))
|
||||
% (urllib.parse.quote(query.encode('utf8')))
|
||||
|
||||
self._log.debug(u'genius: requesting search {}', url)
|
||||
try:
|
||||
|
|
@ -461,8 +470,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 +512,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
|
||||
|
|
@ -542,9 +551,9 @@ class Google(Backend):
|
|||
query = u"%s %s" % (artist, title)
|
||||
url = u'https://www.googleapis.com/customsearch/v1?key=%s&cx=%s&q=%s' \
|
||||
% (self.api_key, self.engine_id,
|
||||
urllib.quote(query.encode('utf8')))
|
||||
urllib.parse.quote(query.encode('utf8')))
|
||||
|
||||
data = urllib.urlopen(url)
|
||||
data = urllib.request.urlopen(url)
|
||||
data = json.load(data)
|
||||
if 'error' in data:
|
||||
reason = data['error']['errors'][0]['reason']
|
||||
|
|
@ -643,7 +652,7 @@ class LyricsPlugin(plugins.BeetsPlugin):
|
|||
oauth_url = 'https://datamarket.accesscontrol.windows.net/v2/OAuth2-13'
|
||||
oauth_token = json.loads(requests.post(
|
||||
oauth_url,
|
||||
data=urllib.urlencode(params)).content)
|
||||
data=urllib.parse.urlencode(params)).content)
|
||||
if 'access_token' in oauth_token:
|
||||
return "Bearer " + oauth_token['access_token']
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -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']:
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ from importlib import import_module
|
|||
from beets.util.confit import ConfigValueError
|
||||
from beets import ui
|
||||
from beets.plugins import BeetsPlugin
|
||||
import six
|
||||
|
||||
|
||||
METASYNC_MODULE = 'beetsplug.metasync'
|
||||
|
|
@ -35,9 +36,7 @@ SOURCES = {
|
|||
}
|
||||
|
||||
|
||||
class MetaSource(object):
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
class MetaSource(six.with_metaclass(ABCMeta, object)):
|
||||
def __init__(self, config, log):
|
||||
self.item_types = {}
|
||||
self.config = config
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ import os
|
|||
import shutil
|
||||
import tempfile
|
||||
import plistlib
|
||||
import urllib
|
||||
from urlparse import urlparse
|
||||
|
||||
from six.moves.urllib.parse import urlparse, unquote
|
||||
from time import mktime
|
||||
|
||||
from beets import util
|
||||
|
|
@ -57,7 +57,7 @@ def _norm_itunes_path(path):
|
|||
# E.g., '\\G:\\Music\\bar' needs to be stripped to 'G:\\Music\\bar'
|
||||
|
||||
return util.bytestring_path(os.path.normpath(
|
||||
urllib.unquote(urlparse(path).path)).lstrip('\\')).lower()
|
||||
unquote(urlparse(path).path)).lstrip('\\')).lower()
|
||||
|
||||
|
||||
class Itunes(MetaSource):
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -12,9 +12,8 @@ Put something like the following in your config.yaml to configure:
|
|||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import requests
|
||||
from urlparse import urljoin
|
||||
from urllib import urlencode
|
||||
import xml.etree.ElementTree as ET
|
||||
from six.moves.urllib.parse import urljoin, urlencode
|
||||
from beets import config
|
||||
from beets.plugins import BeetsPlugin
|
||||
|
||||
|
|
|
|||
|
|
@ -18,15 +18,16 @@ from __future__ import division, absolute_import, print_function
|
|||
import subprocess
|
||||
import os
|
||||
import collections
|
||||
import itertools
|
||||
import sys
|
||||
import warnings
|
||||
import re
|
||||
from six.moves import zip
|
||||
|
||||
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. "
|
||||
|
|
@ -883,8 +884,7 @@ class ReplayGainPlugin(BeetsPlugin):
|
|||
)
|
||||
|
||||
self.store_album_gain(album, album_gain.album_gain)
|
||||
for item, track_gain in itertools.izip(album.items(),
|
||||
album_gain.track_gains):
|
||||
for item, track_gain in zip(album.items(), album_gain.track_gains):
|
||||
self.store_track_gain(item, track_gain)
|
||||
if write:
|
||||
item.try_write()
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -68,7 +69,7 @@ class RewritePlugin(BeetsPlugin):
|
|||
rules['albumartist'].append((pattern, value))
|
||||
|
||||
# Replace each template field with the new rewriter function.
|
||||
for fieldname, fieldrules in rules.iteritems():
|
||||
for fieldname, fieldrules in six.iteritems(rules):
|
||||
getter = rewriter(fieldname, fieldrules)
|
||||
self.template_fields[fieldname] = getter
|
||||
if fieldname in library.Album._fields:
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ from beets.library import Item, Album, parse_query_string
|
|||
from beets.dbcore import OrQuery
|
||||
from beets.dbcore.query import MultipleSort, ParsingError
|
||||
import os
|
||||
import six
|
||||
|
||||
|
||||
class SmartPlaylistPlugin(BeetsPlugin):
|
||||
|
|
@ -106,7 +107,7 @@ class SmartPlaylistPlugin(BeetsPlugin):
|
|||
qs = playlist.get(key)
|
||||
if qs is None:
|
||||
query_and_sort = None, None
|
||||
elif isinstance(qs, basestring):
|
||||
elif isinstance(qs, six.string_types):
|
||||
query_and_sort = parse_query_string(qs, Model)
|
||||
elif len(qs) == 1:
|
||||
query_and_sort = parse_query_string(qs[0], Model)
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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''
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@ Also note that beets may take some time to quit after ^C is typed; it
|
|||
tries to clean up after itself briefly even when canceled.
|
||||
|
||||
(For developers: this is because the UI thread is blocking on
|
||||
``raw_input`` and cannot be interrupted by the main thread, which is
|
||||
``input`` and cannot be interrupted by the main thread, which is
|
||||
trying to close all pipeline stages in the exception handler by setting
|
||||
a flag. There is no simple way to remedy this.)
|
||||
|
||||
|
|
|
|||
1
setup.py
1
setup.py
|
|
@ -86,6 +86,7 @@ setup(
|
|||
},
|
||||
|
||||
install_requires=[
|
||||
'six',
|
||||
'enum34>=1.0.4',
|
||||
'mutagen>=1.27',
|
||||
'munkres',
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ import shutil
|
|||
import subprocess
|
||||
from tempfile import mkdtemp, mkstemp
|
||||
from contextlib import contextmanager
|
||||
from StringIO import StringIO
|
||||
from six import StringIO
|
||||
from enum import Enum
|
||||
|
||||
import beets
|
||||
|
|
@ -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
|
||||
|
|
@ -89,7 +90,8 @@ def control_stdin(input=None):
|
|||
"""
|
||||
org = sys.stdin
|
||||
sys.stdin = StringIO(input)
|
||||
sys.stdin.encoding = 'utf8'
|
||||
if six.PY2: # StringIO encoding attr isn't writable in python >= 3
|
||||
sys.stdin.encoding = 'utf8'
|
||||
try:
|
||||
yield sys.stdin
|
||||
finally:
|
||||
|
|
@ -108,7 +110,8 @@ def capture_stdout():
|
|||
"""
|
||||
org = sys.stdout
|
||||
sys.stdout = capture = StringIO()
|
||||
sys.stdout.encoding = 'utf8'
|
||||
if six.PY2: # StringIO encoding attr isn't writable in python >= 3
|
||||
sys.stdout.encoding = 'utf8'
|
||||
try:
|
||||
yield sys.stdout
|
||||
finally:
|
||||
|
|
@ -121,7 +124,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:
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ from beets.library import Item
|
|||
from beets.util import plurality
|
||||
from beets.autotag import AlbumInfo, TrackInfo
|
||||
from beets import config
|
||||
import six
|
||||
|
||||
|
||||
class PluralityTest(_common.TestCase):
|
||||
|
|
@ -611,7 +612,7 @@ class AssignmentTest(unittest.TestCase):
|
|||
match.assign_items(items, trackinfo)
|
||||
self.assertEqual(extra_items, [])
|
||||
self.assertEqual(extra_tracks, [])
|
||||
for item, info in mapping.iteritems():
|
||||
for item, info in six.iteritems(mapping):
|
||||
self.assertEqual(items.index(item), trackinfo.index(info))
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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:')
|
||||
|
|
|
|||
|
|
@ -20,11 +20,13 @@ from __future__ import division, absolute_import, print_function
|
|||
import os
|
||||
import shutil
|
||||
import sqlite3
|
||||
from six import assertRaisesRegex
|
||||
|
||||
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
|
||||
|
|
@ -298,9 +300,9 @@ class ModelTest(unittest.TestCase):
|
|||
self.assertNotIn('flex_field', model2)
|
||||
|
||||
def test_check_db_fails(self):
|
||||
with self.assertRaisesRegexp(ValueError, 'no database'):
|
||||
with assertRaisesRegex(self, ValueError, 'no database'):
|
||||
dbcore.Model()._check_db()
|
||||
with self.assertRaisesRegexp(ValueError, 'no id'):
|
||||
with assertRaisesRegex(self, ValueError, 'no id'):
|
||||
TestModel1(self.db)._check_db()
|
||||
|
||||
dbcore.Model(self.db)._check_db(need_id=False)
|
||||
|
|
@ -312,7 +314,7 @@ class ModelTest(unittest.TestCase):
|
|||
def test_computed_field(self):
|
||||
model = TestModelWithGetters()
|
||||
self.assertEqual(model.aComputedField, 'thing')
|
||||
with self.assertRaisesRegexp(KeyError, u'computed field .+ deleted'):
|
||||
with assertRaisesRegex(self, KeyError, u'computed field .+ deleted'):
|
||||
del model.aComputedField
|
||||
|
||||
def test_items(self):
|
||||
|
|
@ -328,7 +330,7 @@ class ModelTest(unittest.TestCase):
|
|||
model._db
|
||||
|
||||
def test_parse_nonstring(self):
|
||||
with self.assertRaisesRegexp(TypeError, u"must be a string"):
|
||||
with assertRaisesRegex(self, TypeError, u"must be a string"):
|
||||
dbcore.Model._parse(None, 42)
|
||||
|
||||
|
||||
|
|
@ -349,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):
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ from test.test_ui_importer import TerminalImportSessionSetup
|
|||
from test.test_importer import ImportHelper, AutotagStub
|
||||
from beets.library import Item
|
||||
from beetsplug.edit import EditPlugin
|
||||
import six
|
||||
|
||||
|
||||
class ModifyFileMocker(object):
|
||||
|
|
@ -63,7 +64,7 @@ class ModifyFileMocker(object):
|
|||
"""
|
||||
with codecs.open(filename, 'r', encoding='utf8') as f:
|
||||
contents = f.read()
|
||||
for old, new_ in self.replacements.iteritems():
|
||||
for old, new_ in six.iteritems(self.replacements):
|
||||
contents = contents.replace(old, new_)
|
||||
with codecs.open(filename, 'w', encoding='utf8') as f:
|
||||
f.write(contents)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
from __future__ import division, absolute_import, print_function
|
||||
import six
|
||||
|
||||
"""Tests for the `importadded` plugin."""
|
||||
|
||||
|
|
@ -124,7 +125,7 @@ class ImportAddedTest(unittest.TestCase, ImportHelper):
|
|||
self.assertEqualTimes(album.added, album_added_before)
|
||||
items_added_after = dict((item.path, item.added)
|
||||
for item in album.items())
|
||||
for item_path, added_after in items_added_after.iteritems():
|
||||
for item_path, added_after in six.iteritems(items_added_after):
|
||||
self.assertEqualTimes(items_added_before[item_path], added_after,
|
||||
u"reimport modified Item.added for " +
|
||||
util.displayable_path(item_path))
|
||||
|
|
@ -162,7 +163,7 @@ class ImportAddedTest(unittest.TestCase, ImportHelper):
|
|||
# Verify the reimported items
|
||||
items_added_after = dict((item.path, item.added)
|
||||
for item in self.lib.items())
|
||||
for item_path, added_after in items_added_after.iteritems():
|
||||
for item_path, added_after in six.iteritems(items_added_after):
|
||||
self.assertEqualTimes(items_added_before[item_path], added_after,
|
||||
u"reimport modified Item.added for " +
|
||||
util.displayable_path(item_path))
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ from __future__ import division, absolute_import, print_function
|
|||
import os
|
||||
import re
|
||||
import shutil
|
||||
import StringIO
|
||||
import unicodedata
|
||||
import sys
|
||||
from six import StringIO
|
||||
from tempfile import mkstemp
|
||||
from zipfile import ZipFile
|
||||
from tarfile import TarFile
|
||||
|
|
@ -1250,14 +1250,14 @@ class ImportDuplicateSingletonTest(unittest.TestCase, TestHelper,
|
|||
|
||||
class TagLogTest(_common.TestCase):
|
||||
def test_tag_log_line(self):
|
||||
sio = StringIO.StringIO()
|
||||
sio = StringIO()
|
||||
handler = logging.StreamHandler(sio)
|
||||
session = _common.import_session(loghandler=handler)
|
||||
session.tag_log('status', 'path')
|
||||
self.assertIn('status path', sio.getvalue())
|
||||
|
||||
def test_tag_log_unicode(self):
|
||||
sio = StringIO.StringIO()
|
||||
sio = StringIO()
|
||||
handler = logging.StreamHandler(sio)
|
||||
session = _common.import_session(loghandler=handler)
|
||||
session.tag_log('status', u'caf\xe9') # send unicode
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ from beetsplug import lastgenre
|
|||
from beets import config
|
||||
|
||||
from test.helper import TestHelper
|
||||
import six
|
||||
|
||||
|
||||
class LastGenrePluginTest(unittest.TestCase, TestHelper):
|
||||
|
|
@ -38,11 +39,11 @@ class LastGenrePluginTest(unittest.TestCase, TestHelper):
|
|||
def _setup_config(self, whitelist=False, canonical=False, count=1):
|
||||
config['lastgenre']['canonical'] = canonical
|
||||
config['lastgenre']['count'] = count
|
||||
if isinstance(whitelist, (bool, basestring)):
|
||||
if isinstance(whitelist, (bool, six.string_types)):
|
||||
# Filename, default, or disabled.
|
||||
config['lastgenre']['whitelist'] = whitelist
|
||||
self.plugin.setup()
|
||||
if not isinstance(whitelist, (bool, basestring)):
|
||||
if not isinstance(whitelist, (bool, six.string_types)):
|
||||
# Explicit list of genres.
|
||||
self.plugin.whitelist = whitelist
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from __future__ import division, absolute_import, print_function
|
|||
import sys
|
||||
import threading
|
||||
import logging as log
|
||||
from StringIO import StringIO
|
||||
from six import StringIO
|
||||
|
||||
import beets.logging as blog
|
||||
from beets import plugins, ui
|
||||
|
|
@ -14,6 +14,7 @@ import beetsplug
|
|||
from test import _common
|
||||
from test._common import unittest, TestCase
|
||||
from test import helper
|
||||
import six
|
||||
|
||||
|
||||
class LoggingTest(TestCase):
|
||||
|
|
@ -218,7 +219,7 @@ class ConcurrentEventsTest(TestCase, helper.TestHelper):
|
|||
|
||||
def check_dp_exc():
|
||||
if dp.exc_info:
|
||||
raise dp.exc_info[1], None, dp.exc_info[2]
|
||||
six.reraise(dp.exc_info[1], None, dp.exc_info[2])
|
||||
|
||||
try:
|
||||
dp.lock1.acquire()
|
||||
|
|
|
|||
|
|
@ -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'))
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import shutil
|
|||
import tempfile
|
||||
import datetime
|
||||
import time
|
||||
from six import assertCountEqual
|
||||
|
||||
from test import _common
|
||||
from test._common import unittest
|
||||
|
|
@ -32,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):
|
||||
|
|
@ -268,7 +270,7 @@ class GenreListTestMixin(object):
|
|||
|
||||
def test_read_genre_list(self):
|
||||
mediafile = self._mediafile_fixture('full')
|
||||
self.assertItemsEqual(mediafile.genres, ['the genre'])
|
||||
assertCountEqual(self, mediafile.genres, ['the genre'])
|
||||
|
||||
def test_write_genre_list(self):
|
||||
mediafile = self._mediafile_fixture('empty')
|
||||
|
|
@ -276,7 +278,7 @@ class GenreListTestMixin(object):
|
|||
mediafile.save()
|
||||
|
||||
mediafile = MediaFile(mediafile.path)
|
||||
self.assertItemsEqual(mediafile.genres, [u'one', u'two'])
|
||||
assertCountEqual(self, mediafile.genres, [u'one', u'two'])
|
||||
|
||||
def test_write_genre_list_get_first(self):
|
||||
mediafile = self._mediafile_fixture('empty')
|
||||
|
|
@ -293,7 +295,7 @@ class GenreListTestMixin(object):
|
|||
mediafile.save()
|
||||
|
||||
mediafile = MediaFile(mediafile.path)
|
||||
self.assertItemsEqual(mediafile.genres, [u'the genre', u'another'])
|
||||
assertCountEqual(self, mediafile.genres, [u'the genre', u'another'])
|
||||
|
||||
|
||||
field_extension = MediaField(
|
||||
|
|
@ -352,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,
|
||||
|
|
@ -949,7 +951,7 @@ class MediaFieldTest(unittest.TestCase):
|
|||
def test_known_fields(self):
|
||||
fields = list(ReadWriteTestBase.tag_fields)
|
||||
fields.extend(('encoder', 'images', 'genres', 'albumtype'))
|
||||
self.assertItemsEqual(MediaFile.fields(), fields)
|
||||
assertCountEqual(self, MediaFile.fields(), fields)
|
||||
|
||||
def test_fields_in_readable_fields(self):
|
||||
readable = MediaFile.readable_fields()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import six
|
||||
|
||||
from test._common import unittest
|
||||
from beets.util import pipeline
|
||||
|
||||
|
|
@ -134,7 +136,10 @@ class ExceptionTest(unittest.TestCase):
|
|||
pull = pl.pull()
|
||||
for i in range(3):
|
||||
next(pull)
|
||||
self.assertRaises(TestException, pull.next)
|
||||
if six.PY2:
|
||||
self.assertRaises(TestException, pull.next)
|
||||
else:
|
||||
self.assertRaises(TestException, pull.__next__)
|
||||
|
||||
|
||||
class ParallelExceptionTest(unittest.TestCase):
|
||||
|
|
@ -157,6 +162,7 @@ class ConstrainedThreadedPipelineTest(unittest.TestCase):
|
|||
pl.run_parallel(1)
|
||||
self.assertEqual(l, [i * 2 for i in range(1000)])
|
||||
|
||||
@unittest.skipIf(six.PY3, u'freezes the test suite in py3')
|
||||
def test_constrained_exception(self):
|
||||
# Raise an exception in a constrained pipeline.
|
||||
l = []
|
||||
|
|
|
|||
|
|
@ -34,6 +34,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):
|
||||
|
|
@ -302,11 +303,11 @@ 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(')
|
||||
exception_text = unicode(raised.exception)
|
||||
exception_text = six.text_type(raised.exception)
|
||||
self.assertIn(u'not a regular expression', exception_text)
|
||||
if sys.version_info >= (3, 5):
|
||||
self.assertIn(u'unterminated subpattern', exception_text)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ from beets import config
|
|||
from beets.mediafile import MediaFile
|
||||
from beetsplug.replaygain import (FatalGstreamerPluginReplayGainError,
|
||||
GStreamerBackend)
|
||||
import six
|
||||
|
||||
try:
|
||||
import gi
|
||||
|
|
@ -62,7 +63,7 @@ class ReplayGainCliTestBase(TestHelper):
|
|||
# teardown operations may fail. In particular # {Item,Album}
|
||||
# may not have the _original_types attribute in unload_plugins
|
||||
pass
|
||||
raise exc_info[1], None, exc_info[2]
|
||||
six.reraise(exc_info[1], None, exc_info[2])
|
||||
|
||||
album = self.add_album_fixture(2)
|
||||
for item in album.items():
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ from beets import config
|
|||
from beets.library import Item
|
||||
from beetsplug import spotify
|
||||
from test.helper import TestHelper
|
||||
import urlparse
|
||||
from six.moves.urllib.parse import parse_qs, urlparse
|
||||
|
||||
|
||||
class ArgumentsMock(object):
|
||||
|
|
@ -25,7 +25,7 @@ class ArgumentsMock(object):
|
|||
|
||||
def _params(url):
|
||||
"""Get the query parameters from a URL."""
|
||||
return urlparse.parse_qs(urlparse.urlparse(url).query)
|
||||
return parse_qs(urlparse(url).query)
|
||||
|
||||
|
||||
class SpotifyPluginTest(_common.TestCase, TestHelper):
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import warnings
|
|||
|
||||
from test._common import unittest
|
||||
from beets.util import functemplate
|
||||
import six
|
||||
|
||||
|
||||
def _normexpr(expr):
|
||||
|
|
@ -30,7 +31,7 @@ def _normexpr(expr):
|
|||
"""
|
||||
textbuf = []
|
||||
for part in expr.parts:
|
||||
if isinstance(part, basestring):
|
||||
if isinstance(part, six.string_types):
|
||||
textbuf.append(part)
|
||||
else:
|
||||
if textbuf:
|
||||
|
|
@ -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)
|
||||
|
|
@ -258,7 +259,7 @@ class EvalTest(unittest.TestCase):
|
|||
|
||||
def test_function_call_exception(self):
|
||||
res = self._eval(u"%lower{a,b,c,d,e}")
|
||||
self.assertTrue(isinstance(res, basestring))
|
||||
self.assertTrue(isinstance(res, six.string_types))
|
||||
|
||||
def test_function_returning_integer(self):
|
||||
self.assertEqual(self._eval(u"%len{foo}"), u"3")
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
from six import assertCountEqual
|
||||
|
||||
from test._common import unittest
|
||||
from test import _common
|
||||
import json
|
||||
|
|
@ -52,7 +54,7 @@ class WebPluginTest(_common.LibTestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(len(response.json['items']), 2)
|
||||
response_titles = [item['title'] for item in response.json['items']]
|
||||
self.assertItemsEqual(response_titles, [u'title', u'another title'])
|
||||
assertCountEqual(self, response_titles, [u'title', u'another title'])
|
||||
|
||||
def test_get_single_item_not_found(self):
|
||||
response = self.client.get('/item/3')
|
||||
|
|
@ -80,7 +82,7 @@ class WebPluginTest(_common.LibTestCase):
|
|||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
response_albums = [album['album'] for album in response.json['albums']]
|
||||
self.assertItemsEqual(response_albums, [u'album', u'another album'])
|
||||
assertCountEqual(self, response_albums, [u'album', u'another album'])
|
||||
|
||||
def test_get_single_album_by_id(self):
|
||||
response = self.client.get('/album/2')
|
||||
|
|
@ -96,7 +98,7 @@ class WebPluginTest(_common.LibTestCase):
|
|||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
response_albums = [album['album'] for album in response.json['albums']]
|
||||
self.assertItemsEqual(response_albums, [u'album', u'another album'])
|
||||
assertCountEqual(self, response_albums, [u'album', u'another album'])
|
||||
|
||||
def test_get_album_empty_query(self):
|
||||
response = self.client.get('/album/query/')
|
||||
|
|
|
|||
Loading…
Reference in a new issue