Merge pull request #1887 from beetbox/no_unicode_literals

remove import of unicode_literals
This commit is contained in:
Adrian Sampson 2016-03-02 18:47:52 -08:00
commit abf2511002
130 changed files with 2232 additions and 2289 deletions

View file

@ -1,10 +1,6 @@
language: python
sudo: false
branches:
only:
- master
matrix:
include:
- python: 2.7

View file

@ -13,15 +13,15 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
from __future__ import absolute_import, unicode_literals
from __future__ import division, absolute_import, print_function
import os
import beets.library
from beets.util import confit
__version__ = '1.3.18'
__author__ = 'Adrian Sampson <adrian@radbox.org>'
__version__ = u'1.3.18'
__author__ = u'Adrian Sampson <adrian@radbox.org>'
Library = beets.library.Library

View file

@ -16,8 +16,7 @@
"""Facilities for automatically determining files' correct metadata.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from beets import logging
from beets import config

View file

@ -14,8 +14,7 @@
# included in all copies or substantial portions of the Software.
"""Glue between metadata sources and the matching logic."""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from collections import namedtuple
import re
@ -394,7 +393,7 @@ class Distance(object):
"""
if not isinstance(dist, Distance):
raise ValueError(
'`dist` must be a Distance object, not {0}'.format(type(dist))
u'`dist` must be a Distance object, not {0}'.format(type(dist))
)
for key, penalties in dist._penalties.iteritems():
self._penalties.setdefault(key, []).extend(penalties)
@ -418,7 +417,7 @@ class Distance(object):
"""
if not 0.0 <= dist <= 1.0:
raise ValueError(
'`dist` must be between 0.0 and 1.0, not {0}'.format(dist)
u'`dist` must be between 0.0 and 1.0, not {0}'.format(dist)
)
self._penalties.setdefault(key, []).append(dist)
@ -514,7 +513,7 @@ def album_for_mbid(release_id):
try:
album = mb.album_for_id(release_id)
if album:
plugins.send('albuminfo_received', info=album)
plugins.send(u'albuminfo_received', info=album)
return album
except mb.MusicBrainzAPIError as exc:
exc.log(log)
@ -527,7 +526,7 @@ def track_for_mbid(recording_id):
try:
track = mb.track_for_id(recording_id)
if track:
plugins.send('trackinfo_received', info=track)
plugins.send(u'trackinfo_received', info=track)
return track
except mb.MusicBrainzAPIError as exc:
exc.log(log)
@ -538,7 +537,7 @@ def albums_for_id(album_id):
candidates = [album_for_mbid(album_id)]
plugin_albums = plugins.album_for_id(album_id)
for a in plugin_albums:
plugins.send('albuminfo_received', info=a)
plugins.send(u'albuminfo_received', info=a)
candidates.extend(plugin_albums)
return filter(None, candidates)
@ -548,7 +547,7 @@ def tracks_for_id(track_id):
candidates = [track_for_mbid(track_id)]
plugin_tracks = plugins.track_for_id(track_id)
for t in plugin_tracks:
plugins.send('trackinfo_received', info=t)
plugins.send(u'trackinfo_received', info=t)
candidates.extend(plugin_tracks)
return filter(None, candidates)
@ -581,7 +580,7 @@ def album_candidates(items, artist, album, va_likely):
# Notify subscribed plugins about fetched album info
for a in out:
plugins.send('albuminfo_received', info=a)
plugins.send(u'albuminfo_received', info=a)
return out
@ -605,6 +604,6 @@ def item_candidates(item, artist, title):
# Notify subscribed plugins about fetched track info
for i in out:
plugins.send('trackinfo_received', info=i)
plugins.send(u'trackinfo_received', info=i)
return out

View file

@ -17,8 +17,7 @@
releases and tracks.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import datetime
import re
@ -337,7 +336,7 @@ def _add_candidate(items, results, info):
# Discard albums with zero tracks.
if not info.tracks:
log.debug('No tracks.')
log.debug(u'No tracks.')
return
# Don't duplicate.

View file

@ -15,8 +15,7 @@
"""Searches for albums in the MusicBrainz database.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import musicbrainzngs
import re
@ -43,7 +42,7 @@ class MusicBrainzAPIError(util.HumanReadableException):
def __init__(self, reason, verb, query, tb=None):
self.query = query
if isinstance(reason, musicbrainzngs.WebServiceError):
reason = 'MusicBrainz not reachable'
reason = u'MusicBrainz not reachable'
super(MusicBrainzAPIError, self).__init__(reason, verb, tb)
def get_message(self):
@ -162,7 +161,7 @@ def track_info(recording, index=None, medium=None, medium_index=None,
medium=medium,
medium_index=medium_index,
medium_total=medium_total,
data_source='MusicBrainz',
data_source=u'MusicBrainz',
data_url=track_url(recording['id']),
)
@ -256,7 +255,7 @@ def album_info(release):
mediums=len(release['medium-list']),
artist_sort=artist_sort_name,
artist_credit=artist_credit_name,
data_source='MusicBrainz',
data_source=u'MusicBrainz',
data_url=album_url(release['id']),
)
info.va = info.artist_id == VARIOUS_ARTISTS_ID
@ -377,7 +376,7 @@ def _parse_id(s):
no ID can be found, return None.
"""
# Find the first thing that looks like a UUID/MBID.
match = re.search('[a-f0-9]{8}(-[a-f0-9]{4}){3}-[a-f0-9]{12}', s)
match = re.search(ur'[a-f0-9]{8}(-[a-f0-9]{4}){3}-[a-f0-9]{12}', s)
if match:
return match.group()
@ -398,7 +397,7 @@ def album_for_id(releaseid):
log.debug(u'Album ID match failed.')
return None
except musicbrainzngs.MusicBrainzError as exc:
raise MusicBrainzAPIError(exc, 'get release by ID', albumid,
raise MusicBrainzAPIError(exc, u'get release by ID', albumid,
traceback.format_exc())
return album_info(res['release'])
@ -417,6 +416,6 @@ def track_for_id(releaseid):
log.debug(u'Track ID match failed.')
return None
except musicbrainzngs.MusicBrainzError as exc:
raise MusicBrainzAPIError(exc, 'get recording by ID', trackid,
raise MusicBrainzAPIError(exc, u'get recording by ID', trackid,
traceback.format_exc())
return track_info(res['recording'])

View file

@ -16,7 +16,7 @@
"""DBCore is an abstract database package that forms the basis for beets'
Library.
"""
from __future__ import absolute_import
from __future__ import division, absolute_import, print_function
from .db import Model, Database
from .query import Query, FieldQuery, MatchQuery, AndQuery, OrQuery

View file

@ -15,8 +15,7 @@
"""The central Model and Database constructs for DBCore.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import time
import os
@ -201,9 +200,11 @@ class Model(object):
exception is raised otherwise.
"""
if not self._db:
raise ValueError('{0} has no database'.format(type(self).__name__))
raise ValueError(
u'{0} has no database'.format(type(self).__name__)
)
if need_id and not self.id:
raise ValueError('{0} has no id'.format(type(self).__name__))
raise ValueError(u'{0} has no id'.format(type(self).__name__))
# Essential field accessors.
@ -255,11 +256,11 @@ class Model(object):
del self._values_flex[key]
self._dirty.add(key) # Mark for dropping on store.
elif key in self._getters(): # Computed.
raise KeyError('computed field {0} cannot be deleted'.format(key))
raise KeyError(u'computed field {0} cannot be deleted'.format(key))
elif key in self._fields: # Fixed.
raise KeyError('fixed field {0} cannot be deleted'.format(key))
raise KeyError(u'fixed field {0} cannot be deleted'.format(key))
else:
raise KeyError('no such field {0}'.format(key))
raise KeyError(u'no such field {0}'.format(key))
def keys(self, computed=False):
"""Get a list of available field names for this object. The
@ -318,12 +319,12 @@ class Model(object):
def __getattr__(self, key):
if key.startswith('_'):
raise AttributeError('model has no attribute {0!r}'.format(key))
raise AttributeError(u'model has no attribute {0!r}'.format(key))
else:
try:
return self[key]
except KeyError:
raise AttributeError('no such field {0!r}'.format(key))
raise AttributeError(u'no such field {0!r}'.format(key))
def __setattr__(self, key, value):
if key.startswith('_'):
@ -390,7 +391,7 @@ class Model(object):
"""
self._check_db()
stored_obj = self._db._get(type(self), self.id)
assert stored_obj is not None, "object {0} not in DB".format(self.id)
assert stored_obj is not None, u"object {0} not in DB".format(self.id)
self._values_fixed = {}
self._values_flex = {}
self.update(dict(stored_obj))
@ -463,7 +464,7 @@ class Model(object):
"""Parse a string as a value for the given key.
"""
if not isinstance(string, basestring):
raise TypeError("_parse() argument must be a string")
raise TypeError(u"_parse() argument must be a string")
return cls._type(key).parse(string)
@ -611,7 +612,7 @@ class Results(object):
it.next()
return it.next()
except StopIteration:
raise IndexError('result index {0} out of range'.format(n))
raise IndexError(u'result index {0} out of range'.format(n))
def get(self):
"""Return the first matching object, or None if no objects

View file

@ -15,8 +15,7 @@
"""The Query type hierarchy for DBCore.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import re
from operator import mul
@ -39,7 +38,7 @@ class InvalidQueryError(ParsingError):
def __init__(self, query, explanation):
if isinstance(query, list):
query = " ".join(query)
message = "'{0}': {1}".format(query, explanation)
message = u"'{0}': {1}".format(query, explanation)
super(InvalidQueryError, self).__init__(message)
@ -50,9 +49,9 @@ class InvalidQueryArgumentTypeError(ParsingError):
query) InvalidQueryError can be raised.
"""
def __init__(self, what, expected, detail=None):
message = "'{0}' is not {1}".format(what, expected)
message = u"'{0}' is not {1}".format(what, expected)
if detail:
message = "{0}: {1}".format(message, detail)
message = u"{0}: {1}".format(message, detail)
super(InvalidQueryArgumentTypeError, self).__init__(message)
@ -208,7 +207,7 @@ class RegexpQuery(StringFieldQuery):
except re.error as exc:
# Invalid regular expression.
raise InvalidQueryArgumentTypeError(pattern,
"a regular expression",
u"a regular expression",
format(exc))
@staticmethod
@ -283,7 +282,7 @@ class NumericQuery(FieldQuery):
try:
return float(s)
except ValueError:
raise InvalidQueryArgumentTypeError(s, "an int or a float")
raise InvalidQueryArgumentTypeError(s, u"an int or a float")
def __init__(self, field, pattern, fast=True):
super(NumericQuery, self).__init__(field, pattern, fast)
@ -328,7 +327,7 @@ class NumericQuery(FieldQuery):
elif self.rangemax is not None:
return u'{0} <= ?'.format(self.field), (self.rangemax,)
else:
return '1', ()
return u'1', ()
class CollectionQuery(Query):
@ -369,7 +368,7 @@ class CollectionQuery(Query):
return clause, subvals
def __repr__(self):
return "{0.__class__.__name__}({0.subqueries})".format(self)
return "{0.__class__.__name__}({0.subqueries!r})".format(self)
def __eq__(self, other):
return super(CollectionQuery, self).__eq__(other) and \
@ -407,7 +406,7 @@ class AnyFieldQuery(CollectionQuery):
return False
def __repr__(self):
return ("{0.__class__.__name__}({0.pattern!r}, {0.fields}, "
return ("{0.__class__.__name__}({0.pattern!r}, {0.fields!r}, "
"{0.query_class.__name__})".format(self))
def __eq__(self, other):
@ -467,7 +466,7 @@ class NotQuery(Query):
return not self.subquery.match(item)
def __repr__(self):
return "{0.__class__.__name__}({0.subquery})".format(self)
return "{0.__class__.__name__}({0.subquery!r})".format(self)
def __eq__(self, other):
return super(NotQuery, self).__eq__(other) and \
@ -535,7 +534,7 @@ class Period(object):
precision (a string, one of "year", "month", or "day").
"""
if precision not in Period.precisions:
raise ValueError('Invalid precision {0}'.format(precision))
raise ValueError(u'Invalid precision {0}'.format(precision))
self.date = date
self.precision = precision
@ -575,7 +574,7 @@ class Period(object):
elif 'day' == precision:
return date + timedelta(days=1)
else:
raise ValueError('unhandled precision {0}'.format(precision))
raise ValueError(u'unhandled precision {0}'.format(precision))
class DateInterval(object):
@ -587,7 +586,7 @@ class DateInterval(object):
def __init__(self, start, end):
if start is not None and end is not None and not start < end:
raise ValueError("start date {0} is not before end date {1}"
raise ValueError(u"start date {0} is not before end date {1}"
.format(start, end))
self.start = start
self.end = end
@ -608,7 +607,7 @@ class DateInterval(object):
return True
def __str__(self):
return'[{0}, {1})'.format(self.start, self.end)
return '[{0}, {1})'.format(self.start, self.end)
class DateQuery(FieldQuery):
@ -677,7 +676,7 @@ class DurationQuery(NumericQuery):
except ValueError:
raise InvalidQueryArgumentTypeError(
s,
"a M:SS string or a float")
u"a M:SS string or a float")
# Sorting.
@ -769,7 +768,7 @@ class MultipleSort(Sort):
return items
def __repr__(self):
return u'MultipleSort({0})'.format(repr(self.sorts))
return 'MultipleSort({!r})'.format(self.sorts)
def __hash__(self):
return hash(tuple(self.sorts))
@ -802,7 +801,7 @@ class FieldSort(Sort):
return sorted(objs, key=key, reverse=not self.ascending)
def __repr__(self):
return u'<{0}: {1}{2}>'.format(
return '<{0}: {1}{2}>'.format(
type(self).__name__,
self.field,
'+' if self.ascending else '-',

View file

@ -15,8 +15,7 @@
"""Representation of type information for DBCore model fields.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from . import query
from beets.util import str2bool

View file

@ -13,8 +13,7 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
"""Provides the basic, interface-agnostic workflow for importing and
autotagging music files.
@ -251,17 +250,17 @@ class ImportSession(object):
if duplicate:
# Duplicate: log all three choices (skip, keep both, and trump).
if task.should_remove_duplicates:
self.tag_log('duplicate-replace', paths)
self.tag_log(u'duplicate-replace', paths)
elif task.choice_flag in (action.ASIS, action.APPLY):
self.tag_log('duplicate-keep', paths)
self.tag_log(u'duplicate-keep', paths)
elif task.choice_flag is (action.SKIP):
self.tag_log('duplicate-skip', paths)
self.tag_log(u'duplicate-skip', paths)
else:
# Non-duplicate: log "skip" and "asis" choices.
if task.choice_flag is action.ASIS:
self.tag_log('asis', paths)
self.tag_log(u'asis', paths)
elif task.choice_flag is action.SKIP:
self.tag_log('skip', paths)
self.tag_log(u'skip', paths)
def should_resume(self, path):
raise NotImplementedError
@ -1150,7 +1149,7 @@ class ImportTaskFactory(object):
if not (self.session.config['move'] or
self.session.config['copy']):
log.warn(u"Archive importing requires either "
"'copy' or 'move' to be enabled.")
u"'copy' or 'move' to be enabled.")
return
log.debug(u'Extracting archive: {0}',
@ -1325,7 +1324,7 @@ def resolve_duplicates(session, task):
if task.choice_flag in (action.ASIS, action.APPLY, action.RETAG):
found_duplicates = task.find_duplicates(session.lib)
if found_duplicates:
log.debug('found duplicates: {}'.format(
log.debug(u'found duplicates: {}'.format(
[o.id for o in found_duplicates]
))
session.resolve_duplicate(task, found_duplicates)
@ -1342,7 +1341,7 @@ def import_asis(session, task):
if task.skip:
return
log.info('{}', displayable_path(task.paths))
log.info(u'{}', displayable_path(task.paths))
task.set_choice(action.ASIS)
apply_choice(session, task)

View file

@ -15,8 +15,7 @@
"""The core data store and collection logic for beets.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import os
import sys
@ -627,7 +626,7 @@ class Item(LibModel):
self.write(path, tags)
return True
except FileOperationError as exc:
log.error("{0}", exc)
log.error(u"{0}", exc)
return False
def try_sync(self, write, move, with_album=True):
@ -647,7 +646,7 @@ class Item(LibModel):
if move:
# Check whether this file is inside the library directory.
if self._db and self._db.directory in util.ancestry(self.path):
log.debug('moving {0} to synchronize path',
log.debug(u'moving {0} to synchronize path',
util.displayable_path(self.path))
self.move(with_album=with_album)
self.store()
@ -796,7 +795,7 @@ class Item(LibModel):
if query == PF_KEY_DEFAULT:
break
else:
assert False, "no default path format"
assert False, u"no default path format"
if isinstance(path_format, Template):
subpath_tmpl = path_format
else:
@ -826,9 +825,12 @@ class Item(LibModel):
if fellback:
# Print an error message if legalization fell back to
# default replacements because of the maximum length.
log.warning('Fell back to default replacements when naming '
'file {}. Configure replacements to avoid lengthening '
'the filename.', subpath)
log.warning(
u'Fell back to default replacements when naming '
u'file {}. Configure replacements to avoid lengthening '
u'the filename.',
subpath
)
if fragment:
return subpath
@ -1016,7 +1018,7 @@ class Album(LibModel):
"""
item = self.items().get()
if not item:
raise ValueError('empty album')
raise ValueError(u'empty album')
return os.path.dirname(item.path)
def _albumtotal(self):
@ -1170,7 +1172,7 @@ def parse_query_string(s, model_cls):
The string is split into components using shell-like syntax.
"""
assert isinstance(s, unicode), "Query is not unicode: {0!r}".format(s)
assert isinstance(s, unicode), u"Query is not unicode: {0!r}".format(s)
try:
parts = util.shlex_split(s)
except ValueError as exc:

View file

@ -21,8 +21,7 @@ that when getLogger(name) instantiates a logger that logger uses
{}-style formatting.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from copy import copy
from logging import * # noqa

View file

@ -33,8 +33,7 @@ Internally ``MediaFile`` uses ``MediaField`` descriptors to access the
data from the tags. In turn ``MediaField`` uses a number of
``StorageStyle`` strategies to handle format specific logic.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import mutagen
import mutagen.mp3
@ -650,13 +649,13 @@ class MP4BoolStorageStyle(MP4StorageStyle):
return None
def get_list(self, mutagen_file):
raise NotImplementedError('MP4 bool storage does not support lists')
raise NotImplementedError(u'MP4 bool storage does not support lists')
def set(self, mutagen_file, value):
mutagen_file[self.key] = value
def set_list(self, mutagen_file, values):
raise NotImplementedError('MP4 bool storage does not support lists')
raise NotImplementedError(u'MP4 bool storage does not support lists')
class MP4ImageStorageStyle(MP4ListStorageStyle):
@ -674,7 +673,7 @@ class MP4ImageStorageStyle(MP4ListStorageStyle):
elif image.mime_type == 'image/jpeg':
kind = mutagen.mp4.MP4Cover.FORMAT_JPEG
else:
raise ValueError('MP4 files only supports PNG and JPEG images')
raise ValueError(u'MP4 files only supports PNG and JPEG images')
return mutagen.mp4.MP4Cover(image.data, kind)
@ -1364,11 +1363,11 @@ class MediaFile(object):
# anywhere else.
raise
else:
log.debug('{}', traceback.format_exc())
log.debug(u'{}', traceback.format_exc())
raise MutagenError(path, exc)
except Exception as exc:
# Isolate bugs in Mutagen.
log.debug('{}', traceback.format_exc())
log.debug(u'{}', traceback.format_exc())
log.error(u'uncaught Mutagen exception in open: {0}', exc)
raise MutagenError(path, exc)
@ -1441,7 +1440,7 @@ class MediaFile(object):
# Propagate these through: they don't represent Mutagen bugs.
raise
except Exception as exc:
log.debug('{}', traceback.format_exc())
log.debug(u'{}', traceback.format_exc())
log.error(u'uncaught Mutagen exception in save: {0}', exc)
raise MutagenError(self.path, exc)

View file

@ -15,8 +15,7 @@
"""Support for beets plugins."""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import inspect
import traceback
@ -267,7 +266,7 @@ def load_plugins(names=()):
except:
log.warn(
'** error loading plugin {}:\n{}',
u'** error loading plugin {}:\n{}',
name,
traceback.format_exc(),
)
@ -322,8 +321,8 @@ def types(model_cls):
if field in types and plugin_types[field] != types[field]:
raise PluginConflictException(
u'Plugin {0} defines flexible field {1} '
'which has already been defined with '
'another type.'.format(plugin.name, field)
u'which has already been defined with '
u'another type.'.format(plugin.name, field)
)
types.update(plugin_types)
return types

View file

@ -18,8 +18,7 @@ interface. To invoke the CLI, just call beets.ui.main(). The actual
CLI commands are implemented in the ui.commands module.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import locale
import optparse
@ -192,7 +191,7 @@ def input_(prompt=None):
try:
resp = raw_input()
except EOFError:
raise UserError('stdin stream ended while input required')
raise UserError(u'stdin stream ended while input required')
return resp.decode(sys.stdin.encoding or 'utf8', 'ignore')
@ -238,7 +237,7 @@ def input_options(options, require=False, prompt=None, fallback_prompt=None,
found_letter = letter
break
else:
raise ValueError('no unambiguous lettering found')
raise ValueError(u'no unambiguous lettering found')
letters[found_letter.lower()] = option
index = option.index(found_letter)
@ -321,9 +320,9 @@ def input_options(options, require=False, prompt=None, fallback_prompt=None,
# Make a fallback prompt too. This is displayed if the user enters
# something that is not recognized.
if not fallback_prompt:
fallback_prompt = 'Enter one of '
fallback_prompt = u'Enter one of '
if numrange:
fallback_prompt += '%i-%i, ' % numrange
fallback_prompt += u'%i-%i, ' % numrange
fallback_prompt += ', '.join(display_letters) + ':'
resp = input_(prompt)
@ -362,9 +361,9 @@ def input_yn(prompt, require=False):
"yes" unless `require` is `True`, in which case there is no default.
"""
sel = input_options(
('y', 'n'), require, prompt, 'Enter Y or N:'
('y', 'n'), require, prompt, u'Enter Y or N:'
)
return sel == 'y'
return sel == u'y'
def input_select_objects(prompt, objs, rep):
@ -376,18 +375,18 @@ def input_select_objects(prompt, objs, rep):
object to print it out when confirming objects individually.
"""
choice = input_options(
('y', 'n', 's'), False,
'%s? (Yes/no/select)' % prompt)
(u'y', u'n', u's'), False,
u'%s? (Yes/no/select)' % prompt)
print() # Blank line.
if choice == 'y': # Yes.
if choice == u'y': # Yes.
return objs
elif choice == 's': # Select.
elif choice == u's': # Select.
out = []
for obj in objs:
rep(obj)
if input_yn('%s? (yes/no)' % prompt, True):
if input_yn(u'%s? (yes/no)' % prompt, True):
out.append(obj)
print() # go to a new line
return out
@ -400,14 +399,14 @@ def input_select_objects(prompt, objs, rep):
def human_bytes(size):
"""Formats size, a number of bytes, in a human-readable way."""
powers = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 'H']
powers = [u'', u'K', u'M', u'G', u'T', u'P', u'E', u'Z', u'Y', u'H']
unit = 'B'
for power in powers:
if size < 1024:
return "%3.1f %s%s" % (size, power, unit)
return u"%3.1f %s%s" % (size, power, unit)
size /= 1024.0
unit = 'iB'
return "big"
unit = u'iB'
return u"big"
def human_seconds(interval):
@ -415,13 +414,13 @@ def human_seconds(interval):
interval using English words.
"""
units = [
(1, 'second'),
(60, 'minute'),
(60, 'hour'),
(24, 'day'),
(7, 'week'),
(52, 'year'),
(10, 'decade'),
(1, u'second'),
(60, u'minute'),
(60, u'hour'),
(24, u'day'),
(7, u'week'),
(52, u'year'),
(10, u'decade'),
]
for i in range(len(units) - 1):
increment, suffix = units[i]
@ -434,7 +433,7 @@ def human_seconds(interval):
increment, suffix = units[-1]
interval /= float(increment)
return "%3.1f %ss" % (interval, suffix)
return u"%3.1f %ss" % (interval, suffix)
def human_seconds_short(interval):
@ -495,7 +494,7 @@ def _colorize(color, text):
elif color in LIGHT_COLORS:
escape = COLOR_ESCAPE + "%i;01m" % (LIGHT_COLORS[color] + 30)
else:
raise ValueError('no such color %s', color)
raise ValueError(u'no such color %s', color)
return escape + text + RESET_COLOR
@ -777,7 +776,7 @@ class CommonOptionsParser(optparse.OptionParser, object):
Sets the album property on the options extracted from the CLI.
"""
album = optparse.Option(*flags, action='store_true',
help='match albums instead of tracks')
help=u'match albums instead of tracks')
self.add_option(album)
self._album_flags = set(flags)
@ -822,7 +821,7 @@ class CommonOptionsParser(optparse.OptionParser, object):
callback=self._set_format,
callback_kwargs={'fmt': '$path',
'store_true': True},
help='print paths for matched items or albums')
help=u'print paths for matched items or albums')
self.add_option(path)
def add_format_option(self, flags=('-f', '--format'), target=None):
@ -850,7 +849,7 @@ class CommonOptionsParser(optparse.OptionParser, object):
opt = optparse.Option(*flags, action='callback',
callback=self._set_format,
callback_kwargs=kwargs,
help='print with custom format')
help=u'print with custom format')
self.add_option(opt)
def add_all_common_options(self):
@ -916,7 +915,7 @@ class SubcommandsOptionParser(CommonOptionsParser):
"""
# A more helpful default usage.
if 'usage' not in kwargs:
kwargs['usage'] = """
kwargs['usage'] = u"""
%prog COMMAND [ARGS...]
%prog help COMMAND"""
kwargs['add_help_option'] = False
@ -1024,7 +1023,7 @@ class SubcommandsOptionParser(CommonOptionsParser):
cmdname = args.pop(0)
subcommand = self._subcommand_for_name(cmdname)
if not subcommand:
raise UserError("unknown command '{0}'".format(cmdname))
raise UserError(u"unknown command '{0}'".format(cmdname))
suboptions, subargs = subcommand.parse_args(args)
return subcommand, suboptions, subargs
@ -1076,7 +1075,7 @@ def _load_plugins(config):
"""
paths = config['pluginpath'].get(confit.StrSeq(split=False))
paths = map(util.normpath, paths)
log.debug('plugin paths: {0}', util.displayable_path(paths))
log.debug(u'plugin paths: {0}', util.displayable_path(paths))
import beetsplug
beetsplug.__path__ = paths + beetsplug.__path__
@ -1146,10 +1145,13 @@ def _configure(options):
old_key = 'list_format_{0}'.format(elem)
if config[old_key].exists():
new_key = 'format_{0}'.format(elem)
log.warning('Warning: configuration uses "{0}" which is deprecated'
' in favor of "{1}" now that it affects all commands. '
'See changelog & documentation.'.format(old_key,
new_key))
log.warning(
u'Warning: configuration uses "{0}" which is deprecated'
u' in favor of "{1}" now that it affects all commands. '
u'See changelog & documentation.',
old_key,
new_key,
)
config[new_key].set(config[old_key])
config_path = config.user_config_path()
@ -1178,7 +1180,7 @@ def _open_library(config):
)
lib.get_item(0) # Test database connection.
except (sqlite3.OperationalError, sqlite3.DatabaseError):
log.debug('{}', traceback.format_exc())
log.debug(u'{}', traceback.format_exc())
raise UserError(u"database file {0} could not be opened".format(
util.displayable_path(dbpath)
))
@ -1197,15 +1199,15 @@ def _raw_main(args, lib=None):
parser.add_format_option(flags=('--format-item',), target=library.Item)
parser.add_format_option(flags=('--format-album',), target=library.Album)
parser.add_option('-l', '--library', dest='library',
help='library database file to use')
help=u'library database file to use')
parser.add_option('-d', '--directory', dest='directory',
help="destination music directory")
help=u"destination music directory")
parser.add_option('-v', '--verbose', dest='verbose', action='count',
help='log more details (use twice for even more)')
help=u'log more details (use twice for even more)')
parser.add_option('-c', '--config', dest='config',
help='path to configuration file')
help=u'path to configuration file')
parser.add_option('-h', '--help', dest='help', action='store_true',
help='show this help message and exit')
help=u'show this help message and exit')
parser.add_option('--version', dest='version', action='store_true',
help=optparse.SUPPRESS_HELP)
@ -1261,4 +1263,4 @@ def main(args=None):
raise
except KeyboardInterrupt:
# Silently ignore ^C except in verbose mode.
log.debug('{}', traceback.format_exc())
log.debug(u'{}', traceback.format_exc())

File diff suppressed because it is too large Load diff

View file

@ -15,8 +15,7 @@
"""Miscellaneous utility functions."""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import os
import sys
import re
@ -57,10 +56,10 @@ class HumanReadableException(Exception):
def _gerund(self):
"""Generate a (likely) gerund form of the English verb.
"""
if ' ' in self.verb:
if u' ' in self.verb:
return self.verb
gerund = self.verb[:-1] if self.verb.endswith('e') else self.verb
gerund += 'ing'
gerund = self.verb[:-1] if self.verb.endswith(u'e') else self.verb
gerund += u'ing'
return gerund
def _reasonstr(self):
@ -415,7 +414,7 @@ def copy(path, dest, replace=False):
path = syspath(path)
dest = syspath(dest)
if not replace and os.path.exists(dest):
raise FilesystemError('file exists', 'copy', (path, dest))
raise FilesystemError(u'file exists', 'copy', (path, dest))
try:
shutil.copyfile(path, dest)
except (OSError, IOError) as exc:
@ -436,7 +435,7 @@ def move(path, dest, replace=False):
path = syspath(path)
dest = syspath(dest)
if os.path.exists(dest) and not replace:
raise FilesystemError('file exists', 'rename', (path, dest),
raise FilesystemError(u'file exists', 'rename', (path, dest),
traceback.format_exc())
# First, try renaming the file.
@ -462,13 +461,13 @@ def link(path, dest, replace=False):
path = syspath(path)
dest = syspath(dest)
if os.path.exists(dest) and not replace:
raise FilesystemError('file exists', 'rename', (path, dest),
raise FilesystemError(u'file exists', 'rename', (path, dest),
traceback.format_exc())
try:
os.symlink(path, dest)
except OSError:
raise FilesystemError('Operating system does not support symbolic '
'links.', 'link', (path, dest),
raise FilesystemError(u'Operating system does not support symbolic '
u'links.', 'link', (path, dest),
traceback.format_exc())
@ -619,7 +618,7 @@ def legalize_path(path, replacements, length, extension, fragment):
def str2bool(value):
"""Returns a boolean reflecting a human-entered string."""
return value.lower() in ('yes', '1', 'true', 't', 'y')
return value.lower() in (u'yes', u'1', u'true', u't', u'y')
def as_string(value):
@ -643,7 +642,7 @@ def plurality(objs):
"""
c = Counter(objs)
if not c:
raise ValueError('sequence must be non-empty')
raise ValueError(u'sequence must be non-empty')
return c.most_common(1)[0]
@ -766,7 +765,7 @@ def shlex_split(s):
return [c.decode('utf8') for c in shlex.split(bs)]
else:
raise TypeError('shlex_split called with non-string')
raise TypeError(u'shlex_split called with non-string')
def interactive_open(targets, command):
@ -854,8 +853,8 @@ def raw_seconds_short(string):
Raises ValueError if the conversion cannot take place due to `string` not
being in the right format.
"""
match = re.match('^(\d+):([0-5]\d)$', string)
match = re.match(r'^(\d+):([0-5]\d)$', string)
if not match:
raise ValueError('String not in M:SS format')
raise ValueError(u'String not in M:SS format')
minutes, seconds = map(int, match.groups())
return float(minutes * 60 + seconds)

View file

@ -16,8 +16,7 @@
"""Abstraction layer to resize images using PIL, ImageMagick, or a
public resizing proxy if neither is available.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import urllib
import subprocess
@ -125,10 +124,10 @@ def im_getsize(path_in):
try:
out = util.command_output(cmd)
except subprocess.CalledProcessError as exc:
log.warn('ImageMagick size query failed')
log.warn(u'ImageMagick size query failed')
log.debug(
'`convert` exited with (status {}) when '
'getting size with command {}:\n{}',
u'`convert` exited with (status {}) when '
u'getting size with command {}:\n{}',
exc.returncode, cmd, exc.output.strip()
)
return

View file

@ -7,8 +7,7 @@ asyncore.
Bluelet: easy concurrency without all the messy parallelism.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import socket
import select
@ -555,7 +554,7 @@ def spawn(coro):
and child coroutines run concurrently.
"""
if not isinstance(coro, types.GeneratorType):
raise ValueError('%s is not a coroutine' % coro)
raise ValueError(u'%s is not a coroutine' % coro)
return SpawnEvent(coro)
@ -565,7 +564,7 @@ def call(coro):
returns a value using end(), then this event returns that value.
"""
if not isinstance(coro, types.GeneratorType):
raise ValueError('%s is not a coroutine' % coro)
raise ValueError(u'%s is not a coroutine' % coro)
return DelegationEvent(coro)

View file

@ -15,8 +15,7 @@
"""Worry-free YAML configuration files.
"""
from __future__ import (unicode_literals, absolute_import, print_function,
division)
from __future__ import division, absolute_import, print_function
import platform
import os
@ -101,17 +100,17 @@ class ConfigReadError(ConfigError):
self.filename = filename
self.reason = reason
message = 'file {0} could not be read'.format(filename)
message = u'file {0} could not be read'.format(filename)
if isinstance(reason, yaml.scanner.ScannerError) and \
reason.problem == YAML_TAB_PROBLEM:
# Special-case error message for tab indentation in YAML markup.
message += ': found tab character at line {0}, column {1}'.format(
message += u': found tab character at line {0}, column {1}'.format(
reason.problem_mark.line + 1,
reason.problem_mark.column + 1,
)
elif reason:
# Generic error message uses exception's message.
message += ': {0}'.format(reason)
message += u': {0}'.format(reason)
super(ConfigReadError, self).__init__(message)
@ -125,15 +124,15 @@ class ConfigSource(dict):
def __init__(self, value, filename=None, default=False):
super(ConfigSource, self).__init__(value)
if filename is not None and not isinstance(filename, BASESTRING):
raise TypeError('filename must be a string or None')
raise TypeError(u'filename must be a string or None')
self.filename = filename
self.default = default
def __repr__(self):
return 'ConfigSource({0}, {1}, {2})'.format(
super(ConfigSource, self).__repr__(),
repr(self.filename),
repr(self.default)
return 'ConfigSource({0!r}, {1!r}, {2!r})'.format(
super(ConfigSource, self),
self.filename,
self.default,
)
@classmethod
@ -147,7 +146,7 @@ class ConfigSource(dict):
elif isinstance(value, dict):
return ConfigSource(value)
else:
raise TypeError('source value must be a dict')
raise TypeError(u'source value must be a dict')
class ConfigView(object):
@ -182,7 +181,7 @@ class ConfigView(object):
try:
return iter_first(pairs)
except ValueError:
raise NotFoundError("{0} not found".format(self.name))
raise NotFoundError(u"{0} not found".format(self.name))
def exists(self):
"""Determine whether the view has a setting in any source.
@ -230,7 +229,7 @@ class ConfigView(object):
collection = self.get()
if not isinstance(collection, (list, tuple)):
raise ConfigTypeError(
'{0} must be a dictionary or a list, not {1}'.format(
u'{0} must be a dictionary or a list, not {1}'.format(
self.name, type(collection).__name__
)
)
@ -308,7 +307,7 @@ class ConfigView(object):
cur_keys = dic.keys()
except AttributeError:
raise ConfigTypeError(
'{0} must be a dict, not {1}'.format(
u'{0} must be a dict, not {1}'.format(
self.name, type(dic).__name__
)
)
@ -349,7 +348,7 @@ class ConfigView(object):
it = iter(collection)
except TypeError:
raise ConfigTypeError(
'{0} must be an iterable, not {1}'.format(
u'{0} must be an iterable, not {1}'.format(
self.name, type(collection).__name__
)
)
@ -489,7 +488,7 @@ class Subview(ConfigView):
if not isinstance(self.key, int):
self.name += '.'
if isinstance(self.key, int):
self.name += '#{0}'.format(self.key)
self.name += u'#{0}'.format(self.key)
elif isinstance(self.key, BASESTRING):
if isinstance(self.key, bytes):
self.name += self.key.decode('utf8')
@ -511,7 +510,7 @@ class Subview(ConfigView):
except TypeError:
# Not subscriptable.
raise ConfigTypeError(
"{0} must be a collection, not {1}".format(
u"{0} must be a collection, not {1}".format(
self.parent.name, type(collection).__name__
)
)
@ -621,7 +620,7 @@ class Loader(yaml.SafeLoader):
else:
raise yaml.constructor.ConstructorError(
None, None,
'expected a mapping node, but found %s' % node.id,
u'expected a mapping node, but found %s' % node.id,
node.start_mark
)
@ -632,7 +631,7 @@ class Loader(yaml.SafeLoader):
hash(key)
except TypeError as exc:
raise yaml.constructor.ConstructorError(
'while constructing a mapping',
u'while constructing a mapping',
node.start_mark, 'found unacceptable key (%s)' % exc,
key_node.start_mark
)
@ -710,9 +709,9 @@ class Dumper(yaml.SafeDumper):
"""Represent bool as 'yes' or 'no' instead of 'true' or 'false'.
"""
if data:
value = 'yes'
value = u'yes'
else:
value = 'no'
value = u'no'
return self.represent_scalar('tag:yaml.org,2002:bool', value)
def represent_none(self, data):
@ -837,7 +836,7 @@ class Configuration(RootView):
appdir = os.environ[self._env_var]
appdir = os.path.abspath(os.path.expanduser(appdir))
if os.path.isfile(appdir):
raise ConfigError('{0} must be a directory'.format(
raise ConfigError(u'{0} must be a directory'.format(
self._env_var
))
@ -990,7 +989,7 @@ class Template(object):
return self.convert(value, view)
elif self.default is REQUIRED:
# Missing required value. This is an error.
raise NotFoundError("{0} not found".format(view.name))
raise NotFoundError(u"{0} not found".format(view.name))
else:
# Missing value, but not required.
return self.default
@ -1015,7 +1014,7 @@ class Template(object):
"""
exc_class = ConfigTypeError if type_error else ConfigValueError
raise exc_class(
'{0}: {1}'.format(view.name, message)
u'{0}: {1}'.format(view.name, message)
)
def __repr__(self):
@ -1036,7 +1035,7 @@ class Integer(Template):
elif isinstance(value, float):
return int(value)
else:
self.fail('must be a number', view, True)
self.fail(u'must be a number', view, True)
class Number(Template):
@ -1049,7 +1048,7 @@ class Number(Template):
return value
else:
self.fail(
'must be numeric, not {0}'.format(type(value).__name__),
u'must be numeric, not {0}'.format(type(value).__name__),
view,
True
)
@ -1111,12 +1110,12 @@ class String(Template):
if isinstance(value, BASESTRING):
if self.pattern and not self.regex.match(value):
self.fail(
"must match the pattern {0}".format(self.pattern),
u"must match the pattern {0}".format(self.pattern),
view
)
return value
else:
self.fail('must be a string', view, True)
self.fail(u'must be a string', view, True)
class Choice(Template):
@ -1137,7 +1136,7 @@ class Choice(Template):
"""
if value not in self.choices:
self.fail(
'must be one of {0}, not {1}'.format(
u'must be one of {0}, not {1}'.format(
repr(list(self.choices)), repr(value)
),
view
@ -1206,7 +1205,7 @@ class OneOf(Template):
raise ConfigTemplateError(exc)
self.fail(
'must be one of {0}, not {1}'.format(
u'must be one of {0}, not {1}'.format(
repr(self.allowed), repr(value)
),
view
@ -1242,7 +1241,7 @@ class StrSeq(Template):
try:
value = list(value)
except TypeError:
self.fail('must be a whitespace-separated string or a list',
self.fail(u'must be a whitespace-separated string or a list',
view, True)
def convert(x):
@ -1251,7 +1250,7 @@ class StrSeq(Template):
elif isinstance(x, bytes):
return x.decode('utf8', 'ignore')
else:
self.fail('must be a list of strings', view, True)
self.fail(u'must be a list of strings', view, True)
return list(map(convert, value))
@ -1301,19 +1300,19 @@ class Filename(Template):
if not isinstance(template, (collections.Mapping, MappingTemplate)):
# disallow config.get(Filename(relative_to='foo'))
raise ConfigTemplateError(
'relative_to may only be used when getting multiple values.'
u'relative_to may only be used when getting multiple values.'
)
elif self.relative_to == view.key:
raise ConfigTemplateError(
'{0} is relative to itself'.format(view.name)
u'{0} is relative to itself'.format(view.name)
)
elif self.relative_to not in view.parent.keys():
# self.relative_to is not in the config
self.fail(
(
'needs sibling value "{0}" to expand relative path'
u'needs sibling value "{0}" to expand relative path'
).format(self.relative_to),
view
)
@ -1335,12 +1334,12 @@ class Filename(Template):
if next_relative in template.subtemplates:
# we encountered this config key previously
raise ConfigTemplateError((
'{0} and {1} are recursively relative'
u'{0} and {1} are recursively relative'
).format(view.name, self.relative_to))
else:
raise ConfigTemplateError((
'missing template for {0}, needed to expand {1}\'s' +
'relative path'
u'missing template for {0}, needed to expand {1}\'s' +
u'relative path'
).format(self.relative_to, view.name))
next_template.subtemplates[next_relative] = rel_to_template
@ -1352,7 +1351,7 @@ class Filename(Template):
path, source = view.first()
if not isinstance(path, BASESTRING):
self.fail(
'must be a filename, not {0}'.format(type(path).__name__),
u'must be a filename, not {0}'.format(type(path).__name__),
view,
True
)
@ -1390,7 +1389,7 @@ class TypeTemplate(Template):
def convert(self, value, view):
if not isinstance(value, self.typ):
self.fail(
'must be a {0}, not {1}'.format(
u'must be a {0}, not {1}'.format(
self.typ.__name__,
type(value).__name__,
),
@ -1444,4 +1443,4 @@ def as_template(value):
elif isinstance(value, type):
return TypeTemplate(value)
else:
raise ValueError('cannot convert to template: {0!r}'.format(value))
raise ValueError(u'cannot convert to template: {0!r}'.format(value))

View file

@ -13,8 +13,7 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from enum import Enum

View file

@ -27,8 +27,7 @@ This is sort of like a tiny, horrible degeneration of a real templating
engine like Jinja2 or Mustache.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import re
import ast
@ -79,7 +78,7 @@ def ex_literal(val):
return ast.Name(bytes(val), ast.Load())
elif isinstance(val, basestring):
return ast.Str(val)
raise TypeError('no literal for {0}'.format(type(val)))
raise TypeError(u'no literal for {0}'.format(type(val)))
def ex_varassign(name, expr):
@ -571,4 +570,4 @@ if __name__ == b'__main__':
'from __main__ import _tmpl, _vars, _funcs',
number=10000)
print(comp_time)
print('Speedup:', interp_time / comp_time)
print(u'Speedup:', interp_time / comp_time)

View file

@ -32,8 +32,7 @@ To do so, pass an iterable of coroutines to the Pipeline constructor
in place of any single coroutine.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import Queue
from threading import Thread, Lock
@ -362,7 +361,7 @@ class Pipeline(object):
be at least two stages.
"""
if len(stages) < 2:
raise ValueError('pipeline must have at least two stages')
raise ValueError(u'pipeline must have at least two stages')
self.stages = []
for stage in stages:
if isinstance(stage, (list, tuple)):
@ -467,14 +466,14 @@ if __name__ == b'__main__':
# in parallel.
def produce():
for i in range(5):
print('generating %i' % i)
print(u'generating %i' % i)
time.sleep(1)
yield i
def work():
num = yield
while True:
print('processing %i' % num)
print(u'processing %i' % num)
time.sleep(2)
num = yield num * 2
@ -482,7 +481,7 @@ if __name__ == b'__main__':
while True:
num = yield
time.sleep(1)
print('received %i' % num)
print(u'received %i' % num)
ts_start = time.time()
Pipeline([produce(), work(), consume()]).run_sequential()
@ -491,22 +490,22 @@ if __name__ == b'__main__':
ts_par = time.time()
Pipeline([produce(), (work(), work()), consume()]).run_parallel()
ts_end = time.time()
print('Sequential time:', ts_seq - ts_start)
print('Parallel time:', ts_par - ts_seq)
print('Multiply-parallel time:', ts_end - ts_par)
print(u'Sequential time:', ts_seq - ts_start)
print(u'Parallel time:', ts_par - ts_seq)
print(u'Multiply-parallel time:', ts_end - ts_par)
print()
# Test a pipeline that raises an exception.
def exc_produce():
for i in range(10):
print('generating %i' % i)
print(u'generating %i' % i)
time.sleep(1)
yield i
def exc_work():
num = yield
while True:
print('processing %i' % num)
print(u'processing %i' % num)
time.sleep(3)
if num == 3:
raise Exception()
@ -515,6 +514,6 @@ if __name__ == b'__main__':
def exc_consume():
while True:
num = yield
print('received %i' % num)
print(u'received %i' % num)
Pipeline([exc_produce(), exc_work(), exc_consume()]).run_parallel(1)

View file

@ -16,8 +16,7 @@
"""A simple utility for constructing filesystem-like trees from beets
libraries.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from collections import namedtuple
from beets import util

View file

@ -15,8 +15,8 @@
"""A namespace package for beets plugins."""
# Make this a namespace package.
from __future__ import absolute_import
from __future__ import division, absolute_import, print_function
# Make this a namespace package.
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)

View file

@ -15,8 +15,7 @@
"""Fetch various AcousticBrainz metadata using MBID.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import requests
import operator
@ -38,7 +37,7 @@ class AcousticPlugin(plugins.BeetsPlugin):
def commands(self):
cmd = ui.Subcommand('acousticbrainz',
help="fetch metadata from AcousticBrainz")
help=u"fetch metadata from AcousticBrainz")
def func(lib, opts, args):
items = lib.items(ui.decargs(args))
@ -63,24 +62,24 @@ def fetch_info(log, items, write):
try:
return reduce(operator.getitem, map_path, data)
except KeyError:
log.debug('Invalid Path: {}', map_path)
log.debug(u'Invalid Path: {}', map_path)
for item in items:
if item.mb_trackid:
log.info('getting data for: {}', item)
log.info(u'getting data for: {}', item)
# Fetch the data from the AB API.
urls = [generate_url(item.mb_trackid, path) for path in LEVELS]
log.debug('fetching URLs: {}', ' '.join(urls))
log.debug(u'fetching URLs: {}', ' '.join(urls))
try:
res = [requests.get(url) for url in urls]
except requests.RequestException as exc:
log.info('request error: {}', exc)
log.info(u'request error: {}', exc)
continue
# Check for missing tracks.
if any(r.status_code == 404 for r in res):
log.info('recording ID {} not found', item.mb_trackid)
log.info(u'recording ID {} not found', item.mb_trackid)
continue
# Parse the JSON response.
@ -88,7 +87,7 @@ def fetch_info(log, items, write):
data = res[0].json()
data.update(res[1].json())
except ValueError:
log.debug('Invalid Response: {} & {}', [r.text for r in res])
log.debug(u'Invalid Response: {} & {}', [r.text for r in res])
# Get each field and assign it on the item.
item.danceable = get_value(

View file

@ -16,8 +16,7 @@
"""Use command-line tools to check for audio file corruption.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from beets.plugins import BeetsPlugin
from beets.ui import Subcommand
@ -32,7 +31,7 @@ import sys
class BadFiles(BeetsPlugin):
def run_command(self, cmd):
self._log.debug("running command: {}",
self._log.debug(u"running command: {}",
displayable_path(list2cmdline(cmd)))
try:
output = check_output(cmd, stderr=STDOUT)
@ -44,7 +43,7 @@ class BadFiles(BeetsPlugin):
status = e.returncode
except OSError as e:
if e.errno == errno.ENOENT:
ui.print_("command not found: {}".format(cmd[0]))
ui.print_(u"command not found: {}".format(cmd[0]))
sys.exit(1)
else:
raise
@ -87,9 +86,9 @@ class BadFiles(BeetsPlugin):
# First, check whether the path exists. If not, the user
# should probably run `beet update` to cleanup your library.
dpath = displayable_path(item.path)
self._log.debug("checking path: {}", dpath)
self._log.debug(u"checking path: {}", dpath)
if not os.path.exists(item.path):
ui.print_("{}: file does not exist".format(
ui.print_(u"{}: file does not exist".format(
ui.colorize('text_error', dpath)))
# Run the checker against the file if one is found
@ -102,20 +101,20 @@ class BadFiles(BeetsPlugin):
path = item.path.decode(sys.getfilesystemencoding())
status, errors, output = checker(path)
if status > 0:
ui.print_("{}: checker exited withs status {}"
ui.print_(u"{}: checker exited withs status {}"
.format(ui.colorize('text_error', dpath), status))
for line in output:
ui.print_(" {}".format(displayable_path(line)))
elif errors > 0:
ui.print_("{}: checker found {} errors or warnings"
ui.print_(u"{}: checker found {} errors or warnings"
.format(ui.colorize('text_warning', dpath), errors))
for line in output:
ui.print_(" {}".format(displayable_path(line)))
ui.print_(u" {}".format(displayable_path(line)))
else:
ui.print_("{}: ok".format(ui.colorize('text_success', dpath)))
ui.print_(u"{}: ok".format(ui.colorize('text_success', dpath)))
def commands(self):
bad_command = Subcommand('bad',
help='check for corrupt or missing files')
help=u'check for corrupt or missing files')
bad_command.func = self.check_bad
return [bad_command]

View file

@ -18,8 +18,7 @@ Beets library. Attempts to implement a compatible protocol to allow
use of the wide range of MPD clients.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import re
from string import Template
@ -124,9 +123,9 @@ def make_bpd_error(s_code, s_message):
pass
return NewBPDError
ArgumentTypeError = make_bpd_error(ERROR_ARG, 'invalid type for argument')
ArgumentIndexError = make_bpd_error(ERROR_ARG, 'argument out of range')
ArgumentNotFoundError = make_bpd_error(ERROR_NO_EXIST, 'argument not found')
ArgumentTypeError = make_bpd_error(ERROR_ARG, u'invalid type for argument')
ArgumentIndexError = make_bpd_error(ERROR_ARG, u'argument out of range')
ArgumentNotFoundError = make_bpd_error(ERROR_NO_EXIST, u'argument not found')
def cast_arg(t, val):
@ -269,7 +268,7 @@ class BaseServer(object):
conn.authenticated = True
else:
conn.authenticated = False
raise BPDError(ERROR_PASSWORD, 'incorrect password')
raise BPDError(ERROR_PASSWORD, u'incorrect password')
def cmd_commands(self, conn):
"""Lists the commands available to the user."""
@ -807,9 +806,9 @@ class Server(BaseServer):
"""
# Path is ignored. Also, the real MPD does this asynchronously;
# this is done inline.
print('Building directory tree...')
print(u'Building directory tree...')
self.tree = vfs.libtree(self.lib)
print('... done.')
print(u'... done.')
self.updated_time = time.time()
# Path (directory tree) browsing.
@ -848,7 +847,7 @@ class Server(BaseServer):
node = self._resolve_path(path)
if isinstance(node, int):
# Trying to list a track.
raise BPDError(ERROR_ARG, 'this is not a directory')
raise BPDError(ERROR_ARG, u'this is not a directory')
else:
for name, itemid in iter(sorted(node.files.items())):
item = self.lib.get_item(itemid)
@ -1173,18 +1172,18 @@ class BPDPlugin(BeetsPlugin):
def commands(self):
cmd = beets.ui.Subcommand(
'bpd', help='run an MPD-compatible music player server'
'bpd', help=u'run an MPD-compatible music player server'
)
cmd.parser.add_option(
'-d', '--debug', action='store_true',
help='dump all MPD traffic to stdout'
help=u'dump all MPD traffic to stdout'
)
def func(lib, opts, args):
host = args.pop(0) if args else self.config['host'].get(unicode)
port = args.pop(0) if args else self.config['port'].get(int)
if args:
raise beets.ui.UserError('too many arguments')
raise beets.ui.UserError(u'too many arguments')
password = self.config['password'].get(unicode)
volume = self.config['volume'].get(int)
debug = opts.debug or False

View file

@ -17,8 +17,7 @@
music player.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import sys
import time
@ -91,7 +90,7 @@ class GstPlayer(object):
# error
self.player.set_state(gst.STATE_NULL)
err, debug = message.parse_error()
print("Error: {0}".format(err))
print(u"Error: {0}".format(err))
self.playing = False
def _set_volume(self, volume):

View file

@ -15,8 +15,7 @@
"""Determine BPM by pressing a key to the rhythm."""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import time
@ -59,8 +58,8 @@ class BPMPlugin(BeetsPlugin):
def commands(self):
cmd = ui.Subcommand('bpm',
help='determine bpm of a song by pressing \
a key to the rhythm')
help=u'determine bpm of a song by pressing '
u'a key to the rhythm')
cmd.func = self.command
return [cmd]
@ -70,7 +69,7 @@ class BPMPlugin(BeetsPlugin):
def get_bpm(self, items, write=False):
overwrite = self.config['overwrite'].get(bool)
if len(items) > 1:
raise ValueError('Can only get bpm of one song at time')
raise ValueError(u'Can only get bpm of one song at time')
item = items[0]
if item['bpm']:

View file

@ -16,8 +16,7 @@
"""Provides the %bucket{} function for path formatting.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from datetime import datetime
import re
@ -46,7 +45,7 @@ def span_from_str(span_str):
"""Convert string to a 4 digits year
"""
if yearfrom < 100:
raise BucketError("%d must be expressed on 4 digits" % yearfrom)
raise BucketError(u"%d must be expressed on 4 digits" % yearfrom)
# if two digits only, pick closest year that ends by these two
# digits starting from yearfrom
@ -59,12 +58,12 @@ def span_from_str(span_str):
years = [int(x) for x in re.findall('\d+', span_str)]
if not years:
raise ui.UserError("invalid range defined for year bucket '%s': no "
"year found" % span_str)
raise ui.UserError(u"invalid range defined for year bucket '%s': no "
u"year found" % span_str)
try:
years = [normalize_year(x, years[0]) for x in years]
except BucketError as exc:
raise ui.UserError("invalid range defined for year bucket '%s': %s" %
raise ui.UserError(u"invalid range defined for year bucket '%s': %s" %
(span_str, exc))
res = {'from': years[0], 'str': span_str}
@ -119,8 +118,8 @@ def build_year_spans(year_spans_str):
def str2fmt(s):
"""Deduces formatting syntax from a span string.
"""
regex = re.compile("(?P<bef>\D*)(?P<fromyear>\d+)(?P<sep>\D*)"
"(?P<toyear>\d*)(?P<after>\D*)")
regex = re.compile(r"(?P<bef>\D*)(?P<fromyear>\d+)(?P<sep>\D*)"
r"(?P<toyear>\d*)(?P<after>\D*)")
m = re.match(regex, s)
res = {'fromnchars': len(m.group('fromyear')),
@ -166,8 +165,8 @@ def build_alpha_spans(alpha_spans_str, alpha_regexs):
beginIdx = ASCII_DIGITS.index(bucket[0])
endIdx = ASCII_DIGITS.index(bucket[-1])
else:
raise ui.UserError("invalid range defined for alpha bucket "
"'%s': no alphanumeric character found" %
raise ui.UserError(u"invalid range defined for alpha bucket "
u"'%s': no alphanumeric character found" %
elem)
spans.append(
re.compile(

View file

@ -16,8 +16,7 @@
"""Adds Chromaprint/Acoustid acoustic fingerprinting support to the
autotagger. Requires the pyacoustid library.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from beets import plugins
from beets import ui
@ -178,19 +177,19 @@ class AcoustidPlugin(plugins.BeetsPlugin):
def commands(self):
submit_cmd = ui.Subcommand('submit',
help='submit Acoustid fingerprints')
help=u'submit Acoustid fingerprints')
def submit_cmd_func(lib, opts, args):
try:
apikey = config['acoustid']['apikey'].get(unicode)
except confit.NotFoundError:
raise ui.UserError('no Acoustid user API key provided')
raise ui.UserError(u'no Acoustid user API key provided')
submit_items(self._log, apikey, lib.items(ui.decargs(args)))
submit_cmd.func = submit_cmd_func
fingerprint_cmd = ui.Subcommand(
'fingerprint',
help='generate fingerprints for items without them'
help=u'generate fingerprints for items without them'
)
def fingerprint_cmd_func(lib, opts, args):

View file

@ -15,8 +15,7 @@
"""Converts tracks or albums to external directory
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import os
import threading
@ -140,21 +139,21 @@ class ConvertPlugin(BeetsPlugin):
self.register_listener('import_task_files', self._cleanup)
def commands(self):
cmd = ui.Subcommand('convert', help='convert to external location')
cmd = ui.Subcommand('convert', help=u'convert to external location')
cmd.parser.add_option('-p', '--pretend', action='store_true',
help='show actions but do nothing')
help=u'show actions but do nothing')
cmd.parser.add_option('-t', '--threads', action='store', type='int',
help='change the number of threads, \
help=u'change the number of threads, \
defaults to maximum available processors')
cmd.parser.add_option('-k', '--keep-new', action='store_true',
dest='keep_new', help='keep only the converted \
dest='keep_new', help=u'keep only the converted \
and move the old files')
cmd.parser.add_option('-d', '--dest', action='store',
help='set the destination directory')
help=u'set the destination directory')
cmd.parser.add_option('-f', '--format', action='store', dest='format',
help='set the target format of the tracks')
help=u'set the target format of the tracks')
cmd.parser.add_option('-y', '--yes', action='store_true', dest='yes',
help='do not ask for confirmation')
help=u'do not ask for confirmation')
cmd.parser.add_album_option()
cmd.func = self.convert_func
return [cmd]
@ -294,7 +293,7 @@ class ConvertPlugin(BeetsPlugin):
if self.config['embed']:
album = item.get_album()
if album and album.artpath:
self._log.debug('embedding album art from {}',
self._log.debug(u'embedding album art from {}',
util.displayable_path(album.artpath))
art.embed_item(self._log, item, album.artpath,
itempath=converted)
@ -373,7 +372,7 @@ class ConvertPlugin(BeetsPlugin):
if not opts.dest:
opts.dest = self.config['dest'].get()
if not opts.dest:
raise ui.UserError('no convert destination set')
raise ui.UserError(u'no convert destination set')
opts.dest = util.bytestring_path(opts.dest)
if not opts.threads:
@ -393,7 +392,7 @@ class ConvertPlugin(BeetsPlugin):
if not pretend:
ui.commands.list_items(lib, ui.decargs(args), opts.album)
if not (opts.yes or ui.input_yn("Convert? (Y/n)")):
if not (opts.yes or ui.input_yn(u"Convert? (Y/n)")):
return
if opts.album:

View file

@ -16,8 +16,7 @@
"""Adds Discogs album search support to the autotagger. Requires the
discogs-client library.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import beets.ui
from beets import logging
@ -101,24 +100,24 @@ class DiscogsPlugin(BeetsPlugin):
try:
_, _, url = auth_client.get_authorize_url()
except CONNECTION_ERRORS as e:
self._log.debug('connection error: {0}', e)
raise beets.ui.UserError('communication with Discogs failed')
self._log.debug(u'connection error: {0}', e)
raise beets.ui.UserError(u'communication with Discogs failed')
beets.ui.print_("To authenticate with Discogs, visit:")
beets.ui.print_(u"To authenticate with Discogs, visit:")
beets.ui.print_(url)
# Ask for the code and validate it.
code = beets.ui.input_("Enter the code:")
code = beets.ui.input_(u"Enter the code:")
try:
token, secret = auth_client.get_access_token(code)
except DiscogsAPIError:
raise beets.ui.UserError('Discogs authorization failed')
raise beets.ui.UserError(u'Discogs authorization failed')
except CONNECTION_ERRORS as e:
self._log.debug(u'connection error: {0}', e)
raise beets.ui.UserError('Discogs token request failed')
raise beets.ui.UserError(u'Discogs token request failed')
# Save the token for later use.
self._log.debug('Discogs token {0}, secret {1}', token, secret)
self._log.debug(u'Discogs token {0}, secret {1}', token, secret)
with open(self._tokenfile(), 'w') as f:
json.dump({'token': token, 'secret': secret}, f)
@ -153,7 +152,7 @@ class DiscogsPlugin(BeetsPlugin):
else:
return []
except CONNECTION_ERRORS:
self._log.debug('Connection error in album search', exc_info=True)
self._log.debug(u'Connection error in album search', exc_info=True)
return []
def album_for_id(self, album_id):
@ -184,7 +183,7 @@ class DiscogsPlugin(BeetsPlugin):
return self.album_for_id(album_id)
return None
except CONNECTION_ERRORS:
self._log.debug('Connection error in album lookup', exc_info=True)
self._log.debug(u'Connection error in album lookup', exc_info=True)
return None
return self.get_album_info(result)
@ -206,7 +205,7 @@ class DiscogsPlugin(BeetsPlugin):
releases = self.discogs_client.search(query,
type='release').page(1)
except CONNECTION_ERRORS:
self._log.debug("Communication error while searching for {0!r}",
self._log.debug(u"Communication error while searching for {0!r}",
query, exc_info=True)
return []
return [self.get_album_info(release) for release in releases[:5]]

View file

@ -15,8 +15,7 @@
"""List duplicate tracks or albums.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import shlex
@ -54,52 +53,57 @@ class DuplicatesPlugin(BeetsPlugin):
self._command = Subcommand('duplicates',
help=__doc__,
aliases=['dup'])
self._command.parser.add_option('-c', '--count', dest='count',
action='store_true',
help='show duplicate counts')
self._command.parser.add_option('-C', '--checksum', dest='checksum',
action='store', metavar='PROG',
help='report duplicates based on'
' arbitrary command')
self._command.parser.add_option('-d', '--delete', dest='delete',
action='store_true',
help='delete items from library and '
'disk')
self._command.parser.add_option('-F', '--full', dest='full',
action='store_true',
help='show all versions of duplicate'
' tracks or albums')
self._command.parser.add_option('-s', '--strict', dest='strict',
action='store_true',
help='report duplicates only if all'
' attributes are set')
self._command.parser.add_option('-k', '--keys', dest='keys',
action='callback', metavar='KEY1 KEY2',
callback=vararg_callback,
help='report duplicates based on keys')
self._command.parser.add_option('-M', '--merge', dest='merge',
action='store_true',
help='merge duplicate items')
self._command.parser.add_option('-m', '--move', dest='move',
action='store', metavar='DEST',
help='move items to dest')
self._command.parser.add_option('-o', '--copy', dest='copy',
action='store', metavar='DEST',
help='copy items to dest')
self._command.parser.add_option('-t', '--tag', dest='tag',
action='store',
help='tag matched items with \'k=v\''
' attribute')
self._command.parser.add_option(
u'-c', u'--count', dest='count',
action='store_true',
help=u'show duplicate counts',
)
self._command.parser.add_option(
u'-C', u'--checksum', dest='checksum',
action='store', metavar='PROG',
help=u'report duplicates based on arbitrary command',
)
self._command.parser.add_option(
u'-d', u'--delete', dest='delete',
action='store_true',
help=u'delete items from library and disk',
)
self._command.parser.add_option(
u'-F', u'--full', dest='full',
action='store_true',
help=u'show all versions of duplicate tracks or albums',
)
self._command.parser.add_option(
u'-s', u'--strict', dest='strict',
action='store_true',
help=u'report duplicates only if all attributes are set',
)
self._command.parser.add_option(
u'-k', u'--keys', dest='keys',
action='callback', metavar='KEY1 KEY2',
callback=vararg_callback,
help=u'report duplicates based on keys',
)
self._command.parser.add_option(
u'-M', u'--merge', dest='merge',
action='store_true',
help=u'merge duplicate items',
)
self._command.parser.add_option(
u'-m', u'--move', dest='move',
action='store', metavar='DEST',
help=u'move items to dest',
)
self._command.parser.add_option(
u'-o', u'--copy', dest='copy',
action='store', metavar='DEST',
help=u'copy items to dest',
)
self._command.parser.add_option(
u'-t', u'--tag', dest='tag',
action='store',
help=u'tag matched items with \'k=v\' attribute',
)
self._command.parser.add_all_common_options()
def commands(self):
@ -181,7 +185,9 @@ class DuplicatesPlugin(BeetsPlugin):
try:
k, v = tag.split('=')
except:
raise UserError('%s: can\'t parse k=v tag: %s' % (PLUGIN, tag))
raise UserError(
u"{}: can't parse k=v tag: {}".format(PLUGIN, tag)
)
setattr(item, k, v)
item.store()
@ -195,7 +201,7 @@ class DuplicatesPlugin(BeetsPlugin):
checksum = getattr(item, key, False)
if not checksum:
self._log.debug(u'key {0} on item {1} not cached:'
'computing checksum',
u'computing checksum',
key, displayable_path(item.path))
try:
checksum = command_output(args)
@ -208,7 +214,7 @@ class DuplicatesPlugin(BeetsPlugin):
displayable_path(item.path), e)
else:
self._log.debug(u'key {0} on item {1} cached:'
'not computing checksum',
u'not computing checksum',
key, displayable_path(item.path))
return key, checksum
@ -225,11 +231,11 @@ class DuplicatesPlugin(BeetsPlugin):
values = [v for v in values if v not in (None, '')]
if strict and len(values) < len(keys):
self._log.debug(u'some keys {0} on item {1} are null or empty:'
' skipping',
u' skipping',
keys, displayable_path(obj.path))
elif (not strict and not len(values)):
self._log.debug(u'all keys {0} on item {1} are null or empty:'
' skipping',
u' skipping',
keys, displayable_path(obj.path))
else:
key = tuple(values)
@ -279,7 +285,7 @@ class DuplicatesPlugin(BeetsPlugin):
value = getattr(o, f, None)
if value:
self._log.debug(u'key {0} on item {1} is null '
'or empty: setting from item {2}',
u'or empty: setting from item {2}',
f, displayable_path(objs[0].path),
displayable_path(o.path))
setattr(objs[0], f, value)
@ -300,7 +306,7 @@ class DuplicatesPlugin(BeetsPlugin):
missing.album_id = objs[0].id
missing.add(i._db)
self._log.debug(u'item {0} missing from album {1}:'
' merging from {2} into {3}',
u' merging from {2} into {3}',
missing,
objs[0],
displayable_path(o.path),

View file

@ -15,8 +15,7 @@
"""Fetch a variety of acoustic metrics from The Echo Nest.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import time
import socket
@ -465,10 +464,11 @@ class EchonestMetadataPlugin(plugins.BeetsPlugin):
def commands(self):
fetch_cmd = ui.Subcommand('echonest',
help='fetch metadata from The Echo Nest')
help=u'fetch metadata from The Echo Nest')
fetch_cmd.parser.add_option(
'-f', '--force', dest='force', action='store_true', default=False,
help='(re-)download information from the EchoNest'
u'-f', u'--force', dest='force',
action='store_true', default=False,
help=u'(re-)download information from the EchoNest'
)
def fetch_func(lib, opts, args):
@ -483,10 +483,10 @@ class EchonestMetadataPlugin(plugins.BeetsPlugin):
fetch_cmd.func = fetch_func
sim_cmd = ui.Subcommand('echosim', help='show related files')
sim_cmd = ui.Subcommand('echosim', help=u'show related files')
sim_cmd.parser.add_option(
'-t', '--threshold', dest='threshold', action='store',
type='float', default=0.15, help='Set difference threshold'
u'-t', u'--threshold', dest='threshold', action='store',
type='float', default=0.15, help=u'Set difference threshold'
)
sim_cmd.parser.add_format_option()

View file

@ -14,8 +14,7 @@
"""Open metadata information in a text editor to let the user edit it.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from beets import plugins
from beets import util
@ -70,7 +69,7 @@ def load(s):
for d in yaml.load_all(s):
if not isinstance(d, dict):
raise ParseError(
'each entry must be a dictionary; found {}'.format(
u'each entry must be a dictionary; found {}'.format(
type(d).__name__
)
)
@ -80,7 +79,7 @@ def load(s):
out.append({unicode(k): v for k, v in d.items()})
except yaml.YAMLError as e:
raise ParseError('invalid YAML: {}'.format(e))
raise ParseError(u'invalid YAML: {}'.format(e))
return out
@ -159,18 +158,18 @@ class EditPlugin(plugins.BeetsPlugin):
def commands(self):
edit_command = ui.Subcommand(
'edit',
help='interactively edit metadata'
help=u'interactively edit metadata'
)
edit_command.parser.add_option(
'-f', '--field',
u'-f', u'--field',
metavar='FIELD',
action='append',
help='edit this field also',
help=u'edit this field also',
)
edit_command.parser.add_option(
'--all',
u'--all',
action='store_true', dest='all',
help='edit all fields',
help=u'edit all fields',
)
edit_command.parser.add_album_option()
edit_command.func = self._edit_command
@ -184,7 +183,7 @@ class EditPlugin(plugins.BeetsPlugin):
items, albums = _do_query(lib, query, opts.album, False)
objs = albums if opts.album else items
if not objs:
ui.print_('Nothing to edit.')
ui.print_(u'Nothing to edit.')
return
# Get the fields to edit.
@ -253,15 +252,15 @@ class EditPlugin(plugins.BeetsPlugin):
with open(new.name) as f:
new_str = f.read()
if new_str == old_str:
ui.print_("No changes; aborting.")
ui.print_(u"No changes; aborting.")
return False
# Parse the updated data.
try:
new_data = load(new_str)
except ParseError as e:
ui.print_("Could not read data: {}".format(e))
if ui.input_yn("Edit again to fix? (Y/n)", True):
ui.print_(u"Could not read data: {}".format(e))
if ui.input_yn(u"Edit again to fix? (Y/n)", True):
continue
else:
return False
@ -276,18 +275,18 @@ class EditPlugin(plugins.BeetsPlugin):
for obj, obj_old in zip(objs, objs_old):
changed |= ui.show_model_changes(obj, obj_old)
if not changed:
ui.print_('No changes to apply.')
ui.print_(u'No changes to apply.')
return False
# Confirm the changes.
choice = ui.input_options(
('continue Editing', 'apply', 'cancel')
(u'continue Editing', u'apply', u'cancel')
)
if choice == 'a': # Apply.
if choice == u'a': # Apply.
return True
elif choice == 'c': # Cancel.
elif choice == u'c': # Cancel.
return False
elif choice == 'e': # Keep editing.
elif choice == u'e': # Keep editing.
# Reset the temporary changes to the objects.
for obj in objs:
obj.read()
@ -305,7 +304,7 @@ class EditPlugin(plugins.BeetsPlugin):
are temporary.
"""
if len(old_data) != len(new_data):
self._log.warn('number of objects changed from {} to {}',
self._log.warn(u'number of objects changed from {} to {}',
len(old_data), len(new_data))
obj_by_id = {o.id: o for o in objs}
@ -316,7 +315,7 @@ class EditPlugin(plugins.BeetsPlugin):
forbidden = False
for key in ignore_fields:
if old_dict.get(key) != new_dict.get(key):
self._log.warn('ignoring object whose {} changed', key)
self._log.warn(u'ignoring object whose {} changed', key)
forbidden = True
break
if forbidden:
@ -331,7 +330,7 @@ class EditPlugin(plugins.BeetsPlugin):
# Save to the database and possibly write tags.
for ob in objs:
if ob._dirty:
self._log.debug('saving changes to {}', ob)
self._log.debug(u'saving changes to {}', ob)
ob.try_sync(ui.should_write(), ui.should_move())
# Methods for interactive importer execution.

View file

@ -14,8 +14,7 @@
# included in all copies or substantial portions of the Software.
"""Allows beets to embed album art into file metadata."""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import os.path
@ -56,10 +55,10 @@ class EmbedCoverArtPlugin(BeetsPlugin):
def commands(self):
# Embed command.
embed_cmd = ui.Subcommand(
'embedart', help='embed image files into file metadata'
'embedart', help=u'embed image files into file metadata'
)
embed_cmd.parser.add_option(
'-f', '--file', metavar='PATH', help='the image file to embed'
u'-f', u'--file', metavar='PATH', help=u'the image file to embed'
)
maxwidth = self.config['maxwidth'].get(int)
compare_threshold = self.config['compare_threshold'].get(int)
@ -84,17 +83,22 @@ class EmbedCoverArtPlugin(BeetsPlugin):
embed_cmd.func = embed_func
# Extract command.
extract_cmd = ui.Subcommand('extractart',
help='extract an image from file metadata')
extract_cmd.parser.add_option('-o', dest='outpath',
help='image output file')
extract_cmd.parser.add_option('-n', dest='filename',
help='image filename to create for all '
'matched albums')
extract_cmd.parser.add_option('-a', dest='associate',
action='store_true',
help='associate the extracted images '
'with the album')
extract_cmd = ui.Subcommand(
'extractart',
help=u'extract an image from file metadata',
)
extract_cmd.parser.add_option(
u'-o', dest='outpath',
help=u'image output file',
)
extract_cmd.parser.add_option(
u'-n', dest='filename',
help=u'image filename to create for all matched albums',
)
extract_cmd.parser.add_option(
'-a', dest='associate', action='store_true',
help='associate the extracted images with the album',
)
def extract_func(lib, opts, args):
if opts.outpath:
@ -104,8 +108,8 @@ class EmbedCoverArtPlugin(BeetsPlugin):
filename = bytestring_path(opts.filename or
config['art_filename'].get())
if os.path.dirname(filename) != '':
self._log.error(u"Only specify a name rather than a path "
u"for -n")
self._log.error(
u"Only specify a name rather than a path for -n")
return
for album in lib.albums(decargs(args)):
artpath = normpath(os.path.join(album.path, filename))
@ -117,8 +121,10 @@ class EmbedCoverArtPlugin(BeetsPlugin):
extract_cmd.func = extract_func
# Clear command.
clear_cmd = ui.Subcommand('clearart',
help='remove images from file metadata')
clear_cmd = ui.Subcommand(
'clearart',
help=u'remove images from file metadata',
)
def clear_func(lib, opts, args):
art.clear(self._log, lib, decargs(args))
@ -142,7 +148,7 @@ class EmbedCoverArtPlugin(BeetsPlugin):
"""
if self.config['remove_art_file'] and album.artpath:
if os.path.isfile(album.artpath):
self._log.debug('Removing album art file for {0}', album)
self._log.debug(u'Removing album art file for {0}', album)
os.remove(album.artpath)
album.artpath = None
album.store()

View file

@ -8,8 +8,7 @@
username: user
password: password
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from beets import config
from beets.plugins import BeetsPlugin
@ -120,7 +119,8 @@ class EmbyUpdate(BeetsPlugin):
token = get_token(host, port, headers, auth_data)
if not token:
self._log.warning(
u'Couldnt not get token for user {0}'.format(username))
u'Could not get token for user {0}', username
)
return
# Recreate headers with a token.

View file

@ -15,8 +15,7 @@
"""Fetches album art.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from contextlib import closing
import os
@ -206,14 +205,14 @@ class ITunesStore(ArtSource):
try:
results = itunes.search_album(search_string)
except Exception as exc:
self._log.debug('iTunes search failed: {0}', exc)
self._log.debug(u'iTunes search failed: {0}', exc)
return
# Get the first match.
if results:
itunes_album = results[0]
else:
self._log.debug('iTunes search for {:r} got no results',
self._log.debug(u'iTunes search for {:r} got no results',
search_string)
return
@ -276,9 +275,9 @@ class Wikipedia(ArtSource):
cover_filename = 'File:' + results[0]['coverFilename']['value']
page_id = results[0]['pageId']['value']
else:
self._log.debug('wikipedia: album not found on dbpedia')
self._log.debug(u'wikipedia: album not found on dbpedia')
except (ValueError, KeyError, IndexError):
self._log.debug('wikipedia: error scraping dbpedia response: {}',
self._log.debug(u'wikipedia: error scraping dbpedia response: {}',
dbpedia_response.text)
# Ensure we have a filename before attempting to query wikipedia
@ -293,7 +292,7 @@ class Wikipedia(ArtSource):
if ' .' in cover_filename and \
'.' not in cover_filename.split(' .')[-1]:
self._log.debug(
'wikipedia: dbpedia provided incomplete cover_filename'
u'wikipedia: dbpedia provided incomplete cover_filename'
)
lpart, rpart = cover_filename.rsplit(' .', 1)
@ -322,7 +321,7 @@ class Wikipedia(ArtSource):
break
except (ValueError, KeyError):
self._log.debug(
'wikipedia: failed to retrieve a cover_filename'
u'wikipedia: failed to retrieve a cover_filename'
)
return
@ -347,7 +346,7 @@ class Wikipedia(ArtSource):
image_url = result['imageinfo'][0]['url']
yield image_url
except (ValueError, KeyError, IndexError):
self._log.debug('wikipedia: error scraping imageinfo')
self._log.debug(u'wikipedia: error scraping imageinfo')
return
@ -493,9 +492,11 @@ class FetchArtPlugin(plugins.BeetsPlugin, RequestMixin):
# Manual album art fetching.
def commands(self):
cmd = ui.Subcommand('fetchart', help='download album art')
cmd.parser.add_option('-f', '--force', dest='force',
action='store_true', default=False,
help='re-download art when already present')
cmd.parser.add_option(
u'-f', u'--force', dest='force',
action='store_true', default=False,
help=u're-download art when already present'
)
def func(lib, opts, args):
self.batch_fetch_art(lib, lib.albums(ui.decargs(args)), opts.force)
@ -511,12 +512,12 @@ class FetchArtPlugin(plugins.BeetsPlugin, RequestMixin):
"""
try:
with closing(self.request(url, stream=True,
message='downloading image')) as resp:
message=u'downloading image')) as resp:
if 'Content-Type' not in resp.headers \
or resp.headers['Content-Type'] not in CONTENT_TYPES:
self._log.debug(
'not a supported image: {}',
resp.headers.get('Content-Type') or 'no content type',
u'not a supported image: {}',
resp.headers.get('Content-Type') or u'no content type',
)
return None
@ -532,7 +533,7 @@ class FetchArtPlugin(plugins.BeetsPlugin, RequestMixin):
except (IOError, requests.RequestException, TypeError) as exc:
# Handling TypeError works around a urllib3 bug:
# https://github.com/shazow/urllib3/issues/556
self._log.debug('error fetching art: {}', exc)
self._log.debug(u'error fetching art: {}', exc)
return None
def _is_valid_image_candidate(self, candidate):
@ -551,7 +552,7 @@ class FetchArtPlugin(plugins.BeetsPlugin, RequestMixin):
# get_size returns None if no local imaging backend is available
size = ArtResizer.shared.get_size(candidate)
self._log.debug('image size: {}', size)
self._log.debug(u'image size: {}', size)
if not size:
self._log.warning(u'Could not get size of image (please see '
@ -562,19 +563,19 @@ class FetchArtPlugin(plugins.BeetsPlugin, RequestMixin):
# Check minimum size.
if self.minwidth and size[0] < self.minwidth:
self._log.debug('image too small ({} < {})',
self._log.debug(u'image too small ({} < {})',
size[0], self.minwidth)
return CANDIDATE_BAD
# Check aspect ratio.
if self.enforce_ratio and size[0] != size[1]:
self._log.debug('image is not square ({} != {})',
self._log.debug(u'image is not square ({} != {})',
size[0], size[1])
return CANDIDATE_BAD
# Check maximum size.
if self.maxwidth and size[0] > self.maxwidth:
self._log.debug('image needs resizing ({} > {})',
self._log.debug(u'image needs resizing ({} > {})',
size[0], self.maxwidth)
return CANDIDATE_DOWNSCALE
@ -600,7 +601,7 @@ class FetchArtPlugin(plugins.BeetsPlugin, RequestMixin):
check = self._is_valid_image_candidate(candidate)
if check:
out = candidate
self._log.debug('found local image {}', out)
self._log.debug(u'found local image {}', out)
break
# Web art sources.
@ -613,7 +614,7 @@ class FetchArtPlugin(plugins.BeetsPlugin, RequestMixin):
check = self._is_valid_image_candidate(candidate)
if check:
out = candidate
self._log.debug('using remote image {}', out)
self._log.debug(u'using remote image {}', out)
break
if self.maxwidth and out and check == CANDIDATE_DOWNSCALE:
@ -627,7 +628,7 @@ class FetchArtPlugin(plugins.BeetsPlugin, RequestMixin):
"""
for album in albums:
if album.artpath and not force and os.path.isfile(album.artpath):
message = ui.colorize('text_highlight_minor', 'has album art')
message = ui.colorize('text_highlight_minor', u'has album art')
else:
# In ordinary invocations, look for images on the
# filesystem. When forcing, however, always go to the Web
@ -638,9 +639,9 @@ class FetchArtPlugin(plugins.BeetsPlugin, RequestMixin):
if path:
album.set_art(path, False)
album.store()
message = ui.colorize('text_success', 'found album art')
message = ui.colorize('text_success', u'found album art')
else:
message = ui.colorize('text_error', 'no art found')
message = ui.colorize('text_error', u'no art found')
self._log.info(u'{0}: {1}', album, message)
@ -654,7 +655,7 @@ class FetchArtPlugin(plugins.BeetsPlugin, RequestMixin):
source_names = {v: k for k, v in ART_SOURCES.items()}
for source in self.sources:
self._log.debug(
'trying source {0} for album {1.albumartist} - {1.album}',
u'trying source {0} for album {1.albumartist} - {1.album}',
source_names[type(source)],
album,
)

View file

@ -16,8 +16,7 @@
"""Creates freedesktop.org-compliant .directory files on an album level.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from beets.plugins import BeetsPlugin
from beets import ui
@ -25,13 +24,14 @@ from beets import ui
class FreedesktopPlugin(BeetsPlugin):
def commands(self):
deprecated = ui.Subcommand("freedesktop", help="Print a message to "
"redirect to thumbnails --dolphin")
deprecated = ui.Subcommand(
"freedesktop",
help=u"Print a message to redirect to thumbnails --dolphin")
deprecated.func = self.deprecation_message
return [deprecated]
def deprecation_message(self, lib, opts, args):
ui.print_("This plugin is deprecated. Its functionality is superseded "
"by the 'thumbnails' plugin")
ui.print_("'thumbnails --dolphin' replaces freedesktop. See doc & "
"changelog for more information")
ui.print_(u"This plugin is deprecated. Its functionality is "
u"superseded by the 'thumbnails' plugin")
ui.print_(u"'thumbnails --dolphin' replaces freedesktop. See doc & "
u"changelog for more information")

View file

@ -16,8 +16,7 @@
"""If the title is empty, try to extract track and title from the
filename.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from beets import plugins
from beets.util import displayable_path

View file

@ -15,8 +15,7 @@
"""Moves "featured" artists to the title from the artist field.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import re
@ -87,12 +86,12 @@ class FtInTitlePlugin(plugins.BeetsPlugin):
self._command = ui.Subcommand(
'ftintitle',
help='move featured artists to the title field')
help=u'move featured artists to the title field')
self._command.parser.add_option(
'-d', '--drop', dest='drop',
u'-d', u'--drop', dest='drop',
action='store_true', default=False,
help='drop featuring from artists and ignore title update')
help=u'drop featuring from artists and ignore title update')
if self.config['auto']:
self.import_stages = [self.imported]

View file

@ -16,8 +16,7 @@
"""Provides a fuzzy matching query.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from beets.plugins import BeetsPlugin
from beets.dbcore.query import StringFieldQuery

View file

@ -13,8 +13,7 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
"""Warns you about things you hate (or even blocks import)."""

View file

@ -5,8 +5,7 @@ modification time (mtime) of the item's source file before import.
Reimported albums and items are skipped.
"""
from __future__ import (unicode_literals, absolute_import, print_function,
division)
from __future__ import division, absolute_import, print_function
import os

View file

@ -13,8 +13,7 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
"""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
@ -135,9 +134,9 @@ class ImportFeedsPlugin(BeetsPlugin):
os.symlink(syspath(path), syspath(dest))
if 'echo' in formats:
self._log.info("Location of imported music:")
self._log.info(u"Location of imported music:")
for path in paths:
self._log.info(" {0}", path)
self._log.info(u" {0}", path)
def library_opened(self, lib):
if self.config['dir'].get() is None:

View file

@ -16,8 +16,7 @@
"""Shows file metadata.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import os
import re
@ -141,17 +140,25 @@ def print_data_keys(data, item=None):
class InfoPlugin(BeetsPlugin):
def commands(self):
cmd = ui.Subcommand('info', help='show file metadata')
cmd = ui.Subcommand('info', help=u'show file metadata')
cmd.func = self.run
cmd.parser.add_option('-l', '--library', action='store_true',
help='show library fields instead of tags')
cmd.parser.add_option('-s', '--summarize', action='store_true',
help='summarize the tags of all files')
cmd.parser.add_option('-i', '--include-keys', default=[],
action='append', dest='included_keys',
help='comma separated list of keys to show')
cmd.parser.add_option('-k', '--keys-only', action='store_true',
help='show only the keys')
cmd.parser.add_option(
u'-l', u'--library', action='store_true',
help=u'show library fields instead of tags',
)
cmd.parser.add_option(
u'-s', u'--summarize', action='store_true',
help=u'summarize the tags of all files',
)
cmd.parser.add_option(
u'-i', u'--include-keys', default=[],
action='append', dest='included_keys',
help=u'comma separated list of keys to show',
)
cmd.parser.add_option(
u'-k', u'--keys-only', action='store_true',
help=u'show only the keys',
)
cmd.parser.add_format_option(target='item')
return [cmd]

View file

@ -15,8 +15,7 @@
"""Allows inline path template customization code in the config file.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import traceback
import itertools

View file

@ -16,8 +16,7 @@
"""Uses the `KeyFinder` program to add the `initial_key` field.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import subprocess
@ -41,7 +40,7 @@ class KeyFinderPlugin(BeetsPlugin):
def commands(self):
cmd = ui.Subcommand('keyfinder',
help='detect and add initial key from audio')
help=u'detect and add initial key from audio')
cmd.func = self.command
return [cmd]
@ -63,12 +62,12 @@ class KeyFinderPlugin(BeetsPlugin):
output = util.command_output([bin, b'-f',
util.syspath(item.path)])
except (subprocess.CalledProcessError, OSError) as exc:
self._log.error('execution failed: {0}', exc)
self._log.error(u'execution failed: {0}', exc)
continue
except UnicodeEncodeError:
# Workaround for Python 2 Windows bug.
# http://bugs.python.org/issue1759845
self._log.error('execution failed for Unicode path: {0!r}',
self._log.error(u'execution failed for Unicode path: {0!r}',
item.path)
continue

View file

@ -13,8 +13,7 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
"""Gets genres for imported music based on Last.fm tags.
@ -239,25 +238,30 @@ class LastGenrePlugin(plugins.BeetsPlugin):
def fetch_album_genre(self, obj):
"""Return the album genre for this Item or Album.
"""
return self._last_lookup(u'album', LASTFM.get_album, obj.albumartist,
obj.album)
return self._last_lookup(
u'album', LASTFM.get_album, obj.albumartist, obj.album
)
def fetch_album_artist_genre(self, obj):
"""Return the album artist genre for this Item or Album.
"""
return self._last_lookup(u'artist', LASTFM.get_artist,
obj.albumartist)
return self._last_lookup(
u'artist', LASTFM.get_artist, obj.albumartist
)
def fetch_artist_genre(self, item):
"""Returns the track artist genre for this Item.
"""
return self._last_lookup(u'artist', LASTFM.get_artist, item.artist)
return self._last_lookup(
u'artist', LASTFM.get_artist, item.artist
)
def fetch_track_genre(self, obj):
"""Returns the track genre for this Item.
"""
return self._last_lookup(u'track', LASTFM.get_track, obj.artist,
obj.title)
return self._last_lookup(
u'track', LASTFM.get_track, obj.artist, obj.title
)
def _get_genre(self, obj):
"""Get the genre string for an Album or Item object based on
@ -326,14 +330,15 @@ class LastGenrePlugin(plugins.BeetsPlugin):
return None, None
def commands(self):
lastgenre_cmd = ui.Subcommand('lastgenre', help='fetch genres')
lastgenre_cmd = ui.Subcommand('lastgenre', help=u'fetch genres')
lastgenre_cmd.parser.add_option(
'-f', '--force', dest='force', action='store_true', default=False,
help='re-download genre when already present'
u'-f', u'--force', dest='force',
action='store_true', default=False,
help=u're-download genre when already present'
)
lastgenre_cmd.parser.add_option(
'-s', '--source', dest='source', type='string',
help='genre source: artist, album, or track'
u'-s', u'--source', dest='source', type='string',
help=u'genre source: artist, album, or track'
)
def lastgenre_func(lib, opts, args):
@ -406,8 +411,8 @@ class LastGenrePlugin(plugins.BeetsPlugin):
return []
except Exception as exc:
# Isolate bugs in pylast.
self._log.debug('{}', traceback.format_exc())
self._log.error('error in pylast library: {0}', exc)
self._log.debug(u'{}', traceback.format_exc())
self._log.error(u'error in pylast library: {0}', exc)
return []
# Filter by weight (optionally).

View file

@ -13,8 +13,7 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import pylast
from pylast import TopItem, _extract, _number
@ -44,7 +43,7 @@ class LastImportPlugin(plugins.BeetsPlugin):
}
def commands(self):
cmd = ui.Subcommand('lastimport', help='import last.fm play-count')
cmd = ui.Subcommand('lastimport', help=u'import last.fm play-count')
def func(lib, opts, args):
import_lastfm(lib, self._log)
@ -115,9 +114,9 @@ def import_lastfm(lib, log):
per_page = config['lastimport']['per_page'].get(int)
if not user:
raise ui.UserError('You must specify a user name for lastimport')
raise ui.UserError(u'You must specify a user name for lastimport')
log.info('Fetching last.fm library for @{0}', user)
log.info(u'Fetching last.fm library for @{0}', user)
page_total = 1
page_current = 0
@ -126,7 +125,7 @@ def import_lastfm(lib, log):
retry_limit = config['lastimport']['retry_limit'].get(int)
# Iterate through a yet to be known page total count
while page_current < page_total:
log.info('Querying page #{0}{1}...',
log.info(u'Querying page #{0}{1}...',
page_current + 1,
'/{}'.format(page_total) if page_total > 1 else '')
@ -134,7 +133,7 @@ def import_lastfm(lib, log):
tracks, page_total = fetch_tracks(user, page_current + 1, per_page)
if page_total < 1:
# It means nothing to us!
raise ui.UserError('Last.fm reported no data.')
raise ui.UserError(u'Last.fm reported no data.')
if tracks:
found, unknown = process_tracks(lib, tracks, log)
@ -142,22 +141,22 @@ def import_lastfm(lib, log):
unknown_total += unknown
break
else:
log.error('ERROR: unable to read page #{0}',
log.error(u'ERROR: unable to read page #{0}',
page_current + 1)
if retry < retry_limit:
log.info(
'Retrying page #{0}... ({1}/{2} retry)',
u'Retrying page #{0}... ({1}/{2} retry)',
page_current + 1, retry + 1, retry_limit
)
else:
log.error('FAIL: unable to fetch page #{0}, ',
'tried {1} times', page_current, retry + 1)
log.error(u'FAIL: unable to fetch page #{0}, ',
u'tried {1} times', page_current, retry + 1)
page_current += 1
log.info('... done!')
log.info('finished processing {0} song pages', page_total)
log.info('{0} unknown play-counts', unknown_total)
log.info('{0} play-counts imported', found_total)
log.info(u'... done!')
log.info(u'finished processing {0} song pages', page_total)
log.info(u'{0} unknown play-counts', unknown_total)
log.info(u'{0} play-counts imported', found_total)
def fetch_tracks(user, page, limit):
@ -191,7 +190,7 @@ def process_tracks(lib, tracks, log):
total = len(tracks)
total_found = 0
total_fails = 0
log.info('Received {0} tracks in this page, processing...', total)
log.info(u'Received {0} tracks in this page, processing...', total)
for num in xrange(0, total):
song = None
@ -244,7 +243,7 @@ def process_tracks(lib, tracks, log):
artist, title, album)
if total_fails > 0:
log.info('Acquired {0}/{1} play-counts ({2} unknown)',
log.info(u'Acquired {0}/{1} play-counts ({2} unknown)',
total_found, total, total_fails)
return total_found, total_fails

View file

@ -16,8 +16,7 @@
"""Fetches, embeds, and displays lyrics.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import re
import requests
@ -107,7 +106,7 @@ def extract_text_in(html, starttag):
parts.append(html[pos:match.start()])
break
else:
print('no closing tag found!')
print(u'no closing tag found!')
return
return u''.join(parts)
@ -237,7 +236,7 @@ class Genius(Backend):
url = u'https://api.genius.com/search?q=%s' \
% (urllib.quote(query.encode('utf8')))
self._log.debug('genius: requesting search {}', url)
self._log.debug(u'genius: requesting search {}', url)
try:
req = requests.get(
url,
@ -246,19 +245,19 @@ class Genius(Backend):
)
req.raise_for_status()
except requests.RequestException as exc:
self._log.debug('genius: request error: {}', exc)
self._log.debug(u'genius: request error: {}', exc)
return None
try:
return req.json()
except ValueError:
self._log.debug('genius: invalid response: {}', req.text)
self._log.debug(u'genius: invalid response: {}', req.text)
return None
def get_lyrics(self, link):
url = u'http://genius-api.com/api/lyricsInfo'
self._log.debug('genius: requesting lyrics for link {}', link)
self._log.debug(u'genius: requesting lyrics for link {}', link)
try:
req = requests.post(
url,
@ -268,13 +267,13 @@ class Genius(Backend):
)
req.raise_for_status()
except requests.RequestException as exc:
self._log.debug('genius: request error: {}', exc)
self._log.debug(u'genius: request error: {}', exc)
return None
try:
return req.json()
except ValueError:
self._log.debug('genius: invalid response: {}', req.text)
self._log.debug(u'genius: invalid response: {}', req.text)
return None
def build_lyric_string(self, lyrics):
@ -576,12 +575,16 @@ class LyricsPlugin(plugins.BeetsPlugin):
def commands(self):
cmd = ui.Subcommand('lyrics', help='fetch song lyrics')
cmd.parser.add_option('-p', '--print', dest='printlyr',
action='store_true', default=False,
help='print lyrics to console')
cmd.parser.add_option('-f', '--force', dest='force_refetch',
action='store_true', default=False,
help='always re-download lyrics')
cmd.parser.add_option(
u'-p', u'--print', dest='printlyr',
action='store_true', default=False,
help=u'print lyrics to console',
)
cmd.parser.add_option(
u'-f', u'--force', dest='force_refetch',
action='store_true', default=False,
help=u'always re-download lyrics',
)
def func(lib, opts, args):
# The "write to files" option corresponds to the

View file

@ -13,8 +13,7 @@
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from beets.plugins import BeetsPlugin
from beets.ui import Subcommand
@ -34,11 +33,11 @@ def mb_call(func, *args, **kwargs):
try:
return func(*args, **kwargs)
except musicbrainzngs.AuthenticationError:
raise ui.UserError('authentication with MusicBrainz failed')
raise ui.UserError(u'authentication with MusicBrainz failed')
except (musicbrainzngs.ResponseError, musicbrainzngs.NetworkError) as exc:
raise ui.UserError('MusicBrainz API error: {0}'.format(exc))
raise ui.UserError(u'MusicBrainz API error: {0}'.format(exc))
except musicbrainzngs.UsageError:
raise ui.UserError('MusicBrainz credentials missing')
raise ui.UserError(u'MusicBrainz credentials missing')
def submit_albums(collection_id, release_ids):
@ -65,7 +64,8 @@ class MusicBrainzCollectionPlugin(BeetsPlugin):
self.import_stages = [self.imported]
def commands(self):
mbupdate = Subcommand('mbupdate', help='Update MusicBrainz collection')
mbupdate = Subcommand('mbupdate',
help=u'Update MusicBrainz collection')
mbupdate.func = self.update_collection
return [mbupdate]
@ -84,7 +84,7 @@ class MusicBrainzCollectionPlugin(BeetsPlugin):
# Get the available collections.
collections = mb_call(musicbrainzngs.get_collections)
if not collections['collection-list']:
raise ui.UserError('no collections exist for user')
raise ui.UserError(u'no collections exist for user')
# Get the first release collection. MusicBrainz also has event
# collections, so we need to avoid adding to those.
@ -93,7 +93,7 @@ class MusicBrainzCollectionPlugin(BeetsPlugin):
collection_id = collection['id']
break
else:
raise ui.UserError('No collection found.')
raise ui.UserError(u'No collection found.')
# Get a list of all the album IDs.
album_ids = []
@ -106,6 +106,8 @@ class MusicBrainzCollectionPlugin(BeetsPlugin):
self._log.info(u'skipping invalid MBID: {0}', aid)
# Submit to MusicBrainz.
self._log.info('Updating MusicBrainz collection {0}...', collection_id)
self._log.info(
u'Updating MusicBrainz collection {0}...', collection_id
)
submit_albums(collection_id, album_ids)
self._log.info('...MusicBrainz collection updated.')
self._log.info(u'...MusicBrainz collection updated.')

View file

@ -22,8 +22,7 @@ implemented by MusicBrainz yet.
[1] http://wiki.musicbrainz.org/History:How_To_Parse_Track_Listings
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from beets.autotag import Recommendation
@ -54,7 +53,7 @@ class MBSubmitPlugin(BeetsPlugin):
def before_choose_candidate_event(self, session, task):
if task.rec <= self.threshold:
return [PromptChoice('p', 'Print tracks', self.print_tracks)]
return [PromptChoice(u'p', u'Print tracks', self.print_tracks)]
def print_tracks(self, session, task):
for i in task.items:

View file

@ -15,8 +15,7 @@
"""Update library's tags using MusicBrainz.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from beets.plugins import BeetsPlugin
from beets import autotag, library, ui, util
@ -43,18 +42,20 @@ class MBSyncPlugin(BeetsPlugin):
def commands(self):
cmd = ui.Subcommand('mbsync',
help='update metadata from musicbrainz')
cmd.parser.add_option('-p', '--pretend', action='store_true',
help='show all changes but do nothing')
cmd.parser.add_option('-m', '--move', action='store_true',
dest='move',
help="move files in the library directory")
cmd.parser.add_option('-M', '--nomove', action='store_false',
dest='move',
help="don't move files in library")
cmd.parser.add_option('-W', '--nowrite', action='store_false',
default=None, dest='write',
help="don't write updated metadata to files")
help=u'update metadata from musicbrainz')
cmd.parser.add_option(
u'-p', u'--pretend', action='store_true',
help=u'show all changes but do nothing')
cmd.parser.add_option(
u'-m', u'--move', action='store_true', dest='move',
help=u"move files in the library directory")
cmd.parser.add_option(
u'-M', u'--nomove', action='store_false', dest='move',
help=u"don't move files in library")
cmd.parser.add_option(
u'-W', u'--nowrite', action='store_false',
default=None, dest='write',
help=u"don't write updated metadata to files")
cmd.parser.add_format_option()
cmd.func = self.func
return [cmd]
@ -140,7 +141,7 @@ class MBSyncPlugin(BeetsPlugin):
break
# Apply.
self._log.debug('applying changes to {}', album_formatted)
self._log.debug(u'applying changes to {}', album_formatted)
with lib.transaction():
autotag.apply_metadata(album_info, mapping)
changed = False

View file

@ -15,8 +15,7 @@
"""List missing tracks.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from beets.autotag import hooks
from beets.library import Item
@ -95,12 +94,12 @@ class MissingPlugin(BeetsPlugin):
self._command = Subcommand('missing',
help=__doc__,
aliases=['miss'])
self._command.parser.add_option('-c', '--count', dest='count',
action='store_true',
help='count missing tracks per album')
self._command.parser.add_option('-t', '--total', dest='total',
action='store_true',
help='count total of missing tracks')
self._command.parser.add_option(
u'-c', u'--count', dest='count', action='store_true',
help=u'count missing tracks per album')
self._command.parser.add_option(
u'-t', u'--total', dest='total', action='store_true',
help=u'count total of missing tracks')
self._command.parser.add_format_option()
def commands(self):

View file

@ -13,8 +13,7 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import mpd
import socket
@ -80,7 +79,7 @@ class MPDClientWrapper(object):
try:
self.client.connect(host, port)
except socket.error as e:
raise ui.UserError('could not connect to MPD: {0}'.format(e))
raise ui.UserError(u'could not connect to MPD: {0}'.format(e))
password = mpd_config['password'].get(unicode)
if password:
@ -88,7 +87,7 @@ class MPDClientWrapper(object):
self.client.password(password)
except mpd.CommandError as e:
raise ui.UserError(
'could not authenticate to MPD: {0}'.format(e)
u'could not authenticate to MPD: {0}'.format(e)
)
def disconnect(self):
@ -338,16 +337,16 @@ class MPDStatsPlugin(plugins.BeetsPlugin):
def commands(self):
cmd = ui.Subcommand(
'mpdstats',
help='run a MPD client to gather play statistics')
help=u'run a MPD client to gather play statistics')
cmd.parser.add_option(
'--host', dest='host', type='string',
help='set the hostname of the server to connect to')
u'--host', dest='host', type='string',
help=u'set the hostname of the server to connect to')
cmd.parser.add_option(
'--port', dest='port', type='int',
help='set the port of the MPD server to connect to')
u'--port', dest='port', type='int',
help=u'set the port of the MPD server to connect to')
cmd.parser.add_option(
'--password', dest='password', type='string',
help='set the password of the MPD server to connect to')
u'--password', dest='password', type='string',
help=u'set the password of the MPD server to connect to')
def func(lib, opts, args):
mpd_config.set_args(opts)

View file

@ -21,8 +21,7 @@ Put something like the following in your config.yaml to configure:
port: 6600
password: seekrit
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from beets.plugins import BeetsPlugin
import os
@ -126,4 +125,4 @@ class MPDUpdatePlugin(BeetsPlugin):
s.send('close\n')
s.close()
self._log.info('Database updated.')
self._log.info(u'Database updated.')

View file

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
"""Fixes file permissions after the file gets written on import. Put something
like the following in your config.yaml to configure:
@ -82,7 +81,7 @@ def permissions(lib, item=None, album=None):
# Checks if the destination path has the permissions configured.
if not check_permissions(util.bytestring_path(path), file_perm):
message = 'There was a problem setting permission on {}'.format(
message = u'There was a problem setting permission on {}'.format(
path)
print(message)
@ -98,6 +97,6 @@ def permissions(lib, item=None, album=None):
# Checks if the destination path has the permissions configured.
if not check_permissions(util.bytestring_path(path), dir_perm):
message = 'There was a problem setting permission on {}'.format(
message = u'There was a problem setting permission on {}'.format(
path)
print(message)

View file

@ -15,8 +15,7 @@
"""Send the results of a query to the configured music player as a playlist.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from beets.plugins import BeetsPlugin
from beets.ui import Subcommand
@ -49,13 +48,13 @@ class PlayPlugin(BeetsPlugin):
def commands(self):
play_command = Subcommand(
'play',
help='send music to a player as a playlist'
help=u'send music to a player as a playlist'
)
play_command.parser.add_album_option()
play_command.parser.add_option(
'-A', '--args',
u'-A', u'--args',
action='store',
help='add additional arguments to the command',
help=u'add additional arguments to the command',
)
play_command.func = self.play_music
return [play_command]
@ -90,7 +89,7 @@ class PlayPlugin(BeetsPlugin):
if ARGS_MARKER in command_str:
command_str = command_str.replace(ARGS_MARKER, opts.args)
else:
command_str = "{} {}".format(command_str, opts.args)
command_str = u"{} {}".format(command_str, opts.args)
# Perform search by album and add folders rather than tracks to
# playlist.
@ -119,16 +118,15 @@ class PlayPlugin(BeetsPlugin):
if not selection:
ui.print_(ui.colorize('text_warning',
'No {0} to play.'.format(item_type)))
u'No {0} to play.'.format(item_type)))
return
# Warn user before playing any huge playlists.
if warning_threshold and len(selection) > warning_threshold:
ui.print_(ui.colorize(
'text_warning',
'You are about to queue {0} {1}.'.format(len(selection),
item_type)
))
u'You are about to queue {0} {1}.'.format(
len(selection), item_type)))
if ui.input_options(('Continue', 'Abort')) == 'a':
return
@ -139,13 +137,13 @@ class PlayPlugin(BeetsPlugin):
else:
open_args = [self._create_tmp_playlist(paths)]
self._log.debug('executing command: {} {}', command_str,
self._log.debug(u'executing command: {} {}', command_str,
b' '.join(open_args))
try:
util.interactive_open(open_args, command_str)
except OSError as exc:
raise ui.UserError("Could not play the query: "
"{0}".format(exc))
raise ui.UserError(
"Could not play the query: {0}".format(exc))
def _create_tmp_playlist(self, paths_list):
"""Create a temporary .m3u file. Return the filename.

View file

@ -9,8 +9,7 @@ Put something like the following in your config.yaml to configure:
port: 32400
token: token
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import requests
from urlparse import urljoin
@ -78,7 +77,7 @@ class PlexUpdate(BeetsPlugin):
def update(self, lib):
"""When the client exists try to send refresh request to Plex server.
"""
self._log.info('Updating Plex library...')
self._log.info(u'Updating Plex library...')
# Try to send update request.
try:
@ -87,7 +86,7 @@ class PlexUpdate(BeetsPlugin):
config['plex']['port'].get(),
config['plex']['token'].get(),
config['plex']['library_name'].get())
self._log.info('... started.')
self._log.info(u'... started.')
except requests.exceptions.RequestException:
self._log.warning('Update failed.')
self._log.warning(u'Update failed.')

View file

@ -15,8 +15,7 @@
"""Get a random song or album from the library.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from beets.plugins import BeetsPlugin
from beets.ui import Subcommand, decargs, print_
@ -66,11 +65,13 @@ def random_item(lib, opts, args):
print_(format(item))
random_cmd = Subcommand('random',
help='chose a random track or album')
random_cmd.parser.add_option('-n', '--number', action='store', type="int",
help='number of objects to choose', default=1)
random_cmd.parser.add_option('-e', '--equal-chance', action='store_true',
help='each artist has the same chance')
help=u'chose a random track or album')
random_cmd.parser.add_option(
u'-n', u'--number', action='store', type="int",
help=u'number of objects to choose', default=1)
random_cmd.parser.add_option(
u'-e', u'--equal-chance', action='store_true',
help=u'each artist has the same chance')
random_cmd.parser.add_all_common_options()
random_cmd.func = random_item

View file

@ -13,8 +13,7 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import subprocess
import os
@ -56,13 +55,13 @@ def call(args):
return command_output(args)
except subprocess.CalledProcessError as e:
raise ReplayGainError(
"{0} exited with status {1}".format(args[0], e.returncode)
u"{0} exited with status {1}".format(args[0], e.returncode)
)
except UnicodeEncodeError:
# Due to a bug in Python 2's subprocess on Windows, Unicode
# filenames can fail to encode on that platform. See:
# http://code.google.com/p/beets/issues/detail?id=499
raise ReplayGainError("argument encoding failed")
raise ReplayGainError(u"argument encoding failed")
# Backend base and plumbing classes.
@ -111,11 +110,11 @@ class Bs1770gainBackend(Backend):
self.command = cmd
except OSError:
raise FatalReplayGainError(
'Is bs1770gain installed? Is your method in config correct?'
u'Is bs1770gain installed? Is your method in config correct?'
)
if not self.command:
raise FatalReplayGainError(
'no replaygain command found: install bs1770gain'
u'no replaygain command found: install bs1770gain'
)
def compute_track_gain(self, items):
@ -137,7 +136,7 @@ class Bs1770gainBackend(Backend):
output = self.compute_gain(supported_items, True)
if not output:
raise ReplayGainError('no output from bs1770gain')
raise ReplayGainError(u'no output from bs1770gain')
return AlbumGain(output[-1], output[:-1])
def isplitter(self, items, chunk_at):
@ -204,7 +203,9 @@ class Bs1770gainBackend(Backend):
args = cmd + [syspath(i.path, prefix=False) for i in items]
# Invoke the command.
self._log.debug("executing {0}", " ".join(map(displayable_path, args)))
self._log.debug(
u'executing {0}', u' '.join(map(displayable_path, args))
)
output = call(args)
self._log.debug(u'analysis finished: {0}', output)
@ -228,8 +229,8 @@ class Bs1770gainBackend(Backend):
for parts in results[0:num_lines]:
part = parts.split(b'\n')
if len(part) == 0:
self._log.debug('bad tool output: {0!r}', text)
raise ReplayGainError('bs1770gain failed')
self._log.debug(u'bad tool output: {0!r}', text)
raise ReplayGainError(u'bs1770gain failed')
try:
song = {
@ -238,7 +239,7 @@ class Bs1770gainBackend(Backend):
'peak': float(part[2].split('/')[1]),
}
except IndexError:
self._log.info('bs1770gain reports (faulty file?): {}', parts)
self._log.info(u'bs1770gain reports (faulty file?): {}', parts)
continue
out.append(Gain(song['gain'], song['peak']))
@ -261,9 +262,8 @@ class CommandBackend(Backend):
# Explicit executable path.
if not os.path.isfile(self.command):
raise FatalReplayGainError(
'replaygain command does not exist: {0}'.format(
self.command
)
u'replaygain command does not exist: {0}'.format(
self.command)
)
else:
# Check whether the program is in $PATH.
@ -275,7 +275,7 @@ class CommandBackend(Backend):
pass
if not self.command:
raise FatalReplayGainError(
'no replaygain command found: install mp3gain or aacgain'
u'no replaygain command found: install mp3gain or aacgain'
)
self.noclip = config['noclip'].get(bool)
@ -322,7 +322,7 @@ class CommandBackend(Backend):
the album gain
"""
if len(items) == 0:
self._log.debug('no supported tracks to analyze')
self._log.debug(u'no supported tracks to analyze')
return []
"""Compute ReplayGain values and return a list of results
@ -361,7 +361,7 @@ class CommandBackend(Backend):
parts = line.split(b'\t')
if len(parts) != 6 or parts[0] == b'File':
self._log.debug(u'bad tool output: {0}', text)
raise ReplayGainError('mp3gain failed')
raise ReplayGainError(u'mp3gain failed')
d = {
'file': parts[0],
'mp3gain': int(parts[1]),
@ -397,7 +397,7 @@ class GStreamerBackend(Backend):
if self._src is None or self._decbin is None or self._conv is None \
or self._res is None or self._rg is None:
raise FatalGstreamerPluginReplayGainError(
"Failed to load required GStreamer plugins"
u"Failed to load required GStreamer plugins"
)
# We check which files need gain ourselves, so all files given
@ -444,14 +444,14 @@ class GStreamerBackend(Backend):
import gi
except ImportError:
raise FatalReplayGainError(
"Failed to load GStreamer: python-gi not found"
u"Failed to load GStreamer: python-gi not found"
)
try:
gi.require_version('Gst', '1.0')
except ValueError as e:
raise FatalReplayGainError(
"Failed to load GStreamer 1.0: {0}".format(e)
u"Failed to load GStreamer 1.0: {0}".format(e)
)
from gi.repository import GObject, Gst, GLib
@ -486,7 +486,7 @@ class GStreamerBackend(Backend):
def compute_track_gain(self, items):
self.compute(items, False)
if len(self._file_tags) != len(items):
raise ReplayGainError("Some tracks did not receive tags")
raise ReplayGainError(u"Some tracks did not receive tags")
ret = []
for item in items:
@ -499,7 +499,7 @@ class GStreamerBackend(Backend):
items = list(album.items())
self.compute(items, True)
if len(self._file_tags) != len(items):
raise ReplayGainError("Some items in album did not receive tags")
raise ReplayGainError(u"Some items in album did not receive tags")
# Collect track gains.
track_gains = []
@ -508,7 +508,7 @@ class GStreamerBackend(Backend):
gain = self._file_tags[item]["TRACK_GAIN"]
peak = self._file_tags[item]["TRACK_PEAK"]
except KeyError:
raise ReplayGainError("results missing for track")
raise ReplayGainError(u"results missing for track")
track_gains.append(Gain(gain, peak))
# Get album gain information from the last track.
@ -517,7 +517,7 @@ class GStreamerBackend(Backend):
gain = last_tags["ALBUM_GAIN"]
peak = last_tags["ALBUM_PEAK"]
except KeyError:
raise ReplayGainError("results missing for album")
raise ReplayGainError(u"results missing for album")
return AlbumGain(Gain(gain, peak), track_gains)
@ -539,7 +539,7 @@ class GStreamerBackend(Backend):
f = self._src.get_property("location")
# A GStreamer error, either an unsupported format or a bug.
self._error = ReplayGainError(
"Error {0!r} - {1!r} on file {2!r}".format(err, debug, f)
u"Error {0!r} - {1!r} on file {2!r}".format(err, debug, f)
)
def _on_tag(self, bus, message):
@ -663,7 +663,7 @@ class AudioToolsBackend(Backend):
import audiotools.replaygain
except ImportError:
raise FatalReplayGainError(
"Failed to load audiotools: audiotools not found"
u"Failed to load audiotools: audiotools not found"
)
self._mod_audiotools = audiotools
self._mod_replaygain = audiotools.replaygain
@ -681,11 +681,11 @@ class AudioToolsBackend(Backend):
audiofile = self._mod_audiotools.open(item.path)
except IOError:
raise ReplayGainError(
"File {} was not found".format(item.path)
u"File {} was not found".format(item.path)
)
except self._mod_audiotools.UnsupportedFile:
raise ReplayGainError(
"Unsupported file type {}".format(item.format)
u"Unsupported file type {}".format(item.format)
)
return audiofile
@ -704,8 +704,7 @@ class AudioToolsBackend(Backend):
rg = self._mod_replaygain.ReplayGain(audiofile.sample_rate())
except ValueError:
raise ReplayGainError(
"Unsupported sample rate {}".format(item.samplerate)
)
u"Unsupported sample rate {}".format(item.samplerate))
return
return rg
@ -730,8 +729,8 @@ class AudioToolsBackend(Backend):
except ValueError as exc:
# `audiotools.replaygain` can raise a `ValueError` if the sample
# rate is incorrect.
self._log.debug('error in rg.title_gain() call: {}', exc)
raise ReplayGainError('audiotools audio data error')
self._log.debug(u'error in rg.title_gain() call: {}', exc)
raise ReplayGainError(u'audiotools audio data error')
def _compute_track_gain(self, item):
"""Compute ReplayGain value for the requested item.
@ -830,8 +829,7 @@ class ReplayGainPlugin(BeetsPlugin):
)
except (ReplayGainError, FatalReplayGainError) as e:
raise ui.UserError(
'replaygain initialization failed: {0}'.format(e)
)
u'replaygain initialization failed: {0}'.format(e))
def track_requires_gain(self, item):
return self.overwrite or \
@ -894,8 +892,7 @@ class ReplayGainPlugin(BeetsPlugin):
self._log.info(u"ReplayGain error: {0}", e)
except FatalReplayGainError as e:
raise ui.UserError(
u"Fatal replay gain error: {0}".format(e)
)
u"Fatal replay gain error: {0}".format(e))
def handle_track(self, item, write):
"""Compute track replay gain and store it in the item.
@ -924,8 +921,7 @@ class ReplayGainPlugin(BeetsPlugin):
self._log.info(u"ReplayGain error: {0}", e)
except FatalReplayGainError as e:
raise ui.UserError(
u"Fatal replay gain error: {0}".format(e)
)
u"Fatal replay gain error: {0}".format(e))
def imported(self, session, task):
"""Add replay gain info to items or albums of ``task``.
@ -951,7 +947,7 @@ class ReplayGainPlugin(BeetsPlugin):
for item in lib.items(ui.decargs(args)):
self.handle_track(item, write)
cmd = ui.Subcommand('replaygain', help='analyze for ReplayGain')
cmd = ui.Subcommand('replaygain', help=u'analyze for ReplayGain')
cmd.parser.add_album_option()
cmd.func = func
return [cmd]

View file

@ -16,8 +16,7 @@
"""Uses user-specified rewriting rules to canonicalize names for path
formats.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import re
from collections import defaultdict
@ -56,9 +55,9 @@ class RewritePlugin(BeetsPlugin):
try:
fieldname, pattern = key.split(None, 1)
except ValueError:
raise ui.UserError("invalid rewrite specification")
raise ui.UserError(u"invalid rewrite specification")
if fieldname not in library.Item._fields:
raise ui.UserError("invalid field name (%s) in rewriter" %
raise ui.UserError(u"invalid field name (%s) in rewriter" %
fieldname)
self._log.debug(u'adding template field {0}', key)
pattern = re.compile(pattern.lower())

View file

@ -17,8 +17,7 @@
automatically whenever tags are written.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from beets.plugins import BeetsPlugin
from beets import ui
@ -64,10 +63,11 @@ class ScrubPlugin(BeetsPlugin):
util.displayable_path(item.path))
self._scrub_item(item, opts.write)
scrub_cmd = ui.Subcommand('scrub', help='clean audio tags')
scrub_cmd.parser.add_option('-W', '--nowrite', dest='write',
action='store_false', default=True,
help='leave tags empty')
scrub_cmd = ui.Subcommand('scrub', help=u'clean audio tags')
scrub_cmd.parser.add_option(
u'-W', u'--nowrite', dest='write',
action='store_false', default=True,
help=u'leave tags empty')
scrub_cmd.func = scrub_func
return [scrub_cmd]

View file

@ -16,8 +16,7 @@
"""Generates smart playlists based on beets queries.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from beets.plugins import BeetsPlugin
from beets import ui
@ -46,9 +45,11 @@ class SmartPlaylistPlugin(BeetsPlugin):
self.register_listener('database_change', self.db_change)
def commands(self):
spl_update = ui.Subcommand('splupdate',
help='update the smart playlists. Playlist '
'names may be passed as arguments.')
spl_update = ui.Subcommand(
'splupdate',
help=u'update the smart playlists. Playlist names may be '
u'passed as arguments.'
)
spl_update.func = self.update_cmd
return [spl_update]
@ -64,9 +65,10 @@ class SmartPlaylistPlugin(BeetsPlugin):
for name, q, a_q in self._unmatched_playlists
if name in args)
if not playlists:
raise ui.UserError('No playlist matching any of {0} '
'found'.format([name for name, _, _ in
self._unmatched_playlists]))
raise ui.UserError(
u'No playlist matching any of {0} found'.format(
[name for name, _, _ in self._unmatched_playlists])
)
self._matched_playlists = playlists
self._unmatched_playlists -= playlists
@ -95,7 +97,7 @@ class SmartPlaylistPlugin(BeetsPlugin):
for playlist in self.config['playlists'].get(list):
if 'name' not in playlist:
self._log.warn("playlist configuration is missing name")
self._log.warn(u"playlist configuration is missing name")
continue
playlist_data = (playlist['name'],)
@ -131,7 +133,7 @@ class SmartPlaylistPlugin(BeetsPlugin):
playlist_data += (query_and_sort,)
except ParsingError as exc:
self._log.warn("invalid query in playlist {}: {}",
self._log.warn(u"invalid query in playlist {}: {}",
playlist['name'], exc)
continue
@ -151,14 +153,15 @@ class SmartPlaylistPlugin(BeetsPlugin):
for playlist in self._unmatched_playlists:
n, (q, _), (a_q, _) = playlist
if self.matches(model, q, a_q):
self._log.debug("{0} will be updated because of {1}", n, model)
self._log.debug(
u"{0} will be updated because of {1}", n, model)
self._matched_playlists.add(playlist)
self.register_listener('cli_exit', self.update_playlists)
self._unmatched_playlists -= self._matched_playlists
def update_playlists(self, lib):
self._log.info("Updating {0} smart playlists...",
self._log.info(u"Updating {0} smart playlists...",
len(self._matched_playlists))
playlist_dir = self.config['playlist_dir'].as_filename()
@ -196,4 +199,4 @@ class SmartPlaylistPlugin(BeetsPlugin):
with open(syspath(m3u_path), 'w') as f:
for path in m3us[m3u]:
f.write(path + b'\n')
self._log.info("{0} playlists updated", len(self._matched_playlists))
self._log.info(u"{0} playlists updated", len(self._matched_playlists))

View file

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import re
import webbrowser
@ -41,17 +40,17 @@ class SpotifyPlugin(BeetsPlugin):
self.output_results(results)
spotify_cmd = ui.Subcommand(
'spotify',
help='build a Spotify playlist'
help=u'build a Spotify playlist'
)
spotify_cmd.parser.add_option(
'-m', '--mode', action='store',
help='"open" to open Spotify with playlist, '
'"list" to print (default)'
u'-m', u'--mode', action='store',
help=u'"open" to open Spotify with playlist, '
u'"list" to print (default)'
)
spotify_cmd.parser.add_option(
'-f', '--show-failures', action='store_true',
help='list tracks that did not match a Spotify ID',
dest='show_failures',
u'-f', u'--show-failures',
action='store_true', dest='show_failures',
help=u'list tracks that did not match a Spotify ID'
)
spotify_cmd.func = queries
return [spotify_cmd]

View file

@ -15,8 +15,7 @@
"""Moves patterns in path formats (suitable for moving articles)."""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import re
from beets.plugins import BeetsPlugin

View file

@ -19,8 +19,7 @@ This plugin is POSIX-only.
Spec: standards.freedesktop.org/thumbnail-spec/latest/index.html
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from hashlib import md5
import os
@ -58,14 +57,15 @@ class ThumbnailsPlugin(BeetsPlugin):
def commands(self):
thumbnails_command = Subcommand("thumbnails",
help="Create album thumbnails")
help=u"Create album thumbnails")
thumbnails_command.parser.add_option(
'-f', '--force', dest='force', action='store_true', default=False,
help='force regeneration of thumbnails deemed fine (existing & '
'recent enough)')
u'-f', u'--force',
dest='force', action='store_true', default=False,
help=u'force regeneration of thumbnails deemed fine (existing & '
u'recent enough)')
thumbnails_command.parser.add_option(
'--dolphin', dest='dolphin', action='store_true', default=False,
help="create Dolphin-compatible thumbnail information (for KDE)")
u'--dolphin', dest='dolphin', action='store_true', default=False,
help=u"create Dolphin-compatible thumbnail information (for KDE)")
thumbnails_command.func = self.process_query
return [thumbnails_command]
@ -84,8 +84,8 @@ class ThumbnailsPlugin(BeetsPlugin):
- detect whether we'll use GIO or Python to get URIs
"""
if not ArtResizer.shared.local:
self._log.warning("No local image resizing capabilities, "
"cannot generate thumbnails")
self._log.warning(u"No local image resizing capabilities, "
u"cannot generate thumbnails")
return False
for dir in (NORMAL_DIR, LARGE_DIR):
@ -99,12 +99,12 @@ class ThumbnailsPlugin(BeetsPlugin):
assert has_PIL() # since we're local
self.write_metadata = write_metadata_pil
tool = "PIL"
self._log.debug("using {0} to write metadata", tool)
self._log.debug(u"using {0} to write metadata", tool)
uri_getter = GioURI()
if not uri_getter.available:
uri_getter = PathlibURI()
self._log.debug("using {0.name} to compute URIs", uri_getter)
self._log.debug(u"using {0.name} to compute URIs", uri_getter)
self.get_uri = uri_getter.uri
return True
@ -122,7 +122,7 @@ class ThumbnailsPlugin(BeetsPlugin):
size = ArtResizer.shared.get_size(album.artpath)
if not size:
self._log.warning('problem getting the picture size for {0}',
self._log.warning(u'problem getting the picture size for {0}',
album.artpath)
return
@ -132,9 +132,9 @@ class ThumbnailsPlugin(BeetsPlugin):
wrote &= self.make_cover_thumbnail(album, 128, NORMAL_DIR)
if wrote:
self._log.info('wrote thumbnail for {0}', album)
self._log.info(u'wrote thumbnail for {0}', album)
else:
self._log.info('nothing to do for {0}', album)
self._log.info(u'nothing to do for {0}', album)
def make_cover_thumbnail(self, album, size, target_dir):
"""Make a thumbnail of given size for `album` and put it in
@ -145,11 +145,11 @@ class ThumbnailsPlugin(BeetsPlugin):
if os.path.exists(target) and \
os.stat(target).st_mtime > os.stat(album.artpath).st_mtime:
if self.config['force']:
self._log.debug("found a suitable {1}x{1} thumbnail for {0}, "
"forcing regeneration", album, size)
self._log.debug(u"found a suitable {1}x{1} thumbnail for {0}, "
u"forcing regeneration", album, size)
else:
self._log.debug("{1}x{1} thumbnail for {0} exists and is "
"recent enough", album, size)
self._log.debug(u"{1}x{1} thumbnail for {0} exists and is "
u"recent enough", album, size)
return False
resized = ArtResizer.shared.resize(size, album.artpath,
util.syspath(target))
@ -174,7 +174,7 @@ class ThumbnailsPlugin(BeetsPlugin):
try:
self.write_metadata(image_path, metadata)
except Exception:
self._log.exception("could not write metadata to {0}",
self._log.exception(u"could not write metadata to {0}",
util.displayable_path(image_path))
def make_dolphin_cover_thumbnail(self, album):
@ -185,7 +185,7 @@ class ThumbnailsPlugin(BeetsPlugin):
with open(outfilename, 'w') as f:
f.write(b"[Desktop Entry]\nIcon=./{0}".format(artfile))
f.close()
self._log.debug("Wrote file {0}", util.displayable_path(outfilename))
self._log.debug(u"Wrote file {0}", util.displayable_path(outfilename))
def write_metadata_im(file, metadata):
@ -266,7 +266,7 @@ class GioURI(URIGetter):
def uri(self, path):
g_file_ptr = self.libgio.g_file_new_for_path(path)
if not g_file_ptr:
raise RuntimeError("No gfile pointer received for {0}".format(
raise RuntimeError(u"No gfile pointer received for {0}".format(
util.displayable_path(path)))
try:
@ -277,8 +277,8 @@ class GioURI(URIGetter):
self.libgio.g_object_unref(g_file_ptr)
if not uri_ptr:
self.libgio.g_free(uri_ptr)
raise RuntimeError("No URI received from the gfile pointer for "
"{0}".format(util.displayable_path(path)))
raise RuntimeError(u"No URI received from the gfile pointer for "
u"{0}".format(util.displayable_path(path)))
try:
uri = copy_c_string(uri_ptr)

View file

@ -13,8 +13,7 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from beets.plugins import BeetsPlugin
from beets.dbcore import types

View file

@ -14,8 +14,7 @@
# included in all copies or substantial portions of the Software.
"""A Web interface to beets."""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from beets.plugins import BeetsPlugin
from beets import ui
@ -264,9 +263,9 @@ class WebPlugin(BeetsPlugin):
})
def commands(self):
cmd = ui.Subcommand('web', help='start a Web interface')
cmd.parser.add_option('-d', '--debug', action='store_true',
default=False, help='debug mode')
cmd = ui.Subcommand('web', help=u'start a Web interface')
cmd.parser.add_option(u'-d', u'--debug', action='store_true',
default=False, help=u'debug mode')
def func(lib, opts, args):
args = ui.decargs(args)
@ -278,7 +277,7 @@ class WebPlugin(BeetsPlugin):
app.config['lib'] = lib
# Enable CORS if required.
if self.config['cors']:
self._log.info('Enabling CORS with origin: {0}',
self._log.info(u'Enabling CORS with origin: {0}',
self.config['cors'])
from flask.ext.cors import CORS
app.config['CORS_ALLOW_HEADERS'] = "Content-Type"

View file

@ -15,8 +15,7 @@
""" Clears tag fields in media files."""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import re
from beets.plugins import BeetsPlugin

View file

@ -14,8 +14,7 @@
# included in all copies or substantial portions of the Software.
"""Some common functionality for beets' test cases."""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import time
import sys
@ -102,11 +101,11 @@ def album(lib=None):
_item_ident += 1
i = beets.library.Album(
artpath=None,
albumartist='some album artist',
albumartist_sort='some sort album artist',
albumartist_credit='some album artist credit',
album='the album',
genre='the genre',
albumartist=u'some album artist',
albumartist_sort=u'some sort album artist',
albumartist_credit=u'some album artist credit',
album=u'the album',
genre=u'the genre',
year=2014,
month=2,
day=5,
@ -170,11 +169,11 @@ class TestCase(unittest.TestCase):
def assertExists(self, path):
self.assertTrue(os.path.exists(path),
'file does not exist: {!r}'.format(path))
u'file does not exist: {!r}'.format(path))
def assertNotExists(self, path):
self.assertFalse(os.path.exists(path),
'file exists: {!r}'.format((path)))
u'file exists: {!r}'.format((path)))
class LibTestCase(TestCase):
@ -228,7 +227,7 @@ class InputException(Exception):
def __str__(self):
msg = "Attempt to read with no input provided."
if self.output is not None:
msg += " Output: %s" % self.output
msg += " Output: {!r}".format(self.output)
return msg
@ -352,5 +351,5 @@ def slow_test(unused=None):
def _id(obj):
return obj
if 'SKIP_SLOW_TESTS' in os.environ:
return unittest.skip('test is slow')
return unittest.skip(u'test is slow')
return _id

View file

@ -31,8 +31,7 @@ information or mock the environment.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import sys
import os
@ -244,7 +243,7 @@ class TestHelper(object):
track_no = 0
album_item_count = item_count
while album_item_count:
title = 'track {0}'.format(track_no)
title = u'track {0}'.format(track_no)
src = os.path.join(_common.RSRC, 'full.mp3')
dest = os.path.join(album_dir, '{0}.mp3'.format(title))
if os.path.exists(dest):
@ -527,14 +526,14 @@ def generate_album_info(album_id, track_ids):
"""
tracks = [generate_track_info(id) for id in track_ids]
album = AlbumInfo(
album_id='album info',
album='album info',
artist='album info',
artist_id='album info',
album_id=u'album info',
album=u'album info',
artist=u'album info',
artist_id=u'album info',
tracks=tracks,
)
for field in ALBUM_INFO_FIELDS:
setattr(album, field, 'album info')
setattr(album, field, u'album info')
return album
@ -553,11 +552,11 @@ def generate_track_info(track_id='track info', values={}):
string fields are set to "track info".
"""
track = TrackInfo(
title='track info',
title=u'track info',
track_id=track_id,
)
for field in TRACK_INFO_FIELDS:
setattr(track, field, 'track info')
setattr(track, field, u'track info')
for field, value in values.items():
setattr(track, field, value)
return track

View file

@ -13,8 +13,7 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import os
import sys
@ -45,7 +44,7 @@ def main(argv=None):
"""
if argv is None:
argv = sys.argv
print('Fetching samples from:')
print(u'Fetching samples from:')
for s in test_lyrics.GOOGLE_SOURCES + test_lyrics.DEFAULT_SOURCES:
print(s['url'])
url = s['url'] + s['path']

View file

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from beets.plugins import BeetsPlugin
from beets import ui
@ -17,7 +16,7 @@ class TestPlugin(BeetsPlugin):
test.func = lambda *args: None
# Used in CompletionTest
test.parser.add_option('-o', '--option', dest='my_opt')
test.parser.add_option(u'-o', u'--option', dest='my_opt')
plugin = ui.Subcommand('plugin')
plugin.func = lambda *args: None

View file

@ -15,8 +15,7 @@
"""Tests for the album art fetchers."""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import os
import shutil
@ -298,10 +297,10 @@ class ArtImporterTest(UseThePlugin):
self.task.is_album = True
self.task.album = self.album
info = AlbumInfo(
album='some album',
album_id='albumid',
artist='some artist',
artist_id='artistid',
album=u'some album',
album_id=u'albumid',
artist=u'some artist',
artist_id=u'artistid',
tracks=[],
)
self.task.set_choice(AlbumMatch(0, info, {}, set(), set()))
@ -439,7 +438,7 @@ class ArtForAlbumTest(UseThePlugin):
PIL (so comparisons and measurements are unavailable).
"""
if ArtResizer.shared.method[0] == WEBPROXY:
self.skipTest("ArtResizer has no local imaging backend available")
self.skipTest(u"ArtResizer has no local imaging backend available")
def test_respect_minwidth(self):
self._require_backend()

View file

@ -15,8 +15,7 @@
"""Tests for autotagging functionality.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import re
import copy
@ -636,7 +635,7 @@ class ApplyTest(_common.TestCase, ApplyTestUtil):
trackinfo = []
trackinfo.append(TrackInfo(
u'oneNew',
'dfa939ec-118c-4d0f-84a0-60f3d1e6522c',
u'dfa939ec-118c-4d0f-84a0-60f3d1e6522c',
medium=1,
medium_index=1,
medium_total=1,
@ -646,7 +645,7 @@ class ApplyTest(_common.TestCase, ApplyTestUtil):
))
trackinfo.append(TrackInfo(
u'twoNew',
'40130ed1-a27c-42fd-a328-1ebefb6caef4',
u'40130ed1-a27c-42fd-a328-1ebefb6caef4',
medium=2,
medium_index=1,
index=2,
@ -808,16 +807,16 @@ class ApplyCompilationTest(_common.TestCase, ApplyTestUtil):
trackinfo = []
trackinfo.append(TrackInfo(
u'oneNew',
'dfa939ec-118c-4d0f-84a0-60f3d1e6522c',
u'dfa939ec-118c-4d0f-84a0-60f3d1e6522c',
u'artistOneNew',
'a05686fc-9db2-4c23-b99e-77f5db3e5282',
u'a05686fc-9db2-4c23-b99e-77f5db3e5282',
index=1,
))
trackinfo.append(TrackInfo(
u'twoNew',
'40130ed1-a27c-42fd-a328-1ebefb6caef4',
u'40130ed1-a27c-42fd-a328-1ebefb6caef4',
u'artistTwoNew',
'80b3cf5e-18fe-4c59-98c7-e5bb87210710',
u'80b3cf5e-18fe-4c59-98c7-e5bb87210710',
index=2,
))
self.info = AlbumInfo(

View file

@ -15,8 +15,7 @@
"""Tests for the 'bucket' plugin."""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from test._common import unittest
from beetsplug import bucket

View file

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import os
import yaml

View file

@ -13,8 +13,7 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import re
import os.path

View file

@ -15,8 +15,7 @@
"""Test for dbcore's date-based queries.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from test import _common
from test._common import unittest

View file

@ -15,8 +15,7 @@
"""Tests for the DBCore database abstraction.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import os
import shutil
@ -313,7 +312,7 @@ class ModelTest(unittest.TestCase):
def test_computed_field(self):
model = TestModelWithGetters()
self.assertEqual(model.aComputedField, 'thing')
with self.assertRaisesRegexp(KeyError, 'computed field .+ deleted'):
with self.assertRaisesRegexp(KeyError, u'computed field .+ deleted'):
del model.aComputedField
def test_items(self):
@ -329,7 +328,7 @@ class ModelTest(unittest.TestCase):
model._db
def test_parse_nonstring(self):
with self.assertRaisesRegexp(TypeError, "must be a string"):
with self.assertRaisesRegexp(TypeError, u"must be a string"):
dbcore.Model._parse(None, 42)

View file

@ -14,8 +14,7 @@
# included in all copies or substantial portions of the Software.
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import os.path
from mock import Mock, patch
@ -31,7 +30,7 @@ class EchonestCliTest(unittest.TestCase, TestHelper):
try:
__import__('pyechonest')
except ImportError:
self.skipTest('pyechonest not available')
self.skipTest(u'pyechonest not available')
self.setup_beets()
self.load_plugins('echonest')
@ -157,7 +156,7 @@ class EchonestCliTest(unittest.TestCase, TestHelper):
def test_custom_field_range_query(self):
item = Item(liveness=2.2)
item.add(self.lib)
item = self.lib.items('liveness:2.2..3').get()
item = self.lib.items(u'liveness:2.2..3').get()
self.assertEqual(item['liveness'], 2.2)
def profile(self, item, **values):

View file

@ -12,8 +12,7 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import codecs
from mock import patch
@ -218,7 +217,7 @@ class EditCommandTest(unittest.TestCase, TestHelper, EditMixin):
# Apply changes.
['a'])
self.assertEqual(self.lib.items('id:1')[0].foo, 'bar')
self.assertEqual(self.lib.items(u'id:1')[0].foo, 'bar')
self.assertCounts(write_call_count=1,
title_starts_with=u't\u00eftle')
@ -265,7 +264,7 @@ class EditCommandTest(unittest.TestCase, TestHelper, EditMixin):
"""Edit the yaml file incorrectly (resulting in a well-formed but
invalid yaml document)."""
# Edit the yaml file to an invalid but parseable file.
self.run_mocked_command({'contents': 'wellformed: yes, but invalid'},
self.run_mocked_command({'contents': u'wellformed: yes, but invalid'},
# No stdin.
[])

View file

@ -13,8 +13,7 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import os.path
import shutil
@ -101,7 +100,7 @@ class EmbedartCliTest(_common.TestCase, TestHelper):
if os.path.isfile(tmp_path):
os.remove(tmp_path)
self.fail('Artwork file {0} was not deleted'.format(tmp_path))
self.fail(u'Artwork file {0} was not deleted'.format(tmp_path))
def test_art_file_missing(self):
self.add_album_fixture()
@ -114,7 +113,7 @@ class EmbedartCliTest(_common.TestCase, TestHelper):
logging.getLogger('beets.embedart').setLevel(logging.DEBUG)
handle, tmp_path = tempfile.mkstemp()
os.write(handle, 'I am not an image.')
os.write(handle, u'I am not an image.')
os.close(handle)
try:
@ -136,7 +135,7 @@ class EmbedartCliTest(_common.TestCase, TestHelper):
mediafile = MediaFile(syspath(item.path))
self.assertEqual(mediafile.images[0].data, self.image_data,
'Image written is not {0}'.format(
u'Image written is not {0}'.format(
self.abbey_artpath))
@require_artresizer_compare
@ -150,7 +149,7 @@ class EmbedartCliTest(_common.TestCase, TestHelper):
mediafile = MediaFile(syspath(item.path))
self.assertEqual(mediafile.images[0].data, self.image_data,
'Image written is not {0}'.format(
u'Image written is not {0}'.format(
self.abbey_similarpath))
def test_non_ascii_album_path(self):

View file

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from test._common import unittest
from test.helper import TestHelper

View file

@ -13,8 +13,7 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import os
from test._common import unittest

View file

@ -15,8 +15,7 @@
"""Test file manipulation functionality of Item.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import shutil
import os
@ -73,7 +72,7 @@ class MoveTest(_common.TestCase):
old_path = self.i.path
self.assertExists(old_path)
self.i.artist = 'newArtist'
self.i.artist = u'newArtist'
self.i.move()
self.assertNotExists(old_path)
self.assertNotExists(os.path.dirname(old_path))
@ -196,7 +195,7 @@ class AlbumFileTest(_common.TestCase):
self.otherdir = os.path.join(self.temp_dir, 'testotherdir')
def test_albuminfo_move_changes_paths(self):
self.ai.album = 'newAlbumName'
self.ai.album = u'newAlbumName'
self.ai.move()
self.ai.store()
self.i.load()
@ -205,7 +204,7 @@ class AlbumFileTest(_common.TestCase):
def test_albuminfo_move_moves_file(self):
oldpath = self.i.path
self.ai.album = 'newAlbumName'
self.ai.album = u'newAlbumName'
self.ai.move()
self.ai.store()
self.i.load()
@ -215,7 +214,7 @@ class AlbumFileTest(_common.TestCase):
def test_albuminfo_move_copies_file(self):
oldpath = self.i.path
self.ai.album = 'newAlbumName'
self.ai.album = u'newAlbumName'
self.ai.move(True)
self.ai.store()
self.i.load()
@ -261,7 +260,7 @@ class ArtFileTest(_common.TestCase):
def test_art_moves_with_album(self):
self.assertTrue(os.path.exists(self.art))
oldpath = self.i.path
self.ai.album = 'newAlbum'
self.ai.album = u'newAlbum'
self.ai.move()
self.i.load()
@ -289,7 +288,7 @@ class ArtFileTest(_common.TestCase):
touch(newart)
i2 = item()
i2.path = self.i.path
i2.artist = 'someArtist'
i2.artist = u'someArtist'
ai = self.lib.add_album((i2,))
i2.move(True)
@ -305,7 +304,7 @@ class ArtFileTest(_common.TestCase):
touch(newart)
i2 = item()
i2.path = self.i.path
i2.artist = 'someArtist'
i2.artist = u'someArtist'
ai = self.lib.add_album((i2,))
i2.move(True)
ai.set_art(newart)
@ -319,7 +318,7 @@ class ArtFileTest(_common.TestCase):
touch(newart)
i2 = item()
i2.path = self.i.path
i2.artist = 'someArtist'
i2.artist = u'someArtist'
ai = self.lib.add_album((i2,))
i2.move(True)
@ -336,7 +335,7 @@ class ArtFileTest(_common.TestCase):
touch(newart)
i2 = item()
i2.path = self.i.path
i2.artist = 'someArtist'
i2.artist = u'someArtist'
ai = self.lib.add_album((i2,))
i2.move(True)
@ -360,7 +359,7 @@ class ArtFileTest(_common.TestCase):
try:
i2 = item()
i2.path = self.i.path
i2.artist = 'someArtist'
i2.artist = u'someArtist'
ai = self.lib.add_album((i2,))
i2.move(True)
ai.set_art(newart)
@ -378,12 +377,12 @@ class ArtFileTest(_common.TestCase):
oldartpath = self.lib.albums()[0].artpath
self.assertExists(oldartpath)
self.ai.album = 'different_album'
self.ai.album = u'different_album'
self.ai.store()
self.ai.items()[0].move()
artpath = self.lib.albums()[0].artpath
self.assertTrue('different_album' in artpath)
self.assertTrue(u'different_album' in artpath)
self.assertExists(artpath)
self.assertNotExists(oldartpath)
@ -395,12 +394,12 @@ class ArtFileTest(_common.TestCase):
oldartpath = self.lib.albums()[0].artpath
self.assertExists(oldartpath)
self.i.album = 'different_album'
self.i.album = u'different_album'
self.i.album_id = None # detach from album
self.i.move()
artpath = self.lib.albums()[0].artpath
self.assertFalse('different_album' in artpath)
self.assertFalse(u'different_album' in artpath)
self.assertEqual(artpath, oldartpath)
self.assertExists(oldartpath)
@ -481,7 +480,7 @@ class SoftRemoveTest(_common.TestCase):
try:
util.remove(self.path + 'XXX', True)
except OSError:
self.fail('OSError when removing path')
self.fail(u'OSError when removing path')
class SafeMoveCopyTest(_common.TestCase):

View file

@ -15,8 +15,7 @@
"""Tests for the 'ftintitle' plugin."""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from test._common import unittest
from test.helper import TestHelper
@ -150,33 +149,33 @@ class FtInTitlePluginTest(unittest.TestCase):
self.assertEqual(feat_part, test_case['feat_part'])
def test_split_on_feat(self):
parts = ftintitle.split_on_feat('Alice ft. Bob')
self.assertEqual(parts, ('Alice', 'Bob'))
parts = ftintitle.split_on_feat('Alice feat Bob')
self.assertEqual(parts, ('Alice', 'Bob'))
parts = ftintitle.split_on_feat('Alice feat. Bob')
self.assertEqual(parts, ('Alice', 'Bob'))
parts = ftintitle.split_on_feat('Alice featuring Bob')
self.assertEqual(parts, ('Alice', 'Bob'))
parts = ftintitle.split_on_feat('Alice & Bob')
self.assertEqual(parts, ('Alice', 'Bob'))
parts = ftintitle.split_on_feat('Alice and Bob')
self.assertEqual(parts, ('Alice', 'Bob'))
parts = ftintitle.split_on_feat('Alice With Bob')
self.assertEqual(parts, ('Alice', 'Bob'))
parts = ftintitle.split_on_feat('Alice defeat Bob')
self.assertEqual(parts, ('Alice defeat Bob', None))
parts = ftintitle.split_on_feat(u'Alice ft. Bob')
self.assertEqual(parts, (u'Alice', u'Bob'))
parts = ftintitle.split_on_feat(u'Alice feat Bob')
self.assertEqual(parts, (u'Alice', u'Bob'))
parts = ftintitle.split_on_feat(u'Alice feat. Bob')
self.assertEqual(parts, (u'Alice', u'Bob'))
parts = ftintitle.split_on_feat(u'Alice featuring Bob')
self.assertEqual(parts, (u'Alice', u'Bob'))
parts = ftintitle.split_on_feat(u'Alice & Bob')
self.assertEqual(parts, (u'Alice', u'Bob'))
parts = ftintitle.split_on_feat(u'Alice and Bob')
self.assertEqual(parts, (u'Alice', u'Bob'))
parts = ftintitle.split_on_feat(u'Alice With Bob')
self.assertEqual(parts, (u'Alice', u'Bob'))
parts = ftintitle.split_on_feat(u'Alice defeat Bob')
self.assertEqual(parts, (u'Alice defeat Bob', None))
def test_contains_feat(self):
self.assertTrue(ftintitle.contains_feat('Alice ft. Bob'))
self.assertTrue(ftintitle.contains_feat('Alice feat. Bob'))
self.assertTrue(ftintitle.contains_feat('Alice feat Bob'))
self.assertTrue(ftintitle.contains_feat('Alice featuring Bob'))
self.assertTrue(ftintitle.contains_feat('Alice & Bob'))
self.assertTrue(ftintitle.contains_feat('Alice and Bob'))
self.assertTrue(ftintitle.contains_feat('Alice With Bob'))
self.assertFalse(ftintitle.contains_feat('Alice defeat Bob'))
self.assertFalse(ftintitle.contains_feat('Aliceft.Bob'))
self.assertTrue(ftintitle.contains_feat(u'Alice ft. Bob'))
self.assertTrue(ftintitle.contains_feat(u'Alice feat. Bob'))
self.assertTrue(ftintitle.contains_feat(u'Alice feat Bob'))
self.assertTrue(ftintitle.contains_feat(u'Alice featuring Bob'))
self.assertTrue(ftintitle.contains_feat(u'Alice & Bob'))
self.assertTrue(ftintitle.contains_feat(u'Alice and Bob'))
self.assertTrue(ftintitle.contains_feat(u'Alice With Bob'))
self.assertFalse(ftintitle.contains_feat(u'Alice defeat Bob'))
self.assertFalse(ftintitle.contains_feat(u'Aliceft.Bob'))
def suite():

View file

@ -2,8 +2,7 @@
"""Tests for the 'ihate' plugin"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from test._common import unittest
from beets import importer
@ -17,7 +16,7 @@ class IHatePluginTest(unittest.TestCase):
match_pattern = {}
test_item = Item(
genre='TestGenre',
genre=u'TestGenre',
album=u'TestAlbum',
artist=u'TestArtist')
task = importer.SingletonImportTask(None, test_item)
@ -26,25 +25,25 @@ class IHatePluginTest(unittest.TestCase):
self.assertFalse(IHatePlugin.do_i_hate_this(task, match_pattern))
# 1 query match.
match_pattern = ["artist:bad_artist", "artist:TestArtist"]
match_pattern = [u"artist:bad_artist", u"artist:TestArtist"]
self.assertTrue(IHatePlugin.do_i_hate_this(task, match_pattern))
# 2 query matches, either should trigger.
match_pattern = ["album:test", "artist:testartist"]
match_pattern = [u"album:test", u"artist:testartist"]
self.assertTrue(IHatePlugin.do_i_hate_this(task, match_pattern))
# Query is blocked by AND clause.
match_pattern = ["album:notthis genre:testgenre"]
match_pattern = [u"album:notthis genre:testgenre"]
self.assertFalse(IHatePlugin.do_i_hate_this(task, match_pattern))
# Both queries are blocked by AND clause with unmatched condition.
match_pattern = ["album:notthis genre:testgenre",
"artist:testartist album:notthis"]
match_pattern = [u"album:notthis genre:testgenre",
u"artist:testartist album:notthis"]
self.assertFalse(IHatePlugin.do_i_hate_this(task, match_pattern))
# Only one query should fire.
match_pattern = ["album:testalbum genre:testgenre",
"artist:testartist album:notthis"]
match_pattern = [u"album:testalbum genre:testgenre",
u"artist:testartist album:notthis"]
self.assertTrue(IHatePlugin.do_i_hate_this(task, match_pattern))

View file

@ -13,8 +13,7 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
"""Tests for the `importadded` plugin."""
@ -73,7 +72,7 @@ class ImportAddedTest(unittest.TestCase, ImportHelper):
for m in self.media_files:
if m.title.replace('Tag', 'Applied') == item.title:
return m
raise AssertionError("No MediaFile found for Item " +
raise AssertionError(u"No MediaFile found for Item " +
util.displayable_path(item.path))
def assertEqualTimes(self, first, second, msg=None):
@ -127,7 +126,7 @@ class ImportAddedTest(unittest.TestCase, ImportHelper):
for item in album.items())
for item_path, added_after in items_added_after.iteritems():
self.assertEqualTimes(items_added_before[item_path], added_after,
"reimport modified Item.added for " +
u"reimport modified Item.added for " +
item_path)
def test_import_singletons_with_added_dates(self):
@ -165,7 +164,7 @@ class ImportAddedTest(unittest.TestCase, ImportHelper):
for item in self.lib.items())
for item_path, added_after in items_added_after.iteritems():
self.assertEqualTimes(items_added_before[item_path], added_after,
"reimport modified Item.added for " +
u"reimport modified Item.added for " +
item_path)

View file

@ -13,8 +13,7 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
"""Tests for the general importer functionality.
"""
@ -121,7 +120,7 @@ class AutotagStub(object):
else:
id = ''
if artist is None:
artist = "Various Artists"
artist = u"Various Artists"
else:
artist = artist.replace('Tag', 'Applied') + id
album = album.replace('Tag', 'Applied') + id
@ -150,9 +149,9 @@ class ImportHelper(TestHelper):
def setup_beets(self, disk=False):
super(ImportHelper, self).setup_beets(disk)
self.lib.path_formats = [
('default', os.path.join('$artist', '$album', '$title')),
('singleton:true', os.path.join('singletons', '$title')),
('comp:true', os.path.join('compilations', '$album', '$title')),
(u'default', os.path.join('$artist', '$album', '$title')),
(u'singleton:true', os.path.join('singletons', '$title')),
(u'comp:true', os.path.join('compilations', '$album', '$title')),
]
def _create_import_dir(self, count=3):
@ -179,8 +178,8 @@ class ImportHelper(TestHelper):
resource_path = os.path.join(_common.RSRC, 'full.mp3')
metadata = {
'artist': 'Tag Artist',
'album': 'Tag Album',
'artist': u'Tag Artist',
'album': u'Tag Album',
'albumartist': None,
'mb_trackid': None,
'mb_albumid': None,
@ -195,7 +194,7 @@ class ImportHelper(TestHelper):
# Set metadata
metadata['track'] = i + 1
metadata['title'] = 'Tag Title %d' % (i + 1)
metadata['title'] = u'Tag Title %d' % (i + 1)
for attr in metadata:
setattr(medium, attr, metadata[attr])
medium.save()
@ -250,7 +249,7 @@ class NonAutotaggedImportTest(_common.TestCase, ImportHelper):
self.importer.run()
albums = self.lib.albums()
self.assertEqual(len(albums), 1)
self.assertEqual(albums[0].albumartist, 'Tag Artist')
self.assertEqual(albums[0].albumartist, u'Tag Artist')
def test_import_copy_arrives(self):
self.importer.run()
@ -411,7 +410,7 @@ class ImportTarTest(ImportZipTest):
return path
@unittest.skipIf(not has_program('unrar'), 'unrar program not found')
@unittest.skipIf(not has_program('unrar'), u'unrar program not found')
class ImportRarTest(ImportZipTest):
def create_archive(self):
@ -446,7 +445,7 @@ class ImportSingletonTest(_common.TestCase, ImportHelper):
self.importer.add_choice(importer.action.ASIS)
self.importer.run()
self.assertEqual(self.lib.items().get().title, 'Tag Title 1')
self.assertEqual(self.lib.items().get().title, u'Tag Title 1')
def test_apply_asis_does_not_add_album(self):
self.assertEqual(self.lib.albums().get(), None)
@ -467,7 +466,7 @@ class ImportSingletonTest(_common.TestCase, ImportHelper):
self.importer.add_choice(importer.action.APPLY)
self.importer.run()
self.assertEqual(self.lib.items().get().title, 'Applied Title 1')
self.assertEqual(self.lib.items().get().title, u'Applied Title 1')
def test_apply_candidate_does_not_add_album(self):
self.importer.add_choice(importer.action.APPLY)
@ -479,7 +478,7 @@ class ImportSingletonTest(_common.TestCase, ImportHelper):
self.importer.add_choice(importer.action.APPLY)
self.importer.run()
self.assert_file_in_lib('singletons', 'Applied Title 1.mp3')
self.assert_file_in_lib('singletons', u'Applied Title 1.mp3')
def test_skip_does_not_add_first_track(self):
self.importer.add_choice(importer.action.SKIP)
@ -532,13 +531,13 @@ class ImportTest(_common.TestCase, ImportHelper):
self.importer.add_choice(importer.action.ASIS)
self.importer.run()
self.assertEqual(self.lib.albums().get().album, 'Tag Album')
self.assertEqual(self.lib.albums().get().album, u'Tag Album')
def test_apply_asis_adds_tracks(self):
self.assertEqual(self.lib.items().get(), None)
self.importer.add_choice(importer.action.ASIS)
self.importer.run()
self.assertEqual(self.lib.items().get().title, 'Tag Title 1')
self.assertEqual(self.lib.items().get().title, u'Tag Title 1')
def test_apply_asis_adds_album_path(self):
self.assert_lib_dir_empty()
@ -552,14 +551,14 @@ class ImportTest(_common.TestCase, ImportHelper):
self.importer.add_choice(importer.action.APPLY)
self.importer.run()
self.assertEqual(self.lib.albums().get().album, 'Applied Album')
self.assertEqual(self.lib.albums().get().album, u'Applied Album')
def test_apply_candidate_adds_tracks(self):
self.assertEqual(self.lib.items().get(), None)
self.importer.add_choice(importer.action.APPLY)
self.importer.run()
self.assertEqual(self.lib.items().get().title, 'Applied Title 1')
self.assertEqual(self.lib.items().get().title, u'Applied Title 1')
def test_apply_candidate_adds_album_path(self):
self.assert_lib_dir_empty()
@ -617,7 +616,7 @@ class ImportTest(_common.TestCase, ImportHelper):
with capture_log() as logs:
self.importer.run()
self.assertIn('No files imported from {0}'.format(import_dir), logs)
self.assertIn(u'No files imported from {0}'.format(import_dir), logs)
def test_empty_directory_singleton_warning(self):
import_dir = os.path.join(self.temp_dir, 'empty')
@ -626,7 +625,7 @@ class ImportTest(_common.TestCase, ImportHelper):
with capture_log() as logs:
self.importer.run()
self.assertIn('No files imported from {0}'.format(import_dir), logs)
self.assertIn(u'No files imported from {0}'.format(import_dir), logs)
def test_asis_no_data_source(self):
self.assertEqual(self.lib.items().get(), None)
@ -659,7 +658,7 @@ class ImportTracksTest(_common.TestCase, ImportHelper):
self.importer.add_choice(importer.action.APPLY)
self.importer.add_choice(importer.action.APPLY)
self.importer.run()
self.assertEqual(self.lib.items().get().title, 'Applied Title 1')
self.assertEqual(self.lib.items().get().title, u'Applied Title 1')
self.assertEqual(self.lib.albums().get(), None)
def test_apply_tracks_adds_singleton_path(self):
@ -688,27 +687,27 @@ class ImportCompilationTest(_common.TestCase, ImportHelper):
def test_asis_homogenous_sets_albumartist(self):
self.importer.add_choice(importer.action.ASIS)
self.importer.run()
self.assertEqual(self.lib.albums().get().albumartist, 'Tag Artist')
self.assertEqual(self.lib.albums().get().albumartist, u'Tag Artist')
for item in self.lib.items():
self.assertEqual(item.albumartist, 'Tag Artist')
self.assertEqual(item.albumartist, u'Tag Artist')
def test_asis_heterogenous_sets_various_albumartist(self):
self.import_media[0].artist = 'Other Artist'
self.import_media[0].artist = u'Other Artist'
self.import_media[0].save()
self.import_media[1].artist = 'Another Artist'
self.import_media[1].artist = u'Another Artist'
self.import_media[1].save()
self.importer.add_choice(importer.action.ASIS)
self.importer.run()
self.assertEqual(self.lib.albums().get().albumartist,
'Various Artists')
u'Various Artists')
for item in self.lib.items():
self.assertEqual(item.albumartist, 'Various Artists')
self.assertEqual(item.albumartist, u'Various Artists')
def test_asis_heterogenous_sets_sompilation(self):
self.import_media[0].artist = 'Other Artist'
self.import_media[0].artist = u'Other Artist'
self.import_media[0].save()
self.import_media[1].artist = 'Another Artist'
self.import_media[1].artist = u'Another Artist'
self.import_media[1].save()
self.importer.add_choice(importer.action.ASIS)
@ -717,33 +716,33 @@ class ImportCompilationTest(_common.TestCase, ImportHelper):
self.assertTrue(item.comp)
def test_asis_sets_majority_albumartist(self):
self.import_media[0].artist = 'Other Artist'
self.import_media[0].artist = u'Other Artist'
self.import_media[0].save()
self.import_media[1].artist = 'Other Artist'
self.import_media[1].artist = u'Other Artist'
self.import_media[1].save()
self.importer.add_choice(importer.action.ASIS)
self.importer.run()
self.assertEqual(self.lib.albums().get().albumartist, 'Other Artist')
self.assertEqual(self.lib.albums().get().albumartist, u'Other Artist')
for item in self.lib.items():
self.assertEqual(item.albumartist, 'Other Artist')
self.assertEqual(item.albumartist, u'Other Artist')
def test_asis_albumartist_tag_sets_albumartist(self):
self.import_media[0].artist = 'Other Artist'
self.import_media[1].artist = 'Another Artist'
self.import_media[0].artist = u'Other Artist'
self.import_media[1].artist = u'Another Artist'
for mediafile in self.import_media:
mediafile.albumartist = 'Album Artist'
mediafile.mb_albumartistid = 'Album Artist ID'
mediafile.albumartist = u'Album Artist'
mediafile.mb_albumartistid = u'Album Artist ID'
mediafile.save()
self.importer.add_choice(importer.action.ASIS)
self.importer.run()
self.assertEqual(self.lib.albums().get().albumartist, 'Album Artist')
self.assertEqual(self.lib.albums().get().albumartist, u'Album Artist')
self.assertEqual(self.lib.albums().get().mb_albumartistid,
'Album Artist ID')
u'Album Artist ID')
for item in self.lib.items():
self.assertEqual(item.albumartist, 'Album Artist')
self.assertEqual(item.mb_albumartistid, 'Album Artist ID')
self.assertEqual(item.albumartist, u'Album Artist')
self.assertEqual(item.mb_albumartistid, u'Album Artist ID')
class ImportExistingTest(_common.TestCase, ImportHelper):
@ -794,17 +793,17 @@ class ImportExistingTest(_common.TestCase, ImportHelper):
def test_asis_updates_metadata(self):
self.setup_importer.run()
medium = MediaFile(self.lib.items().get().path)
medium.title = 'New Title'
medium.title = u'New Title'
medium.save()
self.importer.add_choice(importer.action.ASIS)
self.importer.run()
self.assertEqual(self.lib.items().get().title, 'New Title')
self.assertEqual(self.lib.items().get().title, u'New Title')
def test_asis_updated_moves_file(self):
self.setup_importer.run()
medium = MediaFile(self.lib.items().get().path)
medium.title = 'New Title'
medium.title = u'New Title'
medium.save()
old_path = os.path.join('Applied Artist', 'Applied Album',
@ -820,7 +819,7 @@ class ImportExistingTest(_common.TestCase, ImportHelper):
def test_asis_updated_without_copy_does_not_move_file(self):
self.setup_importer.run()
medium = MediaFile(self.lib.items().get().path)
medium.title = 'New Title'
medium.title = u'New Title'
medium.save()
old_path = os.path.join('Applied Artist', 'Applied Album',
@ -881,8 +880,8 @@ class GroupAlbumsImportTest(_common.TestCase, ImportHelper):
self.matcher.restore()
def test_add_album_for_different_artist_and_different_album(self):
self.import_media[0].artist = "Artist B"
self.import_media[0].album = "Album B"
self.import_media[0].artist = u"Artist B"
self.import_media[0].album = u"Album B"
self.import_media[0].save()
self.importer.run()
@ -890,11 +889,11 @@ class GroupAlbumsImportTest(_common.TestCase, ImportHelper):
self.assertEqual(albums, set(['Album B', 'Tag Album']))
def test_add_album_for_different_artist_and_same_albumartist(self):
self.import_media[0].artist = "Artist B"
self.import_media[0].albumartist = "Album Artist"
self.import_media[0].artist = u"Artist B"
self.import_media[0].albumartist = u"Album Artist"
self.import_media[0].save()
self.import_media[1].artist = "Artist C"
self.import_media[1].albumartist = "Album Artist"
self.import_media[1].artist = u"Artist C"
self.import_media[1].albumartist = u"Album Artist"
self.import_media[1].save()
self.importer.run()
@ -902,7 +901,7 @@ class GroupAlbumsImportTest(_common.TestCase, ImportHelper):
self.assertEqual(artists, set(['Album Artist', 'Tag Artist']))
def test_add_album_for_same_artist_and_different_album(self):
self.import_media[0].album = "Album B"
self.import_media[0].album = u"Album B"
self.import_media[0].save()
self.importer.run()
@ -910,7 +909,7 @@ class GroupAlbumsImportTest(_common.TestCase, ImportHelper):
self.assertEqual(albums, set(['Album B', 'Tag Album']))
def test_add_album_for_same_album_and_different_artist(self):
self.import_media[0].artist = "Artist B"
self.import_media[0].artist = u"Artist B"
self.import_media[0].save()
self.importer.run()
@ -919,7 +918,7 @@ class GroupAlbumsImportTest(_common.TestCase, ImportHelper):
def test_incremental(self):
config['import']['incremental'] = True
self.import_media[0].album = "Album B"
self.import_media[0].album = u"Album B"
self.import_media[0].save()
self.importer.run()
@ -951,12 +950,12 @@ class ChooseCandidateTest(_common.TestCase, ImportHelper):
def test_choose_first_candidate(self):
self.importer.add_choice(1)
self.importer.run()
self.assertEqual(self.lib.albums().get().album, 'Applied Album M')
self.assertEqual(self.lib.albums().get().album, u'Applied Album M')
def test_choose_second_candidate(self):
self.importer.add_choice(2)
self.importer.run()
self.assertEqual(self.lib.albums().get().album, 'Applied Album MM')
self.assertEqual(self.lib.albums().get().album, u'Applied Album MM')
class InferAlbumDataTest(_common.TestCase):
@ -966,9 +965,9 @@ class InferAlbumDataTest(_common.TestCase):
i1 = _common.item()
i2 = _common.item()
i3 = _common.item()
i1.title = 'first item'
i2.title = 'second item'
i3.title = 'third item'
i1.title = u'first item'
i2.title = u'second item'
i3.title = u'third item'
i1.comp = i2.comp = i3.comp = False
i1.albumartist = i2.albumartist = i3.albumartist = ''
i1.mb_albumartistid = i2.mb_albumartistid = i3.mb_albumartistid = ''
@ -984,28 +983,28 @@ class InferAlbumDataTest(_common.TestCase):
self.assertEqual(self.items[0].albumartist, self.items[2].artist)
def test_asis_heterogenous_va(self):
self.items[0].artist = 'another artist'
self.items[1].artist = 'some other artist'
self.items[0].artist = u'another artist'
self.items[1].artist = u'some other artist'
self.task.set_choice(importer.action.ASIS)
self.task.align_album_level_fields()
self.assertTrue(self.items[0].comp)
self.assertEqual(self.items[0].albumartist, 'Various Artists')
self.assertEqual(self.items[0].albumartist, u'Various Artists')
def test_asis_comp_applied_to_all_items(self):
self.items[0].artist = 'another artist'
self.items[1].artist = 'some other artist'
self.items[0].artist = u'another artist'
self.items[1].artist = u'some other artist'
self.task.set_choice(importer.action.ASIS)
self.task.align_album_level_fields()
for item in self.items:
self.assertTrue(item.comp)
self.assertEqual(item.albumartist, 'Various Artists')
self.assertEqual(item.albumartist, u'Various Artists')
def test_asis_majority_artist_single_artist(self):
self.items[0].artist = 'another artist'
self.items[0].artist = u'another artist'
self.task.set_choice(importer.action.ASIS)
self.task.align_album_level_fields()
@ -1014,19 +1013,19 @@ class InferAlbumDataTest(_common.TestCase):
self.assertEqual(self.items[0].albumartist, self.items[2].artist)
def test_asis_track_albumartist_override(self):
self.items[0].artist = 'another artist'
self.items[1].artist = 'some other artist'
self.items[0].artist = u'another artist'
self.items[1].artist = u'some other artist'
for item in self.items:
item.albumartist = 'some album artist'
item.mb_albumartistid = 'some album artist id'
item.albumartist = u'some album artist'
item.mb_albumartistid = u'some album artist id'
self.task.set_choice(importer.action.ASIS)
self.task.align_album_level_fields()
self.assertEqual(self.items[0].albumartist,
'some album artist')
u'some album artist')
self.assertEqual(self.items[0].mb_albumartistid,
'some album artist id')
u'some album artist id')
def test_apply_gets_artist_and_id(self):
self.task.set_choice(AlbumMatch(0, None, {}, set(), set())) # APPLY
@ -1039,16 +1038,16 @@ class InferAlbumDataTest(_common.TestCase):
def test_apply_lets_album_values_override(self):
for item in self.items:
item.albumartist = 'some album artist'
item.mb_albumartistid = 'some album artist id'
item.albumartist = u'some album artist'
item.mb_albumartistid = u'some album artist id'
self.task.set_choice(AlbumMatch(0, None, {}, set(), set())) # APPLY
self.task.align_album_level_fields()
self.assertEqual(self.items[0].albumartist,
'some album artist')
u'some album artist')
self.assertEqual(self.items[0].mb_albumartistid,
'some album artist id')
u'some album artist id')
def test_small_single_artist_album(self):
self.items = [self.items[0]]
@ -1272,11 +1271,11 @@ class ResumeImportTest(unittest.TestCase, TestHelper):
self.importer.run()
self.assertEqual(len(self.lib.albums()), 1)
self.assertIsNotNone(self.lib.albums('album:album 0').get())
self.assertIsNotNone(self.lib.albums(u'album:album 0').get())
self.importer.run()
self.assertEqual(len(self.lib.albums()), 2)
self.assertIsNotNone(self.lib.albums('album:album 1').get())
self.assertIsNotNone(self.lib.albums(u'album:album 1').get())
@patch('beets.plugins.send')
def test_resume_singleton(self, plugins_send):
@ -1293,11 +1292,11 @@ class ResumeImportTest(unittest.TestCase, TestHelper):
self.importer.run()
self.assertEqual(len(self.lib.items()), 1)
self.assertIsNotNone(self.lib.items('title:track 0').get())
self.assertIsNotNone(self.lib.items(u'title:track 0').get())
self.importer.run()
self.assertEqual(len(self.lib.items()), 2)
self.assertIsNotNone(self.lib.items('title:track 1').get())
self.assertIsNotNone(self.lib.items(u'title:track 1').get())
class IncrementalImportTest(unittest.TestCase, TestHelper):
@ -1685,7 +1684,7 @@ class ImportPretendTest(_common.TestCase, ImportHelper):
def test_import_pretend_empty(self):
logs = self.__run([self.empty_path])
self.assertEqual(logs, ['No files imported from {0}'
self.assertEqual(logs, [u'No files imported from {0}'
.format(displayable_path(self.empty_path))])

View file

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import os
import os.path

View file

@ -13,8 +13,7 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from test._common import unittest
from test.helper import TestHelper

View file

@ -13,8 +13,7 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from mock import patch
from test._common import unittest

View file

@ -15,8 +15,7 @@
"""Tests for the 'lastgenre' plugin."""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
from mock import Mock
@ -52,7 +51,7 @@ class LastGenrePluginTest(unittest.TestCase, TestHelper):
"""
self._setup_config()
self.assertEqual(self.plugin._resolve_genres(['delta blues']),
'Delta Blues')
u'Delta Blues')
def test_c14n_only(self):
"""Default c14n tree funnels up to most common genre except for *wrong*
@ -60,16 +59,16 @@ class LastGenrePluginTest(unittest.TestCase, TestHelper):
"""
self._setup_config(canonical=True, count=99)
self.assertEqual(self.plugin._resolve_genres(['delta blues']),
'Blues')
u'Blues')
self.assertEqual(self.plugin._resolve_genres(['iota blues']),
'Iota Blues')
u'Iota Blues')
def test_whitelist_only(self):
"""Default whitelist rejects *wrong* (non existing) genres.
"""
self._setup_config(whitelist=True)
self.assertEqual(self.plugin._resolve_genres(['iota blues']),
'')
u'')
def test_whitelist_c14n(self):
"""Default whitelist and c14n both activated result in all parents
@ -77,7 +76,7 @@ class LastGenrePluginTest(unittest.TestCase, TestHelper):
"""
self._setup_config(canonical=True, whitelist=True, count=99)
self.assertEqual(self.plugin._resolve_genres(['delta blues']),
'Delta Blues, Blues')
u'Delta Blues, Blues')
def test_whitelist_custom(self):
"""Keep only genres that are in the whitelist.
@ -85,11 +84,11 @@ class LastGenrePluginTest(unittest.TestCase, TestHelper):
self._setup_config(whitelist=set(['blues', 'rock', 'jazz']),
count=2)
self.assertEqual(self.plugin._resolve_genres(['pop', 'blues']),
'Blues')
u'Blues')
self._setup_config(canonical='', whitelist=set(['rock']))
self.assertEqual(self.plugin._resolve_genres(['delta blues']),
'')
u'')
def test_count(self):
"""Keep the n first genres, as we expect them to be sorted from more to
@ -99,7 +98,7 @@ class LastGenrePluginTest(unittest.TestCase, TestHelper):
count=2)
self.assertEqual(self.plugin._resolve_genres(
['jazz', 'pop', 'rock', 'blues']),
'Jazz, Rock')
u'Jazz, Rock')
def test_count_c14n(self):
"""Keep the n first genres, after having applied c14n when necessary
@ -111,14 +110,14 @@ class LastGenrePluginTest(unittest.TestCase, TestHelper):
# second slot
self.assertEqual(self.plugin._resolve_genres(
['jazz', 'pop', 'country blues', 'rock']),
'Jazz, Blues')
u'Jazz, Blues')
def test_c14n_whitelist(self):
"""Genres first pass through c14n and are then filtered
"""
self._setup_config(canonical=True, whitelist=set(['rock']))
self.assertEqual(self.plugin._resolve_genres(['delta blues']),
'')
u'')
def test_empty_string_enables_canonical(self):
"""For backwards compatibility, setting the `canonical` option
@ -126,7 +125,7 @@ class LastGenrePluginTest(unittest.TestCase, TestHelper):
"""
self._setup_config(canonical='', count=99)
self.assertEqual(self.plugin._resolve_genres(['delta blues']),
'Blues')
u'Blues')
def test_empty_string_enables_whitelist(self):
"""Again for backwards compatibility, setting the `whitelist`
@ -134,14 +133,14 @@ class LastGenrePluginTest(unittest.TestCase, TestHelper):
"""
self._setup_config(whitelist='')
self.assertEqual(self.plugin._resolve_genres(['iota blues']),
'')
u'')
def test_no_duplicate(self):
"""Remove duplicated genres.
"""
self._setup_config(count=99)
self.assertEqual(self.plugin._resolve_genres(['blues', 'blues']),
'Blues')
u'Blues')
def test_tags_for(self):
class MockPylastElem(object):
@ -189,29 +188,29 @@ class LastGenrePluginTest(unittest.TestCase, TestHelper):
config['lastgenre'] = {'force': False}
res = self.plugin._get_genre(item)
self.assertEqual(res, (item.genre, 'keep'))
self.assertEqual(res, (item.genre, u'keep'))
config['lastgenre'] = {'force': True, 'source': 'track'}
config['lastgenre'] = {'force': True, 'source': u'track'}
res = self.plugin._get_genre(item)
self.assertEqual(res, (MOCK_GENRES['track'], 'track'))
self.assertEqual(res, (MOCK_GENRES['track'], u'track'))
config['lastgenre'] = {'source': 'album'}
config['lastgenre'] = {'source': u'album'}
res = self.plugin._get_genre(item)
self.assertEqual(res, (MOCK_GENRES['album'], 'album'))
self.assertEqual(res, (MOCK_GENRES['album'], u'album'))
config['lastgenre'] = {'source': 'artist'}
config['lastgenre'] = {'source': u'artist'}
res = self.plugin._get_genre(item)
self.assertEqual(res, (MOCK_GENRES['artist'], 'artist'))
self.assertEqual(res, (MOCK_GENRES['artist'], u'artist'))
MOCK_GENRES['artist'] = None
res = self.plugin._get_genre(item)
self.assertEqual(res, (item.genre, 'original'))
self.assertEqual(res, (item.genre, u'original'))
config['lastgenre'] = {'fallback': 'rap'}
config['lastgenre'] = {'fallback': u'rap'}
item.genre = None
res = self.plugin._get_genre(item)
self.assertEqual(res, (config['lastgenre']['fallback'].get(),
'fallback'))
u'fallback'))
def suite():

View file

@ -15,8 +15,7 @@
"""Tests for non-query database functions of Item.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from __future__ import division, absolute_import, print_function
import os
import os.path
@ -47,12 +46,12 @@ np = util.normpath
class LoadTest(_common.LibTestCase):
def test_load_restores_data_from_db(self):
original_title = self.i.title
self.i.title = 'something'
self.i.title = u'something'
self.i.load()
self.assertEqual(original_title, self.i.title)
def test_load_clears_dirty_flags(self):
self.i.artist = 'something'
self.i.artist = u'something'
self.assertTrue('artist' in self.i._dirty)
self.i.load()
self.assertTrue('artist' not in self.i._dirty)
@ -69,7 +68,7 @@ class StoreTest(_common.LibTestCase):
def test_store_only_writes_dirty_fields(self):
original_genre = self.i.genre
self.i._values_fixed['genre'] = 'beatboxing' # change w/o dirtying
self.i._values_fixed['genre'] = u'beatboxing' # change w/o dirtying
self.i.store()
new_genre = self.lib._connection().execute(
'select genre from items where '
@ -77,7 +76,7 @@ class StoreTest(_common.LibTestCase):
self.assertEqual(new_genre, original_genre)
def test_store_clears_dirty_flags(self):
self.i.composer = 'tvp'
self.i.composer = u'tvp'
self.i.store()
self.assertTrue('composer' not in self.i._dirty)
@ -131,7 +130,7 @@ class GetSetTest(_common.TestCase):
self.assertTrue('title' not in self.i._dirty)
def test_invalid_field_raises_attributeerror(self):
self.assertRaises(AttributeError, getattr, self.i, 'xyzzy')
self.assertRaises(AttributeError, getattr, self.i, u'xyzzy')
class DestinationTest(_common.TestCase):
@ -150,17 +149,17 @@ class DestinationTest(_common.TestCase):
def test_directory_works_with_trailing_slash(self):
self.lib.directory = 'one/'
self.lib.path_formats = [('default', 'two')]
self.lib.path_formats = [(u'default', u'two')]
self.assertEqual(self.i.destination(), np('one/two'))
def test_directory_works_without_trailing_slash(self):
self.lib.directory = 'one'
self.lib.path_formats = [('default', 'two')]
self.lib.path_formats = [(u'default', u'two')]
self.assertEqual(self.i.destination(), np('one/two'))
def test_destination_substitues_metadata_values(self):
self.lib.directory = 'base'
self.lib.path_formats = [('default', '$album/$artist $title')]
self.lib.path_formats = [(u'default', u'$album/$artist $title')]
self.i.title = 'three'
self.i.artist = 'two'
self.i.album = 'one'
@ -169,22 +168,22 @@ class DestinationTest(_common.TestCase):
def test_destination_preserves_extension(self):
self.lib.directory = 'base'
self.lib.path_formats = [('default', '$title')]
self.lib.path_formats = [(u'default', u'$title')]
self.i.path = 'hey.audioformat'
self.assertEqual(self.i.destination(),
np('base/the title.audioformat'))
def test_lower_case_extension(self):
self.lib.directory = 'base'
self.lib.path_formats = [('default', '$title')]
self.lib.path_formats = [(u'default', u'$title')]
self.i.path = 'hey.MP3'
self.assertEqual(self.i.destination(),
np('base/the title.mp3'))
def test_destination_pads_some_indices(self):
self.lib.directory = 'base'
self.lib.path_formats = [('default',
'$track $tracktotal $disc $disctotal $bpm')]
self.lib.path_formats = [(u'default',
u'$track $tracktotal $disc $disctotal $bpm')]
self.i.track = 1
self.i.tracktotal = 2
self.i.disc = 3
@ -195,7 +194,7 @@ class DestinationTest(_common.TestCase):
def test_destination_pads_date_values(self):
self.lib.directory = 'base'
self.lib.path_formats = [('default', '$year-$month-$day')]
self.lib.path_formats = [(u'default', u'$year-$month-$day')]
self.i.year = 1
self.i.month = 2
self.i.day = 3
@ -222,13 +221,13 @@ class DestinationTest(_common.TestCase):
self.assertTrue(os.path.join('one', 'two') in dest)
def test_destination_long_names_truncated(self):
self.i.title = 'X' * 300
self.i.artist = 'Y' * 300
self.i.title = u'X' * 300
self.i.artist = u'Y' * 300
for c in self.i.destination().split(os.path.sep):
self.assertTrue(len(c) <= 255)
def test_destination_long_names_keep_extension(self):
self.i.title = 'X' * 300
self.i.title = u'X' * 300
self.i.path = 'something.extn'
dest = self.i.destination()
self.assertEqual(dest[-5:], '.extn')
@ -243,7 +242,7 @@ class DestinationTest(_common.TestCase):
self.assertFalse('two / three' in p)
def test_path_with_format(self):
self.lib.path_formats = [('default', '$artist/$album ($format)')]
self.lib.path_formats = [(u'default', u'$artist/$album ($format)')]
p = self.i.destination()
self.assert_('(FLAC)' in p)
@ -251,7 +250,7 @@ class DestinationTest(_common.TestCase):
i1, i2 = item(), item()
self.lib.add_album([i1, i2])
i1.year, i2.year = 2009, 2010
self.lib.path_formats = [('default', '$album ($year)/$track $title')]
self.lib.path_formats = [(u'default', u'$album ($year)/$track $title')]
dest1, dest2 = i1.destination(), i2.destination()
self.assertEqual(os.path.dirname(dest1), os.path.dirname(dest2))
@ -259,17 +258,17 @@ class DestinationTest(_common.TestCase):
self.i.comp = False
self.lib.add_album([self.i])
self.lib.directory = 'one'
self.lib.path_formats = [('default', 'two'),
('comp:true', 'three')]
self.lib.path_formats = [(u'default', u'two'),
(u'comp:true', u'three')]
self.assertEqual(self.i.destination(), np('one/two'))
def test_singleton_path(self):
i = item(self.lib)
self.lib.directory = 'one'
self.lib.path_formats = [
('default', 'two'),
('singleton:true', 'four'),
('comp:true', 'three'),
(u'default', u'two'),
(u'singleton:true', u'four'),
(u'comp:true', u'three'),
]
self.assertEqual(i.destination(), np('one/four'))
@ -278,9 +277,9 @@ class DestinationTest(_common.TestCase):
i.comp = True
self.lib.directory = 'one'
self.lib.path_formats = [
('default', 'two'),
('comp:true', 'three'),
('singleton:true', 'four'),
(u'default', u'two'),
(u'comp:true', u'three'),
(u'singleton:true', u'four'),
]
self.assertEqual(i.destination(), np('one/three'))
@ -289,32 +288,32 @@ class DestinationTest(_common.TestCase):
self.lib.add_album([self.i])
self.lib.directory = 'one'
self.lib.path_formats = [
('default', 'two'),
('comp:true', 'three'),
(u'default', u'two'),
(u'comp:true', u'three'),
]
self.assertEqual(self.i.destination(), np('one/three'))
def test_albumtype_query_path(self):
self.i.comp = True
self.lib.add_album([self.i])
self.i.albumtype = 'sometype'
self.i.albumtype = u'sometype'
self.lib.directory = 'one'
self.lib.path_formats = [
('default', 'two'),
('albumtype:sometype', 'four'),
('comp:true', 'three'),
(u'default', u'two'),
(u'albumtype:sometype', u'four'),
(u'comp:true', u'three'),
]
self.assertEqual(self.i.destination(), np('one/four'))
def test_albumtype_path_fallback_to_comp(self):
self.i.comp = True
self.lib.add_album([self.i])
self.i.albumtype = 'sometype'
self.i.albumtype = u'sometype'
self.lib.directory = 'one'
self.lib.path_formats = [
('default', 'two'),
('albumtype:anothertype', 'four'),
('comp:true', 'three'),
(u'default', u'two'),
(u'albumtype:anothertype', u'four'),
(u'comp:true', u'three'),
]
self.assertEqual(self.i.destination(), np('one/three'))
@ -356,42 +355,42 @@ class DestinationTest(_common.TestCase):
self.assertEqual(val, u'')
def test_artist_falls_back_to_albumartist(self):
self.i.artist = ''
self.i.albumartist = 'something'
self.lib.path_formats = [('default', '$artist')]
self.i.artist = u''
self.i.albumartist = u'something'
self.lib.path_formats = [(u'default', u'$artist')]
p = self.i.destination()
self.assertEqual(p.rsplit(os.path.sep, 1)[1], 'something')
self.assertEqual(p.rsplit(os.path.sep, 1)[1], u'something')
def test_albumartist_falls_back_to_artist(self):
self.i.artist = 'trackartist'
self.i.albumartist = ''
self.lib.path_formats = [('default', '$albumartist')]
self.i.artist = u'trackartist'
self.i.albumartist = u''
self.lib.path_formats = [(u'default', u'$albumartist')]
p = self.i.destination()
self.assertEqual(p.rsplit(os.path.sep, 1)[1], 'trackartist')
self.assertEqual(p.rsplit(os.path.sep, 1)[1], u'trackartist')
def test_artist_overrides_albumartist(self):
self.i.artist = 'theartist'
self.i.albumartist = 'something'
self.lib.path_formats = [('default', '$artist')]
self.i.artist = u'theartist'
self.i.albumartist = u'something'
self.lib.path_formats = [(u'default', u'$artist')]
p = self.i.destination()
self.assertEqual(p.rsplit(os.path.sep, 1)[1], 'theartist')
self.assertEqual(p.rsplit(os.path.sep, 1)[1], u'theartist')
def test_albumartist_overrides_artist(self):
self.i.artist = 'theartist'
self.i.albumartist = 'something'
self.lib.path_formats = [('default', '$albumartist')]
self.i.artist = u'theartist'
self.i.albumartist = u'something'
self.lib.path_formats = [(u'default', u'$albumartist')]
p = self.i.destination()
self.assertEqual(p.rsplit(os.path.sep, 1)[1], 'something')
self.assertEqual(p.rsplit(os.path.sep, 1)[1], u'something')
def test_unicode_normalized_nfd_on_mac(self):
instr = unicodedata.normalize('NFC', u'caf\xe9')
self.lib.path_formats = [('default', instr)]
self.lib.path_formats = [(u'default', instr)]
dest = self.i.destination(platform='darwin', fragment=True)
self.assertEqual(dest, unicodedata.normalize('NFD', instr))
def test_unicode_normalized_nfc_on_linux(self):
instr = unicodedata.normalize('NFD', u'caf\xe9')
self.lib.path_formats = [('default', instr)]
self.lib.path_formats = [(u'default', instr)]
dest = self.i.destination(platform='linux2', fragment=True)
self.assertEqual(dest, unicodedata.normalize('NFC', instr))
@ -400,7 +399,7 @@ class DestinationTest(_common.TestCase):
sys.getfilesystemencoding = lambda: 'mbcs'
try:
self.i.title = u'h\u0259d'
self.lib.path_formats = [('default', '$title')]
self.lib.path_formats = [(u'default', u'$title')]
p = self.i.destination()
self.assertFalse(b'?' in p)
# We use UTF-8 to encode Windows paths now.
@ -409,7 +408,7 @@ class DestinationTest(_common.TestCase):
sys.getfilesystemencoding = oldfunc
def test_unicode_extension_in_fragment(self):
self.lib.path_formats = [('default', u'foo')]
self.lib.path_formats = [(u'default', u'foo')]
self.i.path = util.bytestring_path(u'bar.caf\xe9')
dest = self.i.destination(platform='linux2', fragment=True)
self.assertEqual(dest, u'foo.caf\xe9')
@ -418,16 +417,16 @@ class DestinationTest(_common.TestCase):
config['asciify_paths'] = True
self.lib.replacements = [(re.compile(u'"'), u'q')]
self.lib.directory = 'lib'
self.lib.path_formats = [('default', '$title')]
self.lib.path_formats = [(u'default', u'$title')]
self.i.title = u'\u201c\u00f6\u2014\u00cf\u201d'
self.assertEqual(self.i.destination(), np('lib/qo--Iq'))
def test_destination_with_replacements(self):
self.lib.directory = 'base'
self.lib.replacements = [(re.compile(r'a'), u'e')]
self.lib.path_formats = [('default', '$album/$title')]
self.i.title = 'foo'
self.i.album = 'bar'
self.lib.path_formats = [(u'default', u'$album/$title')]
self.i.title = u'foo'
self.i.album = u'bar'
self.assertEqual(self.i.destination(),
np('base/ber/foo'))
@ -435,11 +434,11 @@ class DestinationTest(_common.TestCase):
def test_destination_with_empty_component(self):
self.lib.directory = 'base'
self.lib.replacements = [(re.compile(r'^$'), u'_')]
self.lib.path_formats = [('default', '$album/$artist/$title')]
self.i.title = 'three'
self.i.artist = ''
self.i.albumartist = ''
self.i.album = 'one'
self.lib.path_formats = [(u'default', u'$album/$artist/$title')]
self.i.title = u'three'
self.i.artist = u''
self.i.albumartist = u''
self.i.album = u'one'
self.assertEqual(self.i.destination(),
np('base/one/_/three'))
@ -447,9 +446,9 @@ class DestinationTest(_common.TestCase):
def test_destination_with_empty_final_component(self):
self.lib.directory = 'base'
self.lib.replacements = [(re.compile(r'^$'), u'_')]
self.lib.path_formats = [('default', '$album/$title')]
self.i.title = ''
self.i.album = 'one'
self.lib.path_formats = [(u'default', u'$album/$title')]
self.i.title = u''
self.i.album = u'one'
self.i.path = 'foo.mp3'
self.assertEqual(self.i.destination(),
np('base/one/_.mp3'))
@ -463,11 +462,11 @@ class DestinationTest(_common.TestCase):
# Construct an item whose untruncated path ends with a Y but whose
# truncated version ends with an X.
self.i.title = 'X' * 300 + 'Y'
self.i.title = u'X' * 300 + u'Y'
# The final path should reflect the replacement.
dest = self.i.destination()
self.assertEqual(dest[-2:], 'XZ')
self.assertEqual(dest[-2:], u'XZ')
def test_legalize_path_one_for_many_replacement(self):
# Use a replacement that should always replace the last X in any
@ -478,18 +477,18 @@ class DestinationTest(_common.TestCase):
# Construct an item whose untruncated path ends with a Y but whose
# truncated version ends with an X.
self.i.title = 'X' * 300 + 'Y'
self.i.title = u'X' * 300 + u'Y'
# The final path should ignore the user replacement and create a path
# of the correct length, containing Xs.
dest = self.i.destination()
self.assertEqual(dest[-2:], 'XX')
self.assertEqual(dest[-2:], u'XX')
class ItemFormattedMappingTest(_common.LibTestCase):
def test_formatted_item_value(self):
formatted = self.i.formatted()
self.assertEqual(formatted['artist'], 'the artist')
self.assertEqual(formatted['artist'], u'the artist')
def test_get_unset_field(self):
formatted = self.i.formatted()
@ -502,53 +501,53 @@ class ItemFormattedMappingTest(_common.LibTestCase):
def test_get_method_with_specified_default(self):
formatted = self.i.formatted()
self.assertEqual(formatted.get('other_field', 'default'), 'default')
self.assertEqual(formatted.get('other_field', u'default'), u'default')
def test_item_precedence(self):
album = self.lib.add_album([self.i])
album['artist'] = 'foo'
album['artist'] = u'foo'
album.store()
self.assertNotEqual('foo', self.i.formatted().get('artist'))
self.assertNotEqual(u'foo', self.i.formatted().get('artist'))
def test_album_flex_field(self):
album = self.lib.add_album([self.i])
album['flex'] = 'foo'
album['flex'] = u'foo'
album.store()
self.assertEqual('foo', self.i.formatted().get('flex'))
self.assertEqual(u'foo', self.i.formatted().get('flex'))
def test_album_field_overrides_item_field_for_path(self):
# Make the album inconsistent with the item.
album = self.lib.add_album([self.i])
album.album = 'foo'
album.album = u'foo'
album.store()
self.i.album = 'bar'
self.i.album = u'bar'
self.i.store()
# Ensure the album takes precedence.
formatted = self.i.formatted(for_path=True)
self.assertEqual(formatted['album'], 'foo')
self.assertEqual(formatted['album'], u'foo')
def test_artist_falls_back_to_albumartist(self):
self.i.artist = ''
self.i.artist = u''
formatted = self.i.formatted()
self.assertEqual(formatted['artist'], 'the album artist')
self.assertEqual(formatted['artist'], u'the album artist')
def test_albumartist_falls_back_to_artist(self):
self.i.albumartist = ''
self.i.albumartist = u''
formatted = self.i.formatted()
self.assertEqual(formatted['albumartist'], 'the artist')
self.assertEqual(formatted['albumartist'], u'the artist')
def test_both_artist_and_albumartist_empty(self):
self.i.artist = ''
self.i.albumartist = ''
self.i.artist = u''
self.i.albumartist = u''
formatted = self.i.formatted()
self.assertEqual(formatted['albumartist'], '')
self.assertEqual(formatted['albumartist'], u'')
class PathFormattingMixin(object):
"""Utilities for testing path formatting."""
def _setf(self, fmt):
self.lib.path_formats.insert(0, ('default', fmt))
self.lib.path_formats.insert(0, (u'default', fmt))
def _assert_dest(self, dest, i=None):
if i is None:
@ -563,7 +562,7 @@ class DestinationFunctionTest(_common.TestCase, PathFormattingMixin):
super(DestinationFunctionTest, self).setUp()
self.lib = beets.library.Library(':memory:')
self.lib.directory = '/base'
self.lib.path_formats = [('default', u'path')]
self.lib.path_formats = [(u'default', u'path')]
self.i = item(self.lib)
def tearDown(self):
@ -624,7 +623,7 @@ class DisambiguationTest(_common.TestCase, PathFormattingMixin):
super(DisambiguationTest, self).setUp()
self.lib = beets.library.Library(':memory:')
self.lib.directory = '/base'
self.lib.path_formats = [('default', u'path')]
self.lib.path_formats = [(u'default', u'path')]
self.i1 = item()
self.i1.year = 2001
@ -645,14 +644,14 @@ class DisambiguationTest(_common.TestCase, PathFormattingMixin):
def test_unique_with_default_arguments_uses_albumtype(self):
album2 = self.lib.get_album(self.i1)
album2.albumtype = 'bar'
album2.albumtype = u'bar'
album2.store()
self._setf(u'foo%aunique{}/$title')
self._assert_dest('/base/foo [bar]/the title', self.i1)
def test_unique_expands_to_nothing_for_distinct_albums(self):
album2 = self.lib.get_album(self.i2)
album2.album = 'different album'
album2.album = u'different album'
album2.store()
self._assert_dest('/base/foo/the title', self.i1)
@ -673,7 +672,7 @@ class DisambiguationTest(_common.TestCase, PathFormattingMixin):
album2 = self.lib.get_album(self.i2)
album2.year = 2001
album1 = self.lib.get_album(self.i1)
album1.albumtype = 'foo/bar'
album1.albumtype = u'foo/bar'
album2.store()
album1.store()
self._setf(u'foo%aunique{albumartist album,albumtype}/$title')
@ -698,7 +697,7 @@ class PluginDestinationTest(_common.TestCase):
self.lib = beets.library.Library(':memory:')
self.lib.directory = '/base'
self.lib.path_formats = [('default', u'$artist $foo')]
self.lib.path_formats = [(u'default', u'$artist $foo')]
self.i = item(self.lib)
def tearDown(self):
@ -711,25 +710,25 @@ class PluginDestinationTest(_common.TestCase):
self.assertEqual(the_dest, '/base/' + dest)
def test_undefined_value_not_substituted(self):
self._assert_dest('the artist $foo')
self._assert_dest(u'the artist $foo')
def test_plugin_value_not_substituted(self):
self._tv_map = {
'foo': 'bar',
}
self._assert_dest('the artist bar')
self._assert_dest(u'the artist bar')
def test_plugin_value_overrides_attribute(self):
self._tv_map = {
'artist': 'bar',
}
self._assert_dest('bar $foo')
self._assert_dest(u'bar $foo')
def test_plugin_value_sanitized(self):
self._tv_map = {
'foo': 'bar/baz',
}
self._assert_dest('the artist bar_baz')
self._assert_dest(u'the artist bar_baz')
class AlbumInfoTest(_common.TestCase):
@ -766,7 +765,7 @@ class AlbumInfoTest(_common.TestCase):
def test_individual_tracks_have_no_albuminfo(self):
i2 = item()
i2.album = 'aTotallyDifferentAlbum'
i2.album = u'aTotallyDifferentAlbum'
self.lib.add(i2)
ai = self.lib.get_album(i2)
self.assertEqual(ai, None)
@ -782,29 +781,29 @@ class AlbumInfoTest(_common.TestCase):
if i.id == self.i.id:
break
else:
self.fail("item not found")
self.fail(u"item not found")
def test_albuminfo_changes_affect_items(self):
ai = self.lib.get_album(self.i)
ai.album = 'myNewAlbum'
ai.album = u'myNewAlbum'
ai.store()
i = self.lib.items()[0]
self.assertEqual(i.album, 'myNewAlbum')
self.assertEqual(i.album, u'myNewAlbum')
def test_albuminfo_change_albumartist_changes_items(self):
ai = self.lib.get_album(self.i)
ai.albumartist = 'myNewArtist'
ai.albumartist = u'myNewArtist'
ai.store()
i = self.lib.items()[0]
self.assertEqual(i.albumartist, 'myNewArtist')
self.assertNotEqual(i.artist, 'myNewArtist')
self.assertEqual(i.albumartist, u'myNewArtist')
self.assertNotEqual(i.artist, u'myNewArtist')
def test_albuminfo_change_artist_does_not_change_items(self):
ai = self.lib.get_album(self.i)
ai.artist = 'myNewArtist'
ai.artist = u'myNewArtist'
ai.store()
i = self.lib.items()[0]
self.assertNotEqual(i.artist, 'myNewArtist')
self.assertNotEqual(i.artist, u'myNewArtist')
def test_albuminfo_remove_removes_items(self):
item_id = self.i.id
@ -821,7 +820,7 @@ class AlbumInfoTest(_common.TestCase):
def test_noop_albuminfo_changes_affect_items(self):
i = self.lib.items()[0]
i.album = 'foobar'
i.album = u'foobar'
i.store()
ai = self.lib.get_album(self.i)
ai.album = ai.album
@ -882,7 +881,7 @@ class PathStringTest(_common.TestCase):
self.assert_(isinstance(i.path, bytes))
def test_special_chars_preserved_in_database(self):
path = 'b\xe1r'.encode('utf8')
path = u'b\xe1r'.encode('utf8')
self.i.path = path
self.i.store()
i = list(self.lib.items())[0]
@ -890,7 +889,7 @@ class PathStringTest(_common.TestCase):
def test_special_char_path_added_to_database(self):
self.i.remove()
path = 'b\xe1r'.encode('utf8')
path = u'b\xe1r'.encode('utf8')
i = item()
i.path = path
self.lib.add(i)
@ -962,16 +961,16 @@ class MtimeTest(_common.TestCase):
self.assertGreaterEqual(self.i.mtime, self._mtime())
def test_mtime_reset_on_db_modify(self):
self.i.title = 'something else'
self.i.title = u'something else'
self.assertLess(self.i.mtime, self._mtime())
def test_mtime_up_to_date_after_write(self):
self.i.title = 'something else'
self.i.title = u'something else'
self.i.write()
self.assertGreaterEqual(self.i.mtime, self._mtime())
def test_mtime_up_to_date_after_read(self):
self.i.title = 'something else'
self.i.title = u'something else'
self.i.read()
self.assertGreaterEqual(self.i.mtime, self._mtime())
@ -996,19 +995,19 @@ class TemplateTest(_common.LibTestCase):
def test_year_formatted_in_template(self):
self.i.year = 123
self.i.store()
self.assertEqual(self.i.evaluate_template('$year'), '0123')
self.assertEqual(self.i.evaluate_template('$year'), u'0123')
def test_album_flexattr_appears_in_item_template(self):
self.album = self.lib.add_album([self.i])
self.album.foo = 'baz'
self.album.foo = u'baz'
self.album.store()
self.assertEqual(self.i.evaluate_template('$foo'), 'baz')
self.assertEqual(self.i.evaluate_template('$foo'), u'baz')
def test_album_and_item_format(self):
config['format_album'] = u'foö $foo'
album = beets.library.Album()
album.foo = 'bar'
album.tagada = 'togodo'
album.foo = u'bar'
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")
@ -1016,10 +1015,10 @@ class TemplateTest(_common.LibTestCase):
config['format_item'] = 'bar $foo'
item = beets.library.Item()
item.foo = 'bar'
item.tagada = 'togodo'
self.assertEqual("{0}".format(item), "bar bar")
self.assertEqual("{0:$tagada}".format(item), "togodo")
item.foo = u'bar'
item.tagada = u'togodo'
self.assertEqual("{0}".format(item), u"bar bar")
self.assertEqual("{0:$tagada}".format(item), u"togodo")
class UnicodePathTest(_common.LibTestCase):
@ -1079,7 +1078,7 @@ class WriteTest(unittest.TestCase, TestHelper):
# Since `date` is not a MediaField, this should do nothing.
item = self.add_item_fixture()
clean_year = item.year
item.date = 'foo'
item.date = u'foo'
item.write()
self.assertEqual(MediaFile(item.path).year, clean_year)
@ -1119,7 +1118,7 @@ class FilesizeTest(unittest.TestCase, TestHelper):
class ParseQueryTest(unittest.TestCase):
def test_parse_invalid_query_string(self):
with self.assertRaises(beets.dbcore.InvalidQueryError) as raised:
beets.library.parse_query_string('foo"', None)
beets.library.parse_query_string(u'foo"', None)
self.assertIsInstance(raised.exception,
beets.dbcore.query.ParsingError)
@ -1139,9 +1138,9 @@ class LibraryFieldTypesTest(unittest.TestCase):
self.assertEqual(time_local, t.format(123456789))
# parse
self.assertEqual(123456789.0, t.parse(time_local))
self.assertEqual(123456789.0, t.parse('123456789.0'))
self.assertEqual(t.null, t.parse('not123456789.0'))
self.assertEqual(t.null, t.parse('1973-11-29'))
self.assertEqual(123456789.0, t.parse(u'123456789.0'))
self.assertEqual(t.null, t.parse(u'not123456789.0'))
self.assertEqual(t.null, t.parse(u'1973-11-29'))
def test_pathtype(self):
t = beets.library.PathType()
@ -1157,23 +1156,23 @@ class LibraryFieldTypesTest(unittest.TestCase):
t = beets.library.MusicalKey()
# parse
self.assertEqual('C#m', t.parse('c#m'))
self.assertEqual('Gm', t.parse('g minor'))
self.assertEqual('Not c#m', t.parse('not C#m'))
self.assertEqual(u'C#m', t.parse(u'c#m'))
self.assertEqual(u'Gm', t.parse(u'g minor'))
self.assertEqual(u'Not c#m', t.parse(u'not C#m'))
def test_durationtype(self):
t = beets.library.DurationType()
# format
self.assertEqual('1:01', t.format(61.23))
self.assertEqual('60:01', t.format(3601.23))
self.assertEqual('0:00', t.format(None))
self.assertEqual(u'1:01', t.format(61.23))
self.assertEqual(u'60:01', t.format(3601.23))
self.assertEqual(u'0:00', t.format(None))
# parse
self.assertEqual(61.0, t.parse('1:01'))
self.assertEqual(61.23, t.parse('61.23'))
self.assertEqual(3601.0, t.parse('60:01'))
self.assertEqual(t.null, t.parse('1:00:01'))
self.assertEqual(t.null, t.parse('not61.23'))
self.assertEqual(61.0, t.parse(u'1:01'))
self.assertEqual(61.23, t.parse(u'61.23'))
self.assertEqual(3601.0, t.parse(u'60:01'))
self.assertEqual(t.null, t.parse(u'1:00:01'))
self.assertEqual(t.null, t.parse(u'not61.23'))
# config format_raw_length
beets.config['format_raw_length'] = True
self.assertEqual(61.23, t.format(61.23))

Some files were not shown because too many files have changed in this diff Show more