mirror of
https://github.com/beetbox/beets.git
synced 2026-01-15 20:51:38 +01:00
Merge pull request #1247 from brunal/future
Use all __future__ imports in beets core Conflicts: beetsplug/web/__init__.py test/test_embedart.py
This commit is contained in:
commit
b8dab9cf9f
119 changed files with 736 additions and 398 deletions
|
|
@ -12,6 +12,8 @@
|
|||
# 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
|
||||
|
||||
__version__ = '1.3.11'
|
||||
__author__ = 'Adrian Sampson <adrian@radbox.org>'
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
"""Facilities for automatically determining files' correct metadata.
|
||||
"""
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from beets import logging
|
||||
from beets import config
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@
|
|||
# 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 collections import namedtuple
|
||||
import re
|
||||
|
||||
|
|
@ -109,7 +112,7 @@ class AlbumInfo(object):
|
|||
'catalognum', 'script', 'language', 'country',
|
||||
'albumstatus', 'albumdisambig', 'artist_credit', 'media']:
|
||||
value = getattr(self, fld)
|
||||
if isinstance(value, str):
|
||||
if isinstance(value, bytes):
|
||||
setattr(self, fld, value.decode(codec, 'ignore'))
|
||||
|
||||
if self.tracks:
|
||||
|
|
@ -168,7 +171,7 @@ class TrackInfo(object):
|
|||
for fld in ['title', 'artist', 'medium', 'artist_sort', 'disctitle',
|
||||
'artist_credit', 'media']:
|
||||
value = getattr(self, fld)
|
||||
if isinstance(value, str):
|
||||
if isinstance(value, bytes):
|
||||
setattr(self, fld, value.decode(codec, 'ignore'))
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@
|
|||
"""Matches existing metadata with canonical information to identify
|
||||
releases and tracks.
|
||||
"""
|
||||
from __future__ import division
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import datetime
|
||||
import re
|
||||
|
|
@ -405,7 +407,7 @@ def tag_album(items, search_artist=None, search_album=None,
|
|||
if id_info:
|
||||
_add_candidate(items, candidates, id_info)
|
||||
rec = _recommendation(candidates.values())
|
||||
log.debug(u'Album ID match recommendation is {0}', str(rec))
|
||||
log.debug(u'Album ID match recommendation is {0}', rec)
|
||||
if candidates and not config['import']['timid']:
|
||||
# If we have a very good MBID match, return immediately.
|
||||
# Otherwise, this match will compete against metadata-based
|
||||
|
|
@ -424,7 +426,7 @@ def tag_album(items, search_artist=None, search_album=None,
|
|||
va_likely = ((not consensus['artist']) or
|
||||
(search_artist.lower() in VA_ARTISTS) or
|
||||
any(item.comp for item in items))
|
||||
log.debug(u'Album might be VA: {0}', str(va_likely))
|
||||
log.debug(u'Album might be VA: {0}', va_likely)
|
||||
|
||||
# Get the results from the data sources.
|
||||
search_cands = hooks.album_candidates(items, search_artist,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
"""Searches for albums in the MusicBrainz database.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import musicbrainzngs
|
||||
import re
|
||||
import traceback
|
||||
|
|
@ -316,7 +319,7 @@ def match_album(artist, album, tracks=None):
|
|||
# Various Artists search.
|
||||
criteria['arid'] = VARIOUS_ARTISTS_ID
|
||||
if tracks is not None:
|
||||
criteria['tracks'] = str(tracks)
|
||||
criteria['tracks'] = bytes(tracks)
|
||||
|
||||
# Abort if we have no search terms.
|
||||
if not any(criteria.itervalues()):
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
"""DBCore is an abstract database package that forms the basis for beets'
|
||||
Library.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
from .db import Model, Database
|
||||
from .query import Query, FieldQuery, MatchQuery, AndQuery, OrQuery
|
||||
from .types import Type
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
"""The central Model and Database constructs for DBCore.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import time
|
||||
import os
|
||||
from collections import defaultdict
|
||||
|
|
@ -545,13 +548,13 @@ class Results(object):
|
|||
'SELECT * FROM {0} WHERE entity_id=?'.format(
|
||||
self.model_class._flex_table
|
||||
),
|
||||
(row['id'],)
|
||||
(row[b'id'],)
|
||||
)
|
||||
|
||||
cols = dict(row)
|
||||
values = dict((k, v) for (k, v) in cols.items()
|
||||
if not k[:4] == 'flex')
|
||||
flex_values = dict((row['key'], row['value']) for row in flex_rows)
|
||||
flex_values = dict((row[b'key'], row[b'value']) for row in flex_rows)
|
||||
|
||||
# Construct the Python object
|
||||
obj = self.model_class._awaken(self.db, values, flex_values)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
"""The Query type hierarchy for DBCore.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import re
|
||||
from operator import attrgetter
|
||||
from beets import util
|
||||
|
|
@ -178,7 +181,7 @@ class BooleanQuery(MatchQuery):
|
|||
|
||||
class BytesQuery(MatchQuery):
|
||||
"""Match a raw bytes field (i.e., a path). This is a necessary hack
|
||||
to work around the `sqlite3` module's desire to treat `str` and
|
||||
to work around the `sqlite3` module's desire to treat `bytes` and
|
||||
`unicode` equivalently in Python 2. Always use this query instead of
|
||||
`MatchQuery` when matching on BLOB values.
|
||||
"""
|
||||
|
|
@ -423,7 +426,7 @@ class Period(object):
|
|||
precision (a string, one of "year", "month", or "day").
|
||||
"""
|
||||
if precision not in Period.precisions:
|
||||
raise ValueError('Invalid precision ' + str(precision))
|
||||
raise ValueError('Invalid precision {0}'.format(precision))
|
||||
self.date = date
|
||||
self.precision = precision
|
||||
|
||||
|
|
@ -463,7 +466,7 @@ class Period(object):
|
|||
elif 'day' == precision:
|
||||
return date + timedelta(days=1)
|
||||
else:
|
||||
raise ValueError('unhandled precision ' + str(precision))
|
||||
raise ValueError('unhandled precision {0}'.format(precision))
|
||||
|
||||
|
||||
class DateInterval(object):
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
"""Parsing of strings into DBCore queries.
|
||||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import re
|
||||
import itertools
|
||||
from . import query
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
"""Representation of type information for DBCore model fields.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from . import query
|
||||
from beets.util import str2bool
|
||||
|
||||
|
|
|
|||
|
|
@ -12,10 +12,12 @@
|
|||
# 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)
|
||||
|
||||
"""Provides the basic, interface-agnostic workflow for importing and
|
||||
autotagging music files.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import re
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
"""The core data store and collection logic for beets.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import os
|
||||
import sys
|
||||
import shlex
|
||||
|
|
@ -42,7 +45,7 @@ class PathQuery(dbcore.FieldQuery):
|
|||
"""A query that matches all items under a given path."""
|
||||
|
||||
escape_re = re.compile(r'[\\_%]')
|
||||
escape_char = '\\'
|
||||
escape_char = b'\\'
|
||||
|
||||
def __init__(self, field, pattern, fast=True):
|
||||
super(PathQuery, self).__init__(field, pattern, fast)
|
||||
|
|
@ -50,7 +53,7 @@ class PathQuery(dbcore.FieldQuery):
|
|||
# Match the path as a single file.
|
||||
self.file_path = util.bytestring_path(util.normpath(pattern))
|
||||
# As a directory (prefix).
|
||||
self.dir_path = util.bytestring_path(os.path.join(self.file_path, ''))
|
||||
self.dir_path = util.bytestring_path(os.path.join(self.file_path, b''))
|
||||
|
||||
def match(self, item):
|
||||
return (item.path == self.file_path) or \
|
||||
|
|
@ -59,7 +62,7 @@ class PathQuery(dbcore.FieldQuery):
|
|||
def clause(self):
|
||||
escape = lambda m: self.escape_char + m.group(0)
|
||||
dir_pattern = self.escape_re.sub(escape, self.dir_path)
|
||||
dir_pattern = buffer(dir_pattern + '%')
|
||||
dir_pattern = buffer(dir_pattern + b'%')
|
||||
file_blob = buffer(self.file_path)
|
||||
return '({0} = ?) || ({0} LIKE ? ESCAPE ?)'.format(self.field), \
|
||||
(file_blob, dir_pattern, self.escape_char)
|
||||
|
|
@ -118,7 +121,7 @@ class PathType(types.Type):
|
|||
return self.normalize(sql_value)
|
||||
|
||||
def to_sql(self, value):
|
||||
if isinstance(value, str):
|
||||
if isinstance(value, bytes):
|
||||
value = buffer(value)
|
||||
return value
|
||||
|
||||
|
|
@ -390,7 +393,7 @@ class Item(LibModel):
|
|||
_search_fields = ('artist', 'title', 'comments',
|
||||
'album', 'albumartist', 'genre')
|
||||
|
||||
_media_fields = set(MediaFile.readable_fields()) \
|
||||
_media_fields = set(f.decode('utf8') for f in MediaFile.readable_fields()) \
|
||||
.intersection(_fields.keys())
|
||||
"""Set of item fields that are backed by `MediaFile` fields.
|
||||
|
||||
|
|
@ -429,7 +432,7 @@ class Item(LibModel):
|
|||
if isinstance(value, unicode):
|
||||
value = bytestring_path(value)
|
||||
elif isinstance(value, buffer):
|
||||
value = str(value)
|
||||
value = bytes(value)
|
||||
|
||||
if key in MediaFile.fields():
|
||||
self.mtime = 0 # Reset mtime on dirty.
|
||||
|
|
@ -532,7 +535,7 @@ class Item(LibModel):
|
|||
self.write(path)
|
||||
return True
|
||||
except FileOperationError as exc:
|
||||
log.error(str(exc))
|
||||
log.error("{0}", exc)
|
||||
return False
|
||||
|
||||
def try_sync(self, write=None):
|
||||
|
|
@ -1196,7 +1199,7 @@ class DefaultTemplateFunctions(object):
|
|||
additional context to the functions -- specifically, the Item being
|
||||
evaluated.
|
||||
"""
|
||||
_prefix = 'tmpl_'
|
||||
_prefix = b'tmpl_'
|
||||
|
||||
def __init__(self, item=None, lib=None):
|
||||
"""Paramaterize the functions. If `item` or `lib` is None, then
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@ that when getLogger(name) instantiates a logger that logger uses
|
|||
{}-style formatting.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from copy import copy
|
||||
from logging import * # noqa
|
||||
import sys
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@ 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)
|
||||
|
||||
import mutagen
|
||||
import mutagen.mp3
|
||||
import mutagen.oggopus
|
||||
|
|
@ -141,7 +144,7 @@ def _safe_cast(out_type, val):
|
|||
return False
|
||||
|
||||
elif out_type == unicode:
|
||||
if isinstance(val, str):
|
||||
if isinstance(val, bytes):
|
||||
return val.decode('utf8', 'ignore')
|
||||
elif isinstance(val, unicode):
|
||||
return val
|
||||
|
|
@ -176,15 +179,15 @@ def _unpack_asf_image(data):
|
|||
of exceptions (out-of-bounds, etc.). We should clean this up
|
||||
sometime so that the failure modes are well-defined.
|
||||
"""
|
||||
type, size = struct.unpack_from("<bi", data)
|
||||
type, size = struct.unpack_from(b'<bi', data)
|
||||
pos = 5
|
||||
mime = ""
|
||||
while data[pos:pos + 2] != "\x00\x00":
|
||||
while data[pos:pos + 2] != b'\x00\x00':
|
||||
mime += data[pos:pos + 2]
|
||||
pos += 2
|
||||
pos += 2
|
||||
description = ""
|
||||
while data[pos:pos + 2] != "\x00\x00":
|
||||
while data[pos:pos + 2] != b'\x00\x00':
|
||||
description += data[pos:pos + 2]
|
||||
pos += 2
|
||||
pos += 2
|
||||
|
|
@ -196,9 +199,9 @@ def _unpack_asf_image(data):
|
|||
def _pack_asf_image(mime, data, type=3, description=""):
|
||||
"""Pack image data for a WM/Picture tag.
|
||||
"""
|
||||
tag_data = struct.pack("<bi", type, len(data))
|
||||
tag_data += mime.encode("utf-16-le") + "\x00\x00"
|
||||
tag_data += description.encode("utf-16-le") + "\x00\x00"
|
||||
tag_data = struct.pack(b'<bi', type, len(data))
|
||||
tag_data += mime.encode("utf-16-le") + b'\x00\x00'
|
||||
tag_data += description.encode("utf-16-le") + b'\x00\x00'
|
||||
tag_data += data
|
||||
return tag_data
|
||||
|
||||
|
|
@ -213,7 +216,7 @@ def _sc_decode(soundcheck):
|
|||
# characters of ASCII hex preceded by a space.
|
||||
try:
|
||||
soundcheck = soundcheck.replace(' ', '').decode('hex')
|
||||
soundcheck = struct.unpack('!iiiiiiiiii', soundcheck)
|
||||
soundcheck = struct.unpack(b'!iiiiiiiiii', soundcheck)
|
||||
except (struct.error, TypeError, UnicodeEncodeError):
|
||||
# SoundCheck isn't in the format we expect, so return default
|
||||
# values.
|
||||
|
|
@ -399,8 +402,9 @@ class StorageStyle(object):
|
|||
self.float_places = float_places
|
||||
|
||||
# Convert suffix to correct string type.
|
||||
if self.suffix and self.as_type is unicode:
|
||||
self.suffix = self.as_type(self.suffix)
|
||||
if self.suffix and self.as_type is unicode \
|
||||
and not isinstance(self.suffix, unicode):
|
||||
self.suffix = self.suffix.decode('utf8')
|
||||
|
||||
# Getter.
|
||||
|
||||
|
|
@ -451,7 +455,7 @@ class StorageStyle(object):
|
|||
if isinstance(value, bool):
|
||||
# Store bools as 1/0 instead of True/False.
|
||||
value = unicode(int(bool(value)))
|
||||
elif isinstance(value, str):
|
||||
elif isinstance(value, bytes):
|
||||
value = value.decode('utf8', 'ignore')
|
||||
else:
|
||||
value = unicode(value)
|
||||
|
|
@ -564,7 +568,7 @@ class MP4StorageStyle(StorageStyle):
|
|||
|
||||
def serialize(self, value):
|
||||
value = super(MP4StorageStyle, self).serialize(value)
|
||||
if self.key.startswith('----:') and isinstance(value, unicode):
|
||||
if self.key.startswith(b'----:') and isinstance(value, unicode):
|
||||
value = value.encode('utf8')
|
||||
return value
|
||||
|
||||
|
|
@ -639,7 +643,7 @@ class MP4ImageStorageStyle(MP4ListStorageStyle):
|
|||
"""Store images as MPEG-4 image atoms. Values are `Image` objects.
|
||||
"""
|
||||
def __init__(self, **kwargs):
|
||||
super(MP4ImageStorageStyle, self).__init__(key='covr', **kwargs)
|
||||
super(MP4ImageStorageStyle, self).__init__(key=b'covr', **kwargs)
|
||||
|
||||
def deserialize(self, data):
|
||||
return Image(data)
|
||||
|
|
@ -739,7 +743,7 @@ class MP3DescStorageStyle(MP3StorageStyle):
|
|||
# need to make a new frame?
|
||||
if not found:
|
||||
frame = mutagen.id3.Frames[self.key](
|
||||
desc=str(self.description),
|
||||
desc=bytes(self.description),
|
||||
text=value,
|
||||
encoding=3
|
||||
)
|
||||
|
|
@ -812,7 +816,7 @@ class MP3ImageStorageStyle(ListStorageStyle, MP3StorageStyle):
|
|||
"""
|
||||
def __init__(self):
|
||||
super(MP3ImageStorageStyle, self).__init__(key='APIC')
|
||||
self.as_type = str
|
||||
self.as_type = bytes
|
||||
|
||||
def deserialize(self, apic_frame):
|
||||
"""Convert APIC frame into Image."""
|
||||
|
|
@ -881,7 +885,7 @@ class VorbisImageStorageStyle(ListStorageStyle):
|
|||
super(VorbisImageStorageStyle, self).__init__(
|
||||
key='metadata_block_picture'
|
||||
)
|
||||
self.as_type = str
|
||||
self.as_type = bytes
|
||||
|
||||
def fetch(self, mutagen_file):
|
||||
images = []
|
||||
|
|
@ -994,7 +998,7 @@ class APEv2ImageStorageStyle(ListStorageStyle):
|
|||
for cover_type, cover_tag in self.TAG_NAMES.items():
|
||||
try:
|
||||
frame = mutagen_file[cover_tag]
|
||||
text_delimiter_index = frame.value.find('\x00')
|
||||
text_delimiter_index = frame.value.find(b'\x00')
|
||||
comment = frame.value[0:text_delimiter_index] \
|
||||
if text_delimiter_index > 0 else None
|
||||
image_data = frame.value[text_delimiter_index + 1:]
|
||||
|
|
@ -1011,7 +1015,7 @@ class APEv2ImageStorageStyle(ListStorageStyle):
|
|||
for image in values:
|
||||
image_type = image.type or ImageType.other
|
||||
comment = image.desc or ''
|
||||
image_data = comment + "\x00" + image.data
|
||||
image_data = comment.encode('utf8') + b'\x00' + image.data
|
||||
cover_tag = self.TAG_NAMES[image_type]
|
||||
mutagen_file[cover_tag] = image_data
|
||||
|
||||
|
|
@ -1045,7 +1049,7 @@ class MediaField(object):
|
|||
getting this property.
|
||||
|
||||
"""
|
||||
self.out_type = kwargs.get('out_type', unicode)
|
||||
self.out_type = kwargs.get(b'out_type', unicode)
|
||||
self._styles = styles
|
||||
|
||||
def styles(self, mutagen_file):
|
||||
|
|
@ -1109,7 +1113,7 @@ class ListMediaField(MediaField):
|
|||
"""Returns a ``MediaField`` descriptor that gets and sets the
|
||||
first item.
|
||||
"""
|
||||
options = {'out_type': self.out_type}
|
||||
options = {b'out_type': self.out_type}
|
||||
return MediaField(*self._styles, **options)
|
||||
|
||||
|
||||
|
|
@ -1130,7 +1134,7 @@ class DateField(MediaField):
|
|||
storage styles do not return a value.
|
||||
"""
|
||||
super(DateField, self).__init__(*date_styles)
|
||||
year_style = kwargs.get('year', None)
|
||||
year_style = kwargs.get(b'year', None)
|
||||
if year_style:
|
||||
self._year_field = MediaField(*year_style)
|
||||
|
||||
|
|
@ -1476,25 +1480,25 @@ class MediaFile(object):
|
|||
|
||||
title = MediaField(
|
||||
MP3StorageStyle('TIT2'),
|
||||
MP4StorageStyle("\xa9nam"),
|
||||
MP4StorageStyle(b"\xa9nam"),
|
||||
StorageStyle('TITLE'),
|
||||
ASFStorageStyle('Title'),
|
||||
)
|
||||
artist = MediaField(
|
||||
MP3StorageStyle('TPE1'),
|
||||
MP4StorageStyle("\xa9ART"),
|
||||
MP4StorageStyle(b"\xa9ART"),
|
||||
StorageStyle('ARTIST'),
|
||||
ASFStorageStyle('Author'),
|
||||
)
|
||||
album = MediaField(
|
||||
MP3StorageStyle('TALB'),
|
||||
MP4StorageStyle("\xa9alb"),
|
||||
MP4StorageStyle(b"\xa9alb"),
|
||||
StorageStyle('ALBUM'),
|
||||
ASFStorageStyle('WM/AlbumTitle'),
|
||||
)
|
||||
genres = ListMediaField(
|
||||
MP3ListStorageStyle('TCON'),
|
||||
MP4ListStorageStyle("\xa9gen"),
|
||||
MP4ListStorageStyle(b"\xa9gen"),
|
||||
ListStorageStyle('GENRE'),
|
||||
ASFStorageStyle('WM/Genre'),
|
||||
)
|
||||
|
|
@ -1502,19 +1506,19 @@ class MediaFile(object):
|
|||
|
||||
composer = MediaField(
|
||||
MP3StorageStyle('TCOM'),
|
||||
MP4StorageStyle("\xa9wrt"),
|
||||
MP4StorageStyle(b"\xa9wrt"),
|
||||
StorageStyle('COMPOSER'),
|
||||
ASFStorageStyle('WM/Composer'),
|
||||
)
|
||||
grouping = MediaField(
|
||||
MP3StorageStyle('TIT1'),
|
||||
MP4StorageStyle("\xa9grp"),
|
||||
MP4StorageStyle(b"\xa9grp"),
|
||||
StorageStyle('GROUPING'),
|
||||
ASFStorageStyle('WM/ContentGroupDescription'),
|
||||
)
|
||||
track = MediaField(
|
||||
MP3SlashPackStorageStyle('TRCK', pack_pos=0),
|
||||
MP4TupleStorageStyle('trkn', index=0),
|
||||
MP4TupleStorageStyle(b'trkn', index=0),
|
||||
StorageStyle('TRACK'),
|
||||
StorageStyle('TRACKNUMBER'),
|
||||
ASFStorageStyle('WM/TrackNumber'),
|
||||
|
|
@ -1522,7 +1526,7 @@ class MediaFile(object):
|
|||
)
|
||||
tracktotal = MediaField(
|
||||
MP3SlashPackStorageStyle('TRCK', pack_pos=1),
|
||||
MP4TupleStorageStyle('trkn', index=1),
|
||||
MP4TupleStorageStyle(b'trkn', index=1),
|
||||
StorageStyle('TRACKTOTAL'),
|
||||
StorageStyle('TRACKC'),
|
||||
StorageStyle('TOTALTRACKS'),
|
||||
|
|
@ -1531,7 +1535,7 @@ class MediaFile(object):
|
|||
)
|
||||
disc = MediaField(
|
||||
MP3SlashPackStorageStyle('TPOS', pack_pos=0),
|
||||
MP4TupleStorageStyle('disk', index=0),
|
||||
MP4TupleStorageStyle(b'disk', index=0),
|
||||
StorageStyle('DISC'),
|
||||
StorageStyle('DISCNUMBER'),
|
||||
ASFStorageStyle('WM/PartOfSet'),
|
||||
|
|
@ -1539,7 +1543,7 @@ class MediaFile(object):
|
|||
)
|
||||
disctotal = MediaField(
|
||||
MP3SlashPackStorageStyle('TPOS', pack_pos=1),
|
||||
MP4TupleStorageStyle('disk', index=1),
|
||||
MP4TupleStorageStyle(b'disk', index=1),
|
||||
StorageStyle('DISCTOTAL'),
|
||||
StorageStyle('DISCC'),
|
||||
StorageStyle('TOTALDISCS'),
|
||||
|
|
@ -1548,13 +1552,13 @@ class MediaFile(object):
|
|||
)
|
||||
lyrics = MediaField(
|
||||
MP3DescStorageStyle(key='USLT'),
|
||||
MP4StorageStyle("\xa9lyr"),
|
||||
MP4StorageStyle(b"\xa9lyr"),
|
||||
StorageStyle('LYRICS'),
|
||||
ASFStorageStyle('WM/Lyrics'),
|
||||
)
|
||||
comments = MediaField(
|
||||
MP3DescStorageStyle(key='COMM'),
|
||||
MP4StorageStyle("\xa9cmt"),
|
||||
MP4StorageStyle(b"\xa9cmt"),
|
||||
StorageStyle('DESCRIPTION'),
|
||||
StorageStyle('COMMENT'),
|
||||
ASFStorageStyle('WM/Comments'),
|
||||
|
|
@ -1562,111 +1566,111 @@ class MediaFile(object):
|
|||
)
|
||||
bpm = MediaField(
|
||||
MP3StorageStyle('TBPM'),
|
||||
MP4StorageStyle('tmpo', as_type=int),
|
||||
MP4StorageStyle(b'tmpo', as_type=int),
|
||||
StorageStyle('BPM'),
|
||||
ASFStorageStyle('WM/BeatsPerMinute'),
|
||||
out_type=int,
|
||||
)
|
||||
comp = MediaField(
|
||||
MP3StorageStyle('TCMP'),
|
||||
MP4BoolStorageStyle('cpil'),
|
||||
MP4BoolStorageStyle(b'cpil'),
|
||||
StorageStyle('COMPILATION'),
|
||||
ASFStorageStyle('WM/IsCompilation', as_type=bool),
|
||||
out_type=bool,
|
||||
)
|
||||
albumartist = MediaField(
|
||||
MP3StorageStyle('TPE2'),
|
||||
MP4StorageStyle('aART'),
|
||||
MP4StorageStyle(b'aART'),
|
||||
StorageStyle('ALBUM ARTIST'),
|
||||
StorageStyle('ALBUMARTIST'),
|
||||
ASFStorageStyle('WM/AlbumArtist'),
|
||||
)
|
||||
albumtype = MediaField(
|
||||
MP3DescStorageStyle(u'MusicBrainz Album Type'),
|
||||
MP4StorageStyle('----:com.apple.iTunes:MusicBrainz Album Type'),
|
||||
MP4StorageStyle(b'----:com.apple.iTunes:MusicBrainz Album Type'),
|
||||
StorageStyle('MUSICBRAINZ_ALBUMTYPE'),
|
||||
ASFStorageStyle('MusicBrainz/Album Type'),
|
||||
)
|
||||
label = MediaField(
|
||||
MP3StorageStyle('TPUB'),
|
||||
MP4StorageStyle('----:com.apple.iTunes:Label'),
|
||||
MP4StorageStyle('----:com.apple.iTunes:publisher'),
|
||||
MP4StorageStyle(b'----:com.apple.iTunes:Label'),
|
||||
MP4StorageStyle(b'----:com.apple.iTunes:publisher'),
|
||||
StorageStyle('LABEL'),
|
||||
StorageStyle('PUBLISHER'), # Traktor
|
||||
ASFStorageStyle('WM/Publisher'),
|
||||
)
|
||||
artist_sort = MediaField(
|
||||
MP3StorageStyle('TSOP'),
|
||||
MP4StorageStyle("soar"),
|
||||
MP4StorageStyle(b"soar"),
|
||||
StorageStyle('ARTISTSORT'),
|
||||
ASFStorageStyle('WM/ArtistSortOrder'),
|
||||
)
|
||||
albumartist_sort = MediaField(
|
||||
MP3DescStorageStyle(u'ALBUMARTISTSORT'),
|
||||
MP4StorageStyle("soaa"),
|
||||
MP4StorageStyle(b"soaa"),
|
||||
StorageStyle('ALBUMARTISTSORT'),
|
||||
ASFStorageStyle('WM/AlbumArtistSortOrder'),
|
||||
)
|
||||
asin = MediaField(
|
||||
MP3DescStorageStyle(u'ASIN'),
|
||||
MP4StorageStyle("----:com.apple.iTunes:ASIN"),
|
||||
MP4StorageStyle(b"----:com.apple.iTunes:ASIN"),
|
||||
StorageStyle('ASIN'),
|
||||
ASFStorageStyle('MusicBrainz/ASIN'),
|
||||
)
|
||||
catalognum = MediaField(
|
||||
MP3DescStorageStyle(u'CATALOGNUMBER'),
|
||||
MP4StorageStyle("----:com.apple.iTunes:CATALOGNUMBER"),
|
||||
MP4StorageStyle(b"----:com.apple.iTunes:CATALOGNUMBER"),
|
||||
StorageStyle('CATALOGNUMBER'),
|
||||
ASFStorageStyle('WM/CatalogNo'),
|
||||
)
|
||||
disctitle = MediaField(
|
||||
MP3StorageStyle('TSST'),
|
||||
MP4StorageStyle("----:com.apple.iTunes:DISCSUBTITLE"),
|
||||
MP4StorageStyle(b"----:com.apple.iTunes:DISCSUBTITLE"),
|
||||
StorageStyle('DISCSUBTITLE'),
|
||||
ASFStorageStyle('WM/SetSubTitle'),
|
||||
)
|
||||
encoder = MediaField(
|
||||
MP3StorageStyle('TENC'),
|
||||
MP4StorageStyle("\xa9too"),
|
||||
MP4StorageStyle(b"\xa9too"),
|
||||
StorageStyle('ENCODEDBY'),
|
||||
StorageStyle('ENCODER'),
|
||||
ASFStorageStyle('WM/EncodedBy'),
|
||||
)
|
||||
script = MediaField(
|
||||
MP3DescStorageStyle(u'Script'),
|
||||
MP4StorageStyle("----:com.apple.iTunes:SCRIPT"),
|
||||
MP4StorageStyle(b"----:com.apple.iTunes:SCRIPT"),
|
||||
StorageStyle('SCRIPT'),
|
||||
ASFStorageStyle('WM/Script'),
|
||||
)
|
||||
language = MediaField(
|
||||
MP3StorageStyle('TLAN'),
|
||||
MP4StorageStyle("----:com.apple.iTunes:LANGUAGE"),
|
||||
MP4StorageStyle(b"----:com.apple.iTunes:LANGUAGE"),
|
||||
StorageStyle('LANGUAGE'),
|
||||
ASFStorageStyle('WM/Language'),
|
||||
)
|
||||
country = MediaField(
|
||||
MP3DescStorageStyle('MusicBrainz Album Release Country'),
|
||||
MP4StorageStyle("----:com.apple.iTunes:MusicBrainz "
|
||||
"Album Release Country"),
|
||||
MP4StorageStyle(b"----:com.apple.iTunes:MusicBrainz "
|
||||
b"Album Release Country"),
|
||||
StorageStyle('RELEASECOUNTRY'),
|
||||
ASFStorageStyle('MusicBrainz/Album Release Country'),
|
||||
)
|
||||
albumstatus = MediaField(
|
||||
MP3DescStorageStyle(u'MusicBrainz Album Status'),
|
||||
MP4StorageStyle("----:com.apple.iTunes:MusicBrainz Album Status"),
|
||||
MP4StorageStyle(b"----:com.apple.iTunes:MusicBrainz Album Status"),
|
||||
StorageStyle('MUSICBRAINZ_ALBUMSTATUS'),
|
||||
ASFStorageStyle('MusicBrainz/Album Status'),
|
||||
)
|
||||
media = MediaField(
|
||||
MP3StorageStyle('TMED'),
|
||||
MP4StorageStyle("----:com.apple.iTunes:MEDIA"),
|
||||
MP4StorageStyle(b"----:com.apple.iTunes:MEDIA"),
|
||||
StorageStyle('MEDIA'),
|
||||
ASFStorageStyle('WM/Media'),
|
||||
)
|
||||
albumdisambig = MediaField(
|
||||
# This tag mapping was invented for beets (not used by Picard, etc).
|
||||
MP3DescStorageStyle(u'MusicBrainz Album Comment'),
|
||||
MP4StorageStyle("----:com.apple.iTunes:MusicBrainz Album Comment"),
|
||||
MP4StorageStyle(b"----:com.apple.iTunes:MusicBrainz Album Comment"),
|
||||
StorageStyle('MUSICBRAINZ_ALBUMCOMMENT'),
|
||||
ASFStorageStyle('MusicBrainz/Album Comment'),
|
||||
)
|
||||
|
|
@ -1674,7 +1678,7 @@ class MediaFile(object):
|
|||
# Release date.
|
||||
date = DateField(
|
||||
MP3StorageStyle('TDRC'),
|
||||
MP4StorageStyle("\xa9day"),
|
||||
MP4StorageStyle(b"\xa9day"),
|
||||
StorageStyle('DATE'),
|
||||
ASFStorageStyle('WM/Year'),
|
||||
year=(StorageStyle('YEAR'),))
|
||||
|
|
@ -1686,7 +1690,7 @@ class MediaFile(object):
|
|||
# *Original* release date.
|
||||
original_date = DateField(
|
||||
MP3StorageStyle('TDOR'),
|
||||
MP4StorageStyle('----:com.apple.iTunes:ORIGINAL YEAR'),
|
||||
MP4StorageStyle(b'----:com.apple.iTunes:ORIGINAL YEAR'),
|
||||
StorageStyle('ORIGINALDATE'),
|
||||
ASFStorageStyle('WM/OriginalReleaseYear'))
|
||||
|
||||
|
|
@ -1697,13 +1701,13 @@ class MediaFile(object):
|
|||
# Nonstandard metadata.
|
||||
artist_credit = MediaField(
|
||||
MP3DescStorageStyle(u'Artist Credit'),
|
||||
MP4StorageStyle("----:com.apple.iTunes:Artist Credit"),
|
||||
MP4StorageStyle(b"----:com.apple.iTunes:Artist Credit"),
|
||||
StorageStyle('ARTIST_CREDIT'),
|
||||
ASFStorageStyle('beets/Artist Credit'),
|
||||
)
|
||||
albumartist_credit = MediaField(
|
||||
MP3DescStorageStyle(u'Album Artist Credit'),
|
||||
MP4StorageStyle("----:com.apple.iTunes:Album Artist Credit"),
|
||||
MP4StorageStyle(b"----:com.apple.iTunes:Album Artist Credit"),
|
||||
StorageStyle('ALBUMARTIST_CREDIT'),
|
||||
ASFStorageStyle('beets/Album Artist Credit'),
|
||||
)
|
||||
|
|
@ -1717,31 +1721,31 @@ class MediaFile(object):
|
|||
# MusicBrainz IDs.
|
||||
mb_trackid = MediaField(
|
||||
MP3UFIDStorageStyle(owner='http://musicbrainz.org'),
|
||||
MP4StorageStyle('----:com.apple.iTunes:MusicBrainz Track Id'),
|
||||
MP4StorageStyle(b'----:com.apple.iTunes:MusicBrainz Track Id'),
|
||||
StorageStyle('MUSICBRAINZ_TRACKID'),
|
||||
ASFStorageStyle('MusicBrainz/Track Id'),
|
||||
)
|
||||
mb_albumid = MediaField(
|
||||
MP3DescStorageStyle(u'MusicBrainz Album Id'),
|
||||
MP4StorageStyle('----:com.apple.iTunes:MusicBrainz Album Id'),
|
||||
MP4StorageStyle(b'----:com.apple.iTunes:MusicBrainz Album Id'),
|
||||
StorageStyle('MUSICBRAINZ_ALBUMID'),
|
||||
ASFStorageStyle('MusicBrainz/Album Id'),
|
||||
)
|
||||
mb_artistid = MediaField(
|
||||
MP3DescStorageStyle(u'MusicBrainz Artist Id'),
|
||||
MP4StorageStyle('----:com.apple.iTunes:MusicBrainz Artist Id'),
|
||||
MP4StorageStyle(b'----:com.apple.iTunes:MusicBrainz Artist Id'),
|
||||
StorageStyle('MUSICBRAINZ_ARTISTID'),
|
||||
ASFStorageStyle('MusicBrainz/Artist Id'),
|
||||
)
|
||||
mb_albumartistid = MediaField(
|
||||
MP3DescStorageStyle(u'MusicBrainz Album Artist Id'),
|
||||
MP4StorageStyle('----:com.apple.iTunes:MusicBrainz Album Artist Id'),
|
||||
MP4StorageStyle(b'----:com.apple.iTunes:MusicBrainz Album Artist Id'),
|
||||
StorageStyle('MUSICBRAINZ_ALBUMARTISTID'),
|
||||
ASFStorageStyle('MusicBrainz/Album Artist Id'),
|
||||
)
|
||||
mb_releasegroupid = MediaField(
|
||||
MP3DescStorageStyle(u'MusicBrainz Release Group Id'),
|
||||
MP4StorageStyle('----:com.apple.iTunes:MusicBrainz Release Group Id'),
|
||||
MP4StorageStyle(b'----:com.apple.iTunes:MusicBrainz Release Group Id'),
|
||||
StorageStyle('MUSICBRAINZ_RELEASEGROUPID'),
|
||||
ASFStorageStyle('MusicBrainz/Release Group Id'),
|
||||
)
|
||||
|
|
@ -1749,13 +1753,13 @@ class MediaFile(object):
|
|||
# Acoustid fields.
|
||||
acoustid_fingerprint = MediaField(
|
||||
MP3DescStorageStyle(u'Acoustid Fingerprint'),
|
||||
MP4StorageStyle('----:com.apple.iTunes:Acoustid Fingerprint'),
|
||||
MP4StorageStyle(b'----:com.apple.iTunes:Acoustid Fingerprint'),
|
||||
StorageStyle('ACOUSTID_FINGERPRINT'),
|
||||
ASFStorageStyle('Acoustid/Fingerprint'),
|
||||
)
|
||||
acoustid_id = MediaField(
|
||||
MP3DescStorageStyle(u'Acoustid Id'),
|
||||
MP4StorageStyle('----:com.apple.iTunes:Acoustid Id'),
|
||||
MP4StorageStyle(b'----:com.apple.iTunes:Acoustid Id'),
|
||||
StorageStyle('ACOUSTID_ID'),
|
||||
ASFStorageStyle('Acoustid/Id'),
|
||||
)
|
||||
|
|
@ -1776,11 +1780,11 @@ class MediaFile(object):
|
|||
id3_lang='eng'
|
||||
),
|
||||
MP4StorageStyle(
|
||||
'----:com.apple.iTunes:replaygain_track_gain',
|
||||
b'----:com.apple.iTunes:replaygain_track_gain',
|
||||
float_places=2, suffix=b' dB'
|
||||
),
|
||||
MP4SoundCheckStorageStyle(
|
||||
'----:com.apple.iTunes:iTunNORM',
|
||||
b'----:com.apple.iTunes:iTunNORM',
|
||||
index=0
|
||||
),
|
||||
StorageStyle(
|
||||
|
|
@ -1803,7 +1807,7 @@ class MediaFile(object):
|
|||
float_places=2, suffix=u' dB'
|
||||
),
|
||||
MP4SoundCheckStorageStyle(
|
||||
'----:com.apple.iTunes:iTunNORM',
|
||||
b'----:com.apple.iTunes:iTunNORM',
|
||||
index=1
|
||||
),
|
||||
StorageStyle(
|
||||
|
|
@ -1831,11 +1835,11 @@ class MediaFile(object):
|
|||
id3_lang='eng'
|
||||
),
|
||||
MP4StorageStyle(
|
||||
'----:com.apple.iTunes:replaygain_track_peak',
|
||||
b'----:com.apple.iTunes:replaygain_track_peak',
|
||||
float_places=6
|
||||
),
|
||||
MP4SoundCheckStorageStyle(
|
||||
'----:com.apple.iTunes:iTunNORM',
|
||||
b'----:com.apple.iTunes:iTunNORM',
|
||||
index=1
|
||||
),
|
||||
StorageStyle(u'REPLAYGAIN_TRACK_PEAK', float_places=6),
|
||||
|
|
@ -1852,7 +1856,7 @@ class MediaFile(object):
|
|||
float_places=6
|
||||
),
|
||||
MP4StorageStyle(
|
||||
'----:com.apple.iTunes:replaygain_album_peak',
|
||||
b'----:com.apple.iTunes:replaygain_album_peak',
|
||||
float_places=6
|
||||
),
|
||||
StorageStyle(u'REPLAYGAIN_ALBUM_PEAK', float_places=6),
|
||||
|
|
@ -1862,7 +1866,7 @@ class MediaFile(object):
|
|||
|
||||
initial_key = MediaField(
|
||||
MP3StorageStyle('TKEY'),
|
||||
MP4StorageStyle('----:com.apple.iTunes:initialkey'),
|
||||
MP4StorageStyle(b'----:com.apple.iTunes:initialkey'),
|
||||
StorageStyle('INITIALKEY'),
|
||||
ASFStorageStyle('INITIALKEY'),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
"""Support for beets plugins."""
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import traceback
|
||||
import inspect
|
||||
import re
|
||||
|
|
@ -25,7 +28,7 @@ import beets
|
|||
from beets import logging
|
||||
from beets import mediafile
|
||||
|
||||
PLUGIN_NAMESPACE = 'beetsplug'
|
||||
PLUGIN_NAMESPACE = b'beetsplug'
|
||||
|
||||
# Plugins using the Last.fm API can share the same API key.
|
||||
LASTFM_KEY = '2dc3914abf35f0d9c92d97d8f8e42b43'
|
||||
|
|
@ -69,7 +72,7 @@ class BeetsPlugin(object):
|
|||
def __init__(self, name=None):
|
||||
"""Perform one-time plugin setup.
|
||||
"""
|
||||
self.name = name or self.__module__.split('.')[-1]
|
||||
self.name = name or self.__module__.decode('utf8').split('.')[-1]
|
||||
self.config = beets.config[self.name]
|
||||
if not self.template_funcs:
|
||||
self.template_funcs = {}
|
||||
|
|
@ -251,7 +254,8 @@ def load_plugins(names=()):
|
|||
BeetsPlugin subclasses desired.
|
||||
"""
|
||||
for name in names:
|
||||
modname = '%s.%s' % (PLUGIN_NAMESPACE, name)
|
||||
bname = name.encode('utf8')
|
||||
modname = b'%s.%s' % (PLUGIN_NAMESPACE, bname)
|
||||
try:
|
||||
try:
|
||||
namespace = __import__(modname, None, None)
|
||||
|
|
@ -262,7 +266,7 @@ def load_plugins(names=()):
|
|||
else:
|
||||
raise
|
||||
else:
|
||||
for obj in getattr(namespace, name).__dict__.values():
|
||||
for obj in getattr(namespace, bname).__dict__.values():
|
||||
if isinstance(obj, type) and issubclass(obj, BeetsPlugin) \
|
||||
and obj != BeetsPlugin and obj not in _classes:
|
||||
_classes.add(obj)
|
||||
|
|
@ -313,7 +317,7 @@ def queries():
|
|||
|
||||
def types(model_cls):
|
||||
# Gives us `item_types` and `album_types`
|
||||
attr_name = '{0}_types'.format(model_cls.__name__.lower())
|
||||
attr_name = b'{0}_types'.format(model_cls.__name__.lower())
|
||||
types = {}
|
||||
for plugin in find_plugins():
|
||||
plugin_types = getattr(plugin, attr_name, {})
|
||||
|
|
|
|||
|
|
@ -16,7 +16,9 @@
|
|||
interface. To invoke the CLI, just call beets.ui.main(). The actual
|
||||
CLI commands are implemented in the ui.commands module.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import locale
|
||||
import optparse
|
||||
|
|
@ -41,7 +43,7 @@ from beets.autotag import mb
|
|||
from beets.dbcore import query as db_query
|
||||
|
||||
# On Windows platforms, use colorama to support "ANSI" terminal colors.
|
||||
if sys.platform == 'win32':
|
||||
if sys.platform == b'win32':
|
||||
try:
|
||||
import colorama
|
||||
except ImportError:
|
||||
|
|
@ -220,11 +222,11 @@ def input_options(options, require=False, prompt=None, fallback_prompt=None,
|
|||
prompt_part_lengths = []
|
||||
if numrange:
|
||||
if isinstance(default, int):
|
||||
default_name = str(default)
|
||||
default_name = unicode(default)
|
||||
default_name = colorize('turquoise', default_name)
|
||||
tmpl = '# selection (default %s)'
|
||||
prompt_parts.append(tmpl % default_name)
|
||||
prompt_part_lengths.append(len(tmpl % str(default)))
|
||||
prompt_part_lengths.append(len(tmpl % unicode(default)))
|
||||
else:
|
||||
prompt_parts.append('# selection')
|
||||
prompt_part_lengths.append(len(prompt_parts[-1]))
|
||||
|
|
@ -491,7 +493,7 @@ def term_width():
|
|||
except IOError:
|
||||
return fallback
|
||||
try:
|
||||
height, width = struct.unpack('hh', buf)
|
||||
height, width = struct.unpack(b'hh', buf)
|
||||
except struct.error:
|
||||
return fallback
|
||||
return width
|
||||
|
|
@ -611,8 +613,8 @@ class Subcommand(object):
|
|||
@root_parser.setter
|
||||
def root_parser(self, root_parser):
|
||||
self._root_parser = root_parser
|
||||
self.parser.prog = '{0} {1}'.format(root_parser.get_prog_name(),
|
||||
self.name)
|
||||
self.parser.prog = '{0} {1}'.format(
|
||||
root_parser.get_prog_name().decode('utf8'), self.name)
|
||||
|
||||
|
||||
class SubcommandsOptionParser(optparse.OptionParser):
|
||||
|
|
@ -831,7 +833,7 @@ def _configure(options):
|
|||
# Add any additional config files specified with --config. This
|
||||
# special handling lets specified plugins get loaded before we
|
||||
# finish parsing the command line.
|
||||
if getattr(options, 'config', None) is not None:
|
||||
if getattr(options, b'config', None) is not None:
|
||||
config_path = options.config
|
||||
del options.config
|
||||
config.set_file(config_path)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@
|
|||
"""This module provides the default commands for beets' command-line
|
||||
interface.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import os
|
||||
import platform
|
||||
|
|
@ -1487,9 +1489,9 @@ def config_edit():
|
|||
path = config.user_config_path()
|
||||
|
||||
if 'EDITOR' in os.environ:
|
||||
editor = os.environ['EDITOR']
|
||||
editor = os.environ['EDITOR'].encode('utf8')
|
||||
try:
|
||||
editor = shlex.split(editor)
|
||||
editor = [e.decode('utf8') for e in shlex.split(editor)]
|
||||
except ValueError: # Malformed shell tokens.
|
||||
editor = [editor]
|
||||
args = editor + [path]
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@
|
|||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
"""Miscellaneous utility functions."""
|
||||
from __future__ import division
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
|
@ -299,28 +301,28 @@ def _fsencoding():
|
|||
UTF-8 (not MBCS).
|
||||
"""
|
||||
encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
|
||||
if encoding == 'mbcs':
|
||||
if encoding == b'mbcs':
|
||||
# On Windows, a broken encoding known to Python as "MBCS" is
|
||||
# used for the filesystem. However, we only use the Unicode API
|
||||
# for Windows paths, so the encoding is actually immaterial so
|
||||
# we can avoid dealing with this nastiness. We arbitrarily
|
||||
# choose UTF-8.
|
||||
encoding = 'utf8'
|
||||
encoding = b'utf8'
|
||||
return encoding
|
||||
|
||||
|
||||
def bytestring_path(path):
|
||||
"""Given a path, which is either a str or a unicode, returns a str
|
||||
"""Given a path, which is either a bytes or a unicode, returns a str
|
||||
path (ensuring that we never deal with Unicode pathnames).
|
||||
"""
|
||||
# Pass through bytestrings.
|
||||
if isinstance(path, str):
|
||||
if isinstance(path, bytes):
|
||||
return path
|
||||
|
||||
# On Windows, remove the magic prefix added by `syspath`. This makes
|
||||
# ``bytestring_path(syspath(X)) == X``, i.e., we can safely
|
||||
# round-trip through `syspath`.
|
||||
if os.path.__name__ == 'ntpath' and path.startswith(WINDOWS_MAGIC_PREFIX):
|
||||
if os.path.__name__ == b'ntpath' and path.startswith(WINDOWS_MAGIC_PREFIX):
|
||||
path = path[len(WINDOWS_MAGIC_PREFIX):]
|
||||
|
||||
# Try to encode with default encodings, but fall back to UTF8.
|
||||
|
|
@ -339,7 +341,7 @@ def displayable_path(path, separator=u'; '):
|
|||
return separator.join(displayable_path(p) for p in path)
|
||||
elif isinstance(path, unicode):
|
||||
return path
|
||||
elif not isinstance(path, str):
|
||||
elif not isinstance(path, bytes):
|
||||
# A non-string object: just get its unicode representation.
|
||||
return unicode(path)
|
||||
|
||||
|
|
@ -357,7 +359,7 @@ def syspath(path, prefix=True):
|
|||
*really* know what you're doing.
|
||||
"""
|
||||
# Don't do anything if we're not on windows
|
||||
if os.path.__name__ != 'ntpath':
|
||||
if os.path.__name__ != b'ntpath':
|
||||
return path
|
||||
|
||||
if not isinstance(path, unicode):
|
||||
|
|
@ -495,12 +497,12 @@ def unique_path(path):
|
|||
# shares, which are sufficiently common as to cause frequent problems.
|
||||
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx
|
||||
CHAR_REPLACE = [
|
||||
(re.compile(ur'[\\/]'), u'_'), # / and \ -- forbidden everywhere.
|
||||
(re.compile(ur'^\.'), u'_'), # Leading dot (hidden files on Unix).
|
||||
(re.compile(ur'[\x00-\x1f]'), u''), # Control characters.
|
||||
(re.compile(ur'[<>:"\?\*\|]'), u'_'), # Windows "reserved characters".
|
||||
(re.compile(ur'\.$'), u'_'), # Trailing dots.
|
||||
(re.compile(ur'\s+$'), u''), # Trailing whitespace.
|
||||
(re.compile(r'[\\/]'), u'_'), # / and \ -- forbidden everywhere.
|
||||
(re.compile(r'^\.'), u'_'), # Leading dot (hidden files on Unix).
|
||||
(re.compile(r'[\x00-\x1f]'), u''), # Control characters.
|
||||
(re.compile(r'[<>:"\?\*\|]'), u'_'), # Windows "reserved characters".
|
||||
(re.compile(r'\.$'), u'_'), # Trailing dots.
|
||||
(re.compile(r'\s+$'), u''), # Trailing whitespace.
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -554,8 +556,8 @@ def as_string(value):
|
|||
if value is None:
|
||||
return u''
|
||||
elif isinstance(value, buffer):
|
||||
return str(value).decode('utf8', 'ignore')
|
||||
elif isinstance(value, str):
|
||||
return bytes(value).decode('utf8', 'ignore')
|
||||
elif isinstance(value, bytes):
|
||||
return value.decode('utf8', 'ignore')
|
||||
else:
|
||||
return unicode(value)
|
||||
|
|
@ -614,19 +616,19 @@ def cpu_count():
|
|||
"""
|
||||
# Adapted from the soundconverter project:
|
||||
# https://github.com/kassoulet/soundconverter
|
||||
if sys.platform == 'win32':
|
||||
if sys.platform == b'win32':
|
||||
try:
|
||||
num = int(os.environ['NUMBER_OF_PROCESSORS'])
|
||||
except (ValueError, KeyError):
|
||||
num = 0
|
||||
elif sys.platform == 'darwin':
|
||||
elif sys.platform == b'darwin':
|
||||
try:
|
||||
num = int(command_output(['sysctl', '-n', 'hw.ncpu']))
|
||||
except ValueError:
|
||||
num = 0
|
||||
else:
|
||||
try:
|
||||
num = os.sysconf('SC_NPROCESSORS_ONLN')
|
||||
num = os.sysconf(b'SC_NPROCESSORS_ONLN')
|
||||
except (ValueError, OSError, AttributeError):
|
||||
num = 0
|
||||
if num >= 1:
|
||||
|
|
@ -654,7 +656,7 @@ def command_output(cmd, shell=False):
|
|||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
close_fds=platform.system() != 'Windows',
|
||||
close_fds=platform.system() != b'Windows',
|
||||
shell=shell
|
||||
)
|
||||
stdout, stderr = proc.communicate()
|
||||
|
|
@ -673,7 +675,7 @@ def max_filename_length(path, limit=MAX_FILENAME_LENGTH):
|
|||
misreports its capacity). If it cannot be determined (e.g., on
|
||||
Windows), return `limit`.
|
||||
"""
|
||||
if hasattr(os, 'statvfs'):
|
||||
if hasattr(os, b'statvfs'):
|
||||
try:
|
||||
res = os.statvfs(path)
|
||||
except OSError:
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
"""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)
|
||||
|
||||
import urllib
|
||||
import subprocess
|
||||
import os
|
||||
|
|
@ -40,7 +43,7 @@ def resize_url(url, maxwidth):
|
|||
"""
|
||||
return '{0}?{1}'.format(PROXY_URL, urllib.urlencode({
|
||||
'url': url.replace('http://', ''),
|
||||
'w': str(maxwidth),
|
||||
'w': bytes(maxwidth),
|
||||
}))
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ asyncore.
|
|||
|
||||
Bluelet: easy concurrency without all the messy parallelism.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import socket
|
||||
import select
|
||||
import sys
|
||||
|
|
@ -550,7 +553,7 @@ def spawn(coro):
|
|||
and child coroutines run concurrently.
|
||||
"""
|
||||
if not isinstance(coro, types.GeneratorType):
|
||||
raise ValueError('%s is not a coroutine' % str(coro))
|
||||
raise ValueError('%s is not a coroutine' % coro)
|
||||
return SpawnEvent(coro)
|
||||
|
||||
|
||||
|
|
@ -560,7 +563,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' % str(coro))
|
||||
raise ValueError('%s is not a coroutine' % coro)
|
||||
return DelegationEvent(coro)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@
|
|||
|
||||
"""Worry-free YAML configuration files.
|
||||
"""
|
||||
from __future__ import unicode_literals
|
||||
from __future__ import (unicode_literals, absolute_import, print_function,
|
||||
division)
|
||||
|
||||
import platform
|
||||
import os
|
||||
import pkgutil
|
||||
|
|
@ -245,7 +247,7 @@ class ConfigView(object):
|
|||
|
||||
def __str__(self):
|
||||
"""Gets the value for this view as a byte string."""
|
||||
return str(self.get())
|
||||
return bytes(self.get())
|
||||
|
||||
def __unicode__(self):
|
||||
"""Gets the value for this view as a unicode string. (Python 2
|
||||
|
|
@ -421,7 +423,7 @@ class Subview(ConfigView):
|
|||
if isinstance(self.key, int):
|
||||
self.name += '#{0}'.format(self.key)
|
||||
elif isinstance(self.key, BASESTRING):
|
||||
self.name += '{0}'.format(self.key)
|
||||
self.name += '{0}'.format(self.key.decode('utf8'))
|
||||
else:
|
||||
self.name += '{0}'.format(repr(self.key))
|
||||
|
||||
|
|
@ -464,10 +466,10 @@ def _package_path(name):
|
|||
``name == "__main__"``).
|
||||
"""
|
||||
loader = pkgutil.get_loader(name)
|
||||
if loader is None or name == '__main__':
|
||||
if loader is None or name == b'__main__':
|
||||
return None
|
||||
|
||||
if hasattr(loader, 'get_filename'):
|
||||
if hasattr(loader, b'get_filename'):
|
||||
filepath = loader.get_filename(name)
|
||||
else:
|
||||
# Fall back to importing the specified module.
|
||||
|
|
@ -487,13 +489,13 @@ def config_dirs():
|
|||
"""
|
||||
paths = []
|
||||
|
||||
if platform.system() == 'Darwin':
|
||||
if platform.system() == b'Darwin':
|
||||
paths.append(MAC_DIR)
|
||||
paths.append(UNIX_DIR_FALLBACK)
|
||||
if UNIX_DIR_VAR in os.environ:
|
||||
paths.append(os.environ[UNIX_DIR_VAR])
|
||||
|
||||
elif platform.system() == 'Windows':
|
||||
elif platform.system() == b'Windows':
|
||||
paths.append(WINDOWS_DIR_FALLBACK)
|
||||
if WINDOWS_DIR_VAR in os.environ:
|
||||
paths.append(os.environ[WINDOWS_DIR_VAR])
|
||||
|
|
@ -576,7 +578,7 @@ def load_yaml(filename):
|
|||
parsed, a ConfigReadError is raised.
|
||||
"""
|
||||
try:
|
||||
with open(filename, 'r') as f:
|
||||
with open(filename, b'r') as f:
|
||||
return yaml.load(f, Loader=Loader)
|
||||
except (IOError, yaml.error.YAMLError) as exc:
|
||||
raise ConfigReadError(filename, exc)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
# 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 enum import Enum
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,9 @@ library: unknown symbols are left intact.
|
|||
This is sort of like a tiny, horrible degeneration of a real templating
|
||||
engine like Jinja2 or Mustache.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import re
|
||||
import ast
|
||||
|
|
@ -39,8 +41,8 @@ GROUP_CLOSE = u'}'
|
|||
ARG_SEP = u','
|
||||
ESCAPE_CHAR = u'$'
|
||||
|
||||
VARIABLE_PREFIX = '__var_'
|
||||
FUNCTION_PREFIX = '__func_'
|
||||
VARIABLE_PREFIX = b'__var_'
|
||||
FUNCTION_PREFIX = b'__func_'
|
||||
|
||||
|
||||
class Environment(object):
|
||||
|
|
@ -69,11 +71,11 @@ def ex_literal(val):
|
|||
value.
|
||||
"""
|
||||
if val is None:
|
||||
return ast.Name('None', ast.Load())
|
||||
return ast.Name(b'None', ast.Load())
|
||||
elif isinstance(val, (int, float, long)):
|
||||
return ast.Num(val)
|
||||
elif isinstance(val, bool):
|
||||
return ast.Name(str(val), ast.Load())
|
||||
return ast.Name(bytes(val), ast.Load())
|
||||
elif isinstance(val, basestring):
|
||||
return ast.Str(val)
|
||||
raise TypeError('no literal for {0}'.format(type(val)))
|
||||
|
|
@ -110,7 +112,7 @@ def compile_func(arg_names, statements, name='_the_func', debug=False):
|
|||
bytecode of the compiled function.
|
||||
"""
|
||||
func_def = ast.FunctionDef(
|
||||
name,
|
||||
name.encode('utf8'),
|
||||
ast.arguments(
|
||||
[ast.Name(n, ast.Param()) for n in arg_names],
|
||||
None, None,
|
||||
|
|
@ -122,7 +124,7 @@ def compile_func(arg_names, statements, name='_the_func', debug=False):
|
|||
mod = ast.Module([func_def])
|
||||
ast.fix_missing_locations(mod)
|
||||
|
||||
prog = compile(mod, '<generated>', 'exec')
|
||||
prog = compile(mod, b'<generated>', b'exec')
|
||||
|
||||
# Debug: show bytecode.
|
||||
if debug:
|
||||
|
|
@ -205,11 +207,11 @@ class Call(object):
|
|||
# Create a subexpression that joins the result components of
|
||||
# the arguments.
|
||||
arg_exprs.append(ex_call(
|
||||
ast.Attribute(ex_literal(u''), 'join', ast.Load()),
|
||||
ast.Attribute(ex_literal(u''), b'join', ast.Load()),
|
||||
[ex_call(
|
||||
'map',
|
||||
b'map',
|
||||
[
|
||||
ex_rvalue('unicode'),
|
||||
ex_rvalue(b'unicode'),
|
||||
ast.List(subexprs, ast.Load()),
|
||||
]
|
||||
)],
|
||||
|
|
@ -289,7 +291,7 @@ class Parser(object):
|
|||
# Common parsing resources.
|
||||
special_chars = (SYMBOL_DELIM, FUNC_DELIM, GROUP_OPEN, GROUP_CLOSE,
|
||||
ARG_SEP, ESCAPE_CHAR)
|
||||
special_char_re = re.compile(ur'[%s]|$' %
|
||||
special_char_re = re.compile(r'[%s]|$' %
|
||||
u''.join(re.escape(c) for c in special_chars))
|
||||
|
||||
def parse_expression(self):
|
||||
|
|
@ -477,7 +479,7 @@ class Parser(object):
|
|||
Updates ``pos``.
|
||||
"""
|
||||
remainder = self.string[self.pos:]
|
||||
ident = re.match(ur'\w*', remainder).group(0)
|
||||
ident = re.match(r'\w*', remainder).group(0)
|
||||
self.pos += len(ident)
|
||||
return ident
|
||||
|
||||
|
|
@ -532,9 +534,9 @@ class Template(object):
|
|||
|
||||
argnames = []
|
||||
for varname in varnames:
|
||||
argnames.append(VARIABLE_PREFIX.encode('utf8') + varname)
|
||||
argnames.append(VARIABLE_PREFIX + varname)
|
||||
for funcname in funcnames:
|
||||
argnames.append(FUNCTION_PREFIX.encode('utf8') + funcname)
|
||||
argnames.append(FUNCTION_PREFIX + funcname)
|
||||
|
||||
func = compile_func(
|
||||
argnames,
|
||||
|
|
@ -555,7 +557,7 @@ class Template(object):
|
|||
|
||||
# Performance tests.
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
import timeit
|
||||
_tmpl = Template(u'foo $bar %baz{foozle $bar barzle} $bar')
|
||||
_vars = {'bar': 'qux'}
|
||||
|
|
|
|||
|
|
@ -30,14 +30,16 @@ up a bottleneck stage by dividing its work among multiple threads.
|
|||
To do so, pass an iterable of coroutines to the Pipeline constructor
|
||||
in place of any single coroutine.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import Queue
|
||||
from threading import Thread, Lock
|
||||
import sys
|
||||
|
||||
BUBBLE = '__PIPELINE_BUBBLE__'
|
||||
POISON = '__PIPELINE_POISON__'
|
||||
BUBBLE = b'__PIPELINE_BUBBLE__'
|
||||
POISON = b'__PIPELINE_POISON__'
|
||||
|
||||
DEFAULT_QUEUE_SIZE = 16
|
||||
|
||||
|
|
@ -457,7 +459,7 @@ class Pipeline(object):
|
|||
yield msg
|
||||
|
||||
# Smoke test.
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
import time
|
||||
|
||||
# Test a normally-terminating pipeline both in sequence and
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
"""A simple utility for constructing filesystem-like trees from beets
|
||||
libraries.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from collections import namedtuple
|
||||
from beets import util
|
||||
|
||||
|
|
|
|||
|
|
@ -15,5 +15,7 @@
|
|||
"""A namespace package for beets plugins."""
|
||||
|
||||
# Make this a namespace package.
|
||||
from __future__ import absolute_import
|
||||
|
||||
from pkgutil import extend_path
|
||||
__path__ = extend_path(__path__, __name__)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@
|
|||
|
||||
"""Some simple performance benchmarks for beets.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets import ui
|
||||
|
|
|
|||
|
|
@ -16,7 +16,9 @@
|
|||
Beets library. Attempts to implement a compatible protocol to allow
|
||||
use of the wide range of MPD clients.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import re
|
||||
from string import Template
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@
|
|||
"""A wrapper for the GStreamer Python bindings that exposes a simple
|
||||
music player.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
|
@ -88,7 +90,7 @@ class GstPlayer(object):
|
|||
# error
|
||||
self.player.set_state(gst.STATE_NULL)
|
||||
err, debug = message.parse_error()
|
||||
print("Error: " + str(err))
|
||||
print("Error: {0}".format(err))
|
||||
self.playing = False
|
||||
|
||||
def _set_volume(self, volume):
|
||||
|
|
@ -212,7 +214,7 @@ def play_complicated(paths):
|
|||
while my_paths:
|
||||
time.sleep(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
# A very simple command-line player. Just give it names of audio
|
||||
# files on the command line; these are all played in sequence.
|
||||
paths = [os.path.abspath(os.path.expanduser(p))
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
"""Determine BPM by pressing a key to the rhythm."""
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import time
|
||||
|
||||
from beets import ui
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
"""Provides the %bucket{} function for path formatting.
|
||||
"""
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from datetime import datetime
|
||||
import re
|
||||
import string
|
||||
|
|
@ -131,9 +134,9 @@ def str2fmt(s):
|
|||
def format_span(fmt, yearfrom, yearto, fromnchars, tonchars):
|
||||
"""Return a span string representation.
|
||||
"""
|
||||
args = (str(yearfrom)[-fromnchars:])
|
||||
args = (bytes(yearfrom)[-fromnchars:])
|
||||
if tonchars:
|
||||
args = (str(yearfrom)[-fromnchars:], str(yearto)[-tonchars:])
|
||||
args = (bytes(yearfrom)[-fromnchars:], bytes(yearto)[-tonchars:])
|
||||
return fmt % args
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
"""Adds Chromaprint/Acoustid acoustic fingerprinting support to the
|
||||
autotagger. Requires the pyacoustid library.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from beets import plugins
|
||||
from beets import ui
|
||||
from beets import util
|
||||
|
|
@ -62,7 +65,7 @@ def acoustid_match(log, path):
|
|||
duration, fp = acoustid.fingerprint_file(util.syspath(path))
|
||||
except acoustid.FingerprintGenerationError as exc:
|
||||
log.error(u'fingerprinting of {0} failed: {1}',
|
||||
util.displayable_path(repr(path)), str(exc))
|
||||
util.displayable_path(repr(path)), exc)
|
||||
return None
|
||||
_fingerprints[path] = fp
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
"""Converts tracks or albums to external directory
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import os
|
||||
import threading
|
||||
import subprocess
|
||||
|
|
@ -43,7 +46,7 @@ def replace_ext(path, ext):
|
|||
|
||||
The new extension must not contain a leading dot.
|
||||
"""
|
||||
return os.path.splitext(path)[0] + '.' + ext
|
||||
return os.path.splitext(path)[0] + b'.' + ext
|
||||
|
||||
|
||||
def get_format(format=None):
|
||||
|
|
@ -63,7 +66,7 @@ def get_format(format=None):
|
|||
.format(format)
|
||||
)
|
||||
except ConfigTypeError:
|
||||
command = config['convert']['formats'][format].get(str)
|
||||
command = config['convert']['formats'][format].get(bytes)
|
||||
extension = format
|
||||
|
||||
# Convenience and backwards-compatibility shortcuts.
|
||||
|
|
@ -175,8 +178,8 @@ class ConvertPlugin(BeetsPlugin):
|
|||
args = shlex.split(command)
|
||||
for i, arg in enumerate(args):
|
||||
args[i] = Template(arg).safe_substitute({
|
||||
'source': source,
|
||||
'dest': dest,
|
||||
'source': source.decode('utf8'),
|
||||
'dest': dest.decode('utf8'),
|
||||
})
|
||||
|
||||
if pretend:
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
"""Adds Discogs album search support to the autotagger. Requires the
|
||||
discogs-client library.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import beets.ui
|
||||
from beets import logging
|
||||
from beets.autotag.hooks import AlbumInfo, TrackInfo, Distance
|
||||
|
|
@ -33,7 +36,7 @@ import json
|
|||
urllib3_logger = logging.getLogger('requests.packages.urllib3')
|
||||
urllib3_logger.setLevel(logging.CRITICAL)
|
||||
|
||||
USER_AGENT = 'beets/{0} +http://beets.radbox.org/'.format(beets.__version__)
|
||||
USER_AGENT = u'beets/{0} +http://beets.radbox.org/'.format(beets.__version__)
|
||||
|
||||
|
||||
class DiscogsPlugin(BeetsPlugin):
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
"""List duplicate tracks or albums.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import shlex
|
||||
|
||||
from beets.plugins import BeetsPlugin
|
||||
|
|
@ -85,7 +88,7 @@ def _group_by(objs, keys, log):
|
|||
counts[key].append(obj)
|
||||
else:
|
||||
log.debug(u'{0}: all keys {1} on item {2} are null: skipping',
|
||||
PLUGIN, str(keys), displayable_path(obj.path))
|
||||
PLUGIN, keys, displayable_path(obj.path))
|
||||
|
||||
return counts
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
"""Fetch a variety of acoustic metrics from The Echo Nest.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import time
|
||||
import socket
|
||||
import os
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@
|
|||
# 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)
|
||||
|
||||
import os.path
|
||||
import imghdr
|
||||
import subprocess
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
"""Fetches album art.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from contextlib import closing
|
||||
import os
|
||||
import re
|
||||
|
|
@ -251,14 +254,14 @@ class FileSystem(ArtSource):
|
|||
images = []
|
||||
for fn in os.listdir(path):
|
||||
for ext in IMAGE_EXTENSIONS:
|
||||
if fn.lower().endswith('.' + ext) and \
|
||||
if fn.lower().endswith(b'.' + ext.encode('utf8')) and \
|
||||
os.path.isfile(os.path.join(path, fn)):
|
||||
images.append(fn)
|
||||
|
||||
# Look for "preferred" filenames.
|
||||
images = sorted(images,
|
||||
key=lambda x: self.filename_priority(x, cover_names))
|
||||
cover_pat = r"(\b|_)({0})(\b|_)".format('|'.join(cover_names))
|
||||
cover_pat = br"(\b|_)({0})(\b|_)".format(b'|'.join(cover_names))
|
||||
for fn in images:
|
||||
if re.search(cover_pat, os.path.splitext(fn)[0], re.I):
|
||||
self._log.debug(u'using well-named art file {0}',
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
"""Creates freedesktop.org-compliant .directory files on an album level.
|
||||
"""
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.ui import Subcommand
|
||||
from beets.ui import decargs
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
"""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 beets import plugins
|
||||
from beets.util import displayable_path
|
||||
import os
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
"""Moves "featured" artists to the title from the artist field.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import re
|
||||
|
||||
from beets import plugins
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
"""Provides a fuzzy matching query.
|
||||
"""
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.dbcore.query import StringFieldQuery
|
||||
import difflib
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
# 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)
|
||||
|
||||
"""Warns you about things you hate (or even blocks import)."""
|
||||
|
||||
from beets.plugins import BeetsPlugin
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ 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
|
||||
from __future__ import (unicode_literals, absolute_import, print_function,
|
||||
division)
|
||||
|
||||
import os
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
# 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)
|
||||
|
||||
"""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
|
||||
one wants to manually add music to a player by its path.
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
"""Shows file metadata.
|
||||
"""
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import os
|
||||
|
||||
from beets.plugins import BeetsPlugin
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
"""Allows inline path template customization code in the config file.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import traceback
|
||||
import itertools
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
"""Uses the `KeyFinder` program to add the `initial_key` field.
|
||||
"""
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import subprocess
|
||||
|
||||
from beets import ui
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
# 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)
|
||||
|
||||
"""Gets genres for imported music based on Last.fm tags.
|
||||
|
||||
Uses a provided whitelist file to determine which tags are valid genres.
|
||||
|
|
@ -122,7 +125,7 @@ class LastGenrePlugin(plugins.BeetsPlugin):
|
|||
wl_filename = WHITELIST
|
||||
if wl_filename:
|
||||
wl_filename = normpath(wl_filename)
|
||||
with open(wl_filename, 'r') as f:
|
||||
with open(wl_filename, b'r') as f:
|
||||
for line in f:
|
||||
line = line.decode('utf8').strip().lower()
|
||||
if line and not line.startswith(u'#'):
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
# 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)
|
||||
|
||||
import requests
|
||||
from beets import ui
|
||||
from beets import dbcore
|
||||
|
|
@ -105,8 +108,8 @@ def fetch_tracks(user, page, limit):
|
|||
'method': 'library.gettracks',
|
||||
'user': user,
|
||||
'api_key': plugins.LASTFM_KEY,
|
||||
'page': str(page),
|
||||
'limit': str(limit),
|
||||
'page': bytes(page),
|
||||
'limit': bytes(limit),
|
||||
'format': 'json',
|
||||
}).json()
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@
|
|||
|
||||
"""Fetches, embeds, and displays lyrics.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import re
|
||||
import requests
|
||||
|
|
@ -55,7 +57,7 @@ URL_CHARACTERS = {
|
|||
|
||||
def unescape(text):
|
||||
"""Resolves &#xxx; HTML entities (and some others)."""
|
||||
if isinstance(text, str):
|
||||
if isinstance(text, bytes):
|
||||
text = text.decode('utf8', 'ignore')
|
||||
out = text.replace(u' ', u' ')
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
# 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 beets.plugins import BeetsPlugin
|
||||
from beets.ui import Subcommand
|
||||
from beets import ui
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
"""Update library's tags using MusicBrainz.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets import autotag, library, ui, util
|
||||
from beets.autotag import hooks
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
"""List missing tracks.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from beets.autotag import hooks
|
||||
from beets.library import Item
|
||||
from beets.plugins import BeetsPlugin
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@
|
|||
# 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)
|
||||
|
||||
import mpd
|
||||
import socket
|
||||
import select
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ 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 beets.plugins import BeetsPlugin
|
||||
import os
|
||||
import socket
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
"""Fixes file permissions after the file gets written on import. Put something
|
||||
like the following in your config.yaml to configure:
|
||||
|
||||
|
|
@ -14,7 +17,7 @@ def convert_perm(perm):
|
|||
to an oct int. Else it just converts it to oct.
|
||||
"""
|
||||
if isinstance(perm, int):
|
||||
return int(str(perm), 8)
|
||||
return int(bytes(perm), 8)
|
||||
else:
|
||||
return int(perm, 8)
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
"""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 functools import partial
|
||||
|
||||
from beets.plugins import BeetsPlugin
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ Put something like the following in your config.yaml to configure:
|
|||
host: localhost
|
||||
port: 32400
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import requests
|
||||
from urlparse import urljoin
|
||||
import xml.etree.ElementTree as ET
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@
|
|||
|
||||
"""Get a random song or album from the library.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.ui import Subcommand, decargs, print_
|
||||
import random
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
# 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)
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import collections
|
||||
|
|
@ -177,7 +180,7 @@ class CommandBackend(Backend):
|
|||
# Disable clipping warning.
|
||||
cmd = cmd + ['-c']
|
||||
cmd = cmd + ['-a' if is_album else '-r']
|
||||
cmd = cmd + ['-d', str(self.gain_offset)]
|
||||
cmd = cmd + ['-d', bytes(self.gain_offset)]
|
||||
cmd = cmd + [syspath(i.path) for i in items]
|
||||
|
||||
self._log.debug(u'analyzing {0} files', len(items))
|
||||
|
|
@ -195,9 +198,9 @@ class CommandBackend(Backend):
|
|||
containing information about each analyzed file.
|
||||
"""
|
||||
out = []
|
||||
for line in text.split('\n')[1:num_lines + 1]:
|
||||
parts = line.split('\t')
|
||||
if len(parts) != 6 or parts[0] == 'File':
|
||||
for line in text.split(b'\n')[1:num_lines + 1]:
|
||||
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')
|
||||
d = {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
"""Uses user-specified rewriting rules to canonicalize names for path
|
||||
formats.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import re
|
||||
from collections import defaultdict
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@
|
|||
automatically whenever tags are written.
|
||||
"""
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets import ui
|
||||
from beets import util
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@
|
|||
|
||||
"""Generates smart playlists based on beets queries.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets import ui
|
||||
|
|
@ -101,5 +103,5 @@ class SmartPlaylistPlugin(BeetsPlugin):
|
|||
mkdirall(m3u_path)
|
||||
with open(syspath(m3u_path), 'w') as f:
|
||||
for path in m3us[m3u]:
|
||||
f.write(path + '\n')
|
||||
f.write(path + b'\n')
|
||||
self._log.info("{0} playlists updated", len(playlists))
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
from __future__ import print_function
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import re
|
||||
import webbrowser
|
||||
import requests
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
"""Moves patterns in path formats (suitable for moving articles)."""
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import re
|
||||
from beets.plugins import BeetsPlugin
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
# 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 beets.plugins import BeetsPlugin
|
||||
from beets.dbcore import types
|
||||
from beets.util.confit import ConfigValueError
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@
|
|||
# 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 beets.plugins import BeetsPlugin
|
||||
from beets import ui
|
||||
from beets import util
|
||||
|
|
@ -87,7 +90,7 @@ def resource(name):
|
|||
)
|
||||
else:
|
||||
return flask.abort(404)
|
||||
responder.__name__ = 'get_%s' % name
|
||||
responder.__name__ = b'get_%s' % name.encode('utf8')
|
||||
return responder
|
||||
return make_responder
|
||||
|
||||
|
|
@ -101,7 +104,7 @@ def resource_query(name):
|
|||
json_generator(query_func(queries), root='results'),
|
||||
mimetype='application/json'
|
||||
)
|
||||
responder.__name__ = 'query_%s' % name
|
||||
responder.__name__ = b'query_%s' % name.encode('utf8')
|
||||
return responder
|
||||
return make_responder
|
||||
|
||||
|
|
@ -116,7 +119,7 @@ def resource_list(name):
|
|||
json_generator(list_all(), root=name),
|
||||
mimetype='application/json'
|
||||
)
|
||||
responder.__name__ = 'all_%s' % name
|
||||
responder.__name__ = b'all_%s' % name.encode('utf8')
|
||||
return responder
|
||||
return make_responder
|
||||
|
||||
|
|
@ -274,7 +277,7 @@ class WebPlugin(BeetsPlugin):
|
|||
app.config['lib'] = lib
|
||||
# Enable CORS if required.
|
||||
if self.config['cors']:
|
||||
self._log.info(u'Enabling CORS with origin: {0}',
|
||||
self._log.info('Enabling CORS with origin: {0}',
|
||||
self.config['cors'])
|
||||
from flask.ext.cors import CORS
|
||||
app.config['CORS_ALLOW_HEADERS'] = "Content-Type"
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
""" Clears tag fields in media files."""
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import re
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.mediafile import MediaFile
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#!/usr/bin/env python3
|
||||
"""A utility script for automating the beets release process.
|
||||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import click
|
||||
import os
|
||||
import re
|
||||
|
|
@ -275,7 +277,7 @@ def prep():
|
|||
# FIXME It should be possible to specify this as an argument.
|
||||
version_parts = [int(n) for n in cur_version.split('.')]
|
||||
version_parts[-1] += 1
|
||||
next_version = '.'.join(map(str, version_parts))
|
||||
next_version = u'.'.join(map(unicode, version_parts))
|
||||
bump_version(next_version)
|
||||
|
||||
|
||||
|
|
@ -297,5 +299,5 @@ def publish():
|
|||
subprocess.check_call(['twine', 'upload', path])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
release()
|
||||
|
|
|
|||
2
setup.py
2
setup.py
|
|
@ -14,6 +14,8 @@
|
|||
# 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
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@
|
|||
# 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)
|
||||
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
|
|
@ -40,7 +43,7 @@ beetsplug.__path__ = [os.path.abspath(
|
|||
)]
|
||||
|
||||
# Test resources path.
|
||||
RSRC = os.path.join(os.path.dirname(__file__), 'rsrc')
|
||||
RSRC = os.path.join(os.path.dirname(__file__), b'rsrc')
|
||||
|
||||
# Propagate to root loger so nosetest can capture it
|
||||
log = logging.getLogger('beets')
|
||||
|
|
@ -73,7 +76,7 @@ def item(lib=None):
|
|||
comments=u'the comments',
|
||||
bpm=8,
|
||||
comp=True,
|
||||
path='somepath' + str(_item_ident),
|
||||
path='somepath{0}'.format(_item_ident),
|
||||
length=60.0,
|
||||
bitrate=128000,
|
||||
format='FLAC',
|
||||
|
|
@ -235,7 +238,7 @@ class DummyOut(object):
|
|||
self.buf.append(s)
|
||||
|
||||
def get(self):
|
||||
return ''.join(self.buf)
|
||||
return b''.join(self.buf)
|
||||
|
||||
def clear(self):
|
||||
self.buf = []
|
||||
|
|
@ -250,7 +253,7 @@ class DummyIn(object):
|
|||
self.out = out
|
||||
|
||||
def add(self, s):
|
||||
self.buf.append(s + '\n')
|
||||
self.buf.append(s + b'\n')
|
||||
|
||||
def readline(self):
|
||||
if not self.buf:
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ information or mock the environment.
|
|||
"""
|
||||
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import sys
|
||||
import os
|
||||
import os.path
|
||||
|
|
@ -50,7 +53,7 @@ from beets.autotag.hooks import AlbumInfo, TrackInfo
|
|||
from beets.mediafile import MediaFile, Image
|
||||
|
||||
# TODO Move AutotagMock here
|
||||
import _common
|
||||
from test import _common
|
||||
|
||||
|
||||
class LogCapture(logging.Handler):
|
||||
|
|
@ -324,7 +327,7 @@ class TestHelper(object):
|
|||
items = []
|
||||
path = os.path.join(_common.RSRC, 'full.' + ext)
|
||||
for i in range(count):
|
||||
item = Item.from_path(str(path))
|
||||
item = Item.from_path(bytes(path))
|
||||
item.album = u'\u00e4lbum {0}'.format(i) # Check unicode paths
|
||||
item.title = u't\u00eftle {0}'.format(i)
|
||||
item.add(self.lib)
|
||||
|
|
@ -339,7 +342,7 @@ class TestHelper(object):
|
|||
items = []
|
||||
path = os.path.join(_common.RSRC, 'full.' + ext)
|
||||
for i in range(track_count):
|
||||
item = Item.from_path(str(path))
|
||||
item = Item.from_path(bytes(path))
|
||||
item.album = u'\u00e4lbum' # Check unicode paths
|
||||
item.title = u't\u00eftle {0}'.format(i)
|
||||
item.add(self.lib)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
# 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)
|
||||
|
||||
import os
|
||||
import sys
|
||||
import requests
|
||||
|
|
@ -41,9 +44,9 @@ def main(argv=None):
|
|||
"""
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
print 'Fetching samples from:'
|
||||
print('Fetching samples from:')
|
||||
for s in test_lyrics.GOOGLE_SOURCES + test_lyrics.DEFAULT_SOURCES:
|
||||
print s['url']
|
||||
print(s['url'])
|
||||
url = s['url'] + s['path']
|
||||
fn = test_lyrics.url_to_filename(url)
|
||||
if not os.path.isfile(fn):
|
||||
|
|
@ -51,5 +54,5 @@ def main(argv=None):
|
|||
with safe_open_w(fn) as f:
|
||||
f.write(html.encode('utf8'))
|
||||
|
||||
if __name__ == "__main__":
|
||||
if __name__ == b'__main__':
|
||||
sys.exit(main())
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets import ui
|
||||
|
||||
|
|
|
|||
|
|
@ -14,13 +14,16 @@
|
|||
|
||||
"""Tests for the album art fetchers."""
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import os
|
||||
import shutil
|
||||
|
||||
import responses
|
||||
|
||||
import _common
|
||||
from _common import unittest
|
||||
from test import _common
|
||||
from test._common import unittest
|
||||
from beetsplug import fetchart
|
||||
from beets.autotag import AlbumInfo, AlbumMatch
|
||||
from beets import library
|
||||
|
|
@ -357,5 +360,5 @@ class ArtImporterTest(UseThePlugin):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -14,11 +14,14 @@
|
|||
|
||||
"""Tests for autotagging functionality.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import re
|
||||
import copy
|
||||
|
||||
import _common
|
||||
from _common import unittest
|
||||
from test import _common
|
||||
from test._common import unittest
|
||||
from beets import autotag
|
||||
from beets.autotag import match
|
||||
from beets.autotag.hooks import Distance, string_dist
|
||||
|
|
@ -569,7 +572,7 @@ class AssignmentTest(unittest.TestCase):
|
|||
return Item(
|
||||
artist=u'ben harper',
|
||||
album=u'burn to shine',
|
||||
title=u'ben harper - Burn to Shine ' + str(i),
|
||||
title=u'ben harper - Burn to Shine {0}'.format(i),
|
||||
track=i,
|
||||
length=length,
|
||||
mb_trackid='', mb_albumid='', mb_artistid='',
|
||||
|
|
@ -942,5 +945,5 @@ class EnumTest(_common.TestCase):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -15,11 +15,14 @@
|
|||
|
||||
"""Tests for the 'bucket' plugin."""
|
||||
|
||||
from _common import unittest
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from test._common import unittest
|
||||
from beetsplug import bucket
|
||||
from beets import config, ui
|
||||
|
||||
from helper import TestHelper
|
||||
from test.helper import TestHelper
|
||||
|
||||
|
||||
class BucketPluginTest(unittest.TestCase, TestHelper):
|
||||
|
|
@ -151,5 +154,5 @@ class BucketPluginTest(unittest.TestCase, TestHelper):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import os
|
||||
import yaml
|
||||
from mock import patch
|
||||
|
|
@ -7,9 +10,9 @@ from shutil import rmtree
|
|||
from beets import ui
|
||||
from beets import config
|
||||
|
||||
import _common
|
||||
from _common import unittest
|
||||
from helper import TestHelper, capture_stdout
|
||||
from test import _common
|
||||
from test._common import unittest
|
||||
from test.helper import TestHelper, capture_stdout
|
||||
from beets.library import Library
|
||||
|
||||
|
||||
|
|
@ -104,7 +107,7 @@ class ConfigCommandTest(unittest.TestCase, TestHelper):
|
|||
execlp.side_effect = OSError()
|
||||
self.run_command('config', '-e')
|
||||
self.assertIn('Could not edit configuration',
|
||||
str(user_error.exception.args[0]))
|
||||
unicode(user_error.exception.args[0]))
|
||||
|
||||
def test_edit_invalid_config_file(self):
|
||||
self.lib = Library(':memory:')
|
||||
|
|
@ -123,5 +126,5 @@ class ConfigCommandTest(unittest.TestCase, TestHelper):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -12,12 +12,15 @@
|
|||
# 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)
|
||||
|
||||
import re
|
||||
import os.path
|
||||
import _common
|
||||
from _common import unittest
|
||||
import helper
|
||||
from helper import control_stdin
|
||||
from test import _common
|
||||
from test._common import unittest
|
||||
from test import helper
|
||||
from test.helper import control_stdin
|
||||
|
||||
from beets.mediafile import MediaFile
|
||||
|
||||
|
|
@ -223,5 +226,5 @@ class NeverConvertLossyFilesTest(unittest.TestCase, TestHelper):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -14,8 +14,11 @@
|
|||
|
||||
"""Test for dbcore's date-based queries.
|
||||
"""
|
||||
import _common
|
||||
from _common import unittest
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from test import _common
|
||||
from test._common import unittest
|
||||
from datetime import datetime
|
||||
import time
|
||||
from beets.dbcore.query import _parse_periods, DateInterval, DateQuery
|
||||
|
|
@ -124,5 +127,5 @@ def suite():
|
|||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -14,10 +14,13 @@
|
|||
|
||||
"""Tests for the DBCore database abstraction.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import os
|
||||
import sqlite3
|
||||
|
||||
from _common import unittest
|
||||
from test._common import unittest
|
||||
from beets import dbcore
|
||||
from tempfile import mkstemp
|
||||
|
||||
|
|
@ -187,7 +190,7 @@ class ModelTest(unittest.TestCase):
|
|||
model.field_one = 123
|
||||
model.store()
|
||||
row = self.db._connection().execute('select * from test').fetchone()
|
||||
self.assertEqual(row['field_one'], 123)
|
||||
self.assertEqual(row[b'field_one'], 123)
|
||||
|
||||
def test_retrieve_by_id(self):
|
||||
model = TestModel1()
|
||||
|
|
@ -537,5 +540,5 @@ class ResultsIteratorTest(unittest.TestCase):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -13,11 +13,14 @@
|
|||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import os.path
|
||||
from mock import Mock, patch
|
||||
|
||||
from _common import unittest, RSRC
|
||||
from helper import TestHelper
|
||||
from test._common import unittest, RSRC
|
||||
from test.helper import TestHelper
|
||||
|
||||
from beets.library import Item
|
||||
|
||||
|
|
@ -180,5 +183,5 @@ class EchonestCliTest(unittest.TestCase, TestHelper):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -12,12 +12,15 @@
|
|||
# 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)
|
||||
|
||||
import os.path
|
||||
from mock import Mock, patch
|
||||
|
||||
import _common
|
||||
from _common import unittest
|
||||
from helper import TestHelper
|
||||
from test import _common
|
||||
from test._common import unittest
|
||||
from test.helper import TestHelper
|
||||
|
||||
from beets.mediafile import MediaFile
|
||||
from beets import config, logging, ui
|
||||
|
|
@ -147,5 +150,5 @@ class EmbedartTest(unittest.TestCase):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -12,9 +12,12 @@
|
|||
# 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)
|
||||
|
||||
import os
|
||||
from _common import unittest
|
||||
from helper import TestHelper
|
||||
from test._common import unittest
|
||||
from test.helper import TestHelper
|
||||
|
||||
|
||||
class FetchartCliTest(unittest.TestCase, TestHelper):
|
||||
|
|
@ -22,7 +25,7 @@ class FetchartCliTest(unittest.TestCase, TestHelper):
|
|||
def setUp(self):
|
||||
self.setup_beets()
|
||||
self.load_plugins('fetchart')
|
||||
self.config['fetchart']['cover_names'] = 'c\xc3\xb6ver.jpg'
|
||||
self.config['fetchart']['cover_names'] = b'c\xc3\xb6ver.jpg'
|
||||
self.config['art_filename'] = 'mycover'
|
||||
self.album = self.add_album()
|
||||
|
||||
|
|
@ -31,10 +34,10 @@ class FetchartCliTest(unittest.TestCase, TestHelper):
|
|||
self.teardown_beets()
|
||||
|
||||
def test_set_art_from_folder(self):
|
||||
self.touch('c\xc3\xb6ver.jpg', dir=self.album.path, content='IMAGE')
|
||||
self.touch(b'c\xc3\xb6ver.jpg', dir=self.album.path, content='IMAGE')
|
||||
|
||||
self.run_command('fetchart')
|
||||
cover_path = os.path.join(self.album.path, 'mycover.jpg')
|
||||
cover_path = os.path.join(self.album.path, b'mycover.jpg')
|
||||
|
||||
self.album.load()
|
||||
self.assertEqual(self.album['artpath'], cover_path)
|
||||
|
|
@ -42,7 +45,7 @@ class FetchartCliTest(unittest.TestCase, TestHelper):
|
|||
self.assertEqual(f.read(), 'IMAGE')
|
||||
|
||||
def test_filesystem_does_not_pick_up_folder(self):
|
||||
os.makedirs(os.path.join(self.album.path, 'mycover.jpg'))
|
||||
os.makedirs(os.path.join(self.album.path, b'mycover.jpg'))
|
||||
self.run_command('fetchart')
|
||||
self.album.load()
|
||||
self.assertEqual(self.album['artpath'], None)
|
||||
|
|
@ -51,5 +54,5 @@ class FetchartCliTest(unittest.TestCase, TestHelper):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -14,14 +14,17 @@
|
|||
|
||||
"""Test file manipulation functionality of Item.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import shutil
|
||||
import os
|
||||
import stat
|
||||
from os.path import join
|
||||
|
||||
import _common
|
||||
from _common import unittest
|
||||
from _common import item, touch
|
||||
from test import _common
|
||||
from test._common import unittest
|
||||
from test._common import item, touch
|
||||
import beets.library
|
||||
from beets import util
|
||||
|
||||
|
|
@ -621,5 +624,5 @@ class MkDirAllTest(_common.TestCase):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -14,7 +14,10 @@
|
|||
|
||||
"""Tests for the 'ftintitle' plugin."""
|
||||
|
||||
from _common import unittest
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from test._common import unittest
|
||||
from beetsplug import ftintitle
|
||||
|
||||
|
||||
|
|
@ -56,5 +59,5 @@ class FtInTitlePluginTest(unittest.TestCase):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
"""Tests for the 'ihate' plugin"""
|
||||
|
||||
from _common import unittest
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from test._common import unittest
|
||||
from beets import importer
|
||||
from beets.library import Item
|
||||
from beetsplug.ihate import IHatePlugin
|
||||
|
|
@ -46,5 +49,5 @@ class IHatePluginTest(unittest.TestCase):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -12,11 +12,14 @@
|
|||
# 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)
|
||||
|
||||
"""Tests for the `importadded` plugin."""
|
||||
|
||||
import os
|
||||
|
||||
from _common import unittest
|
||||
from test._common import unittest
|
||||
from test.test_importer import ImportHelper, AutotagStub
|
||||
from beets import importer
|
||||
from beets import util
|
||||
|
|
@ -168,5 +171,5 @@ class ImportAddedTest(unittest.TestCase, ImportHelper):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@
|
|||
# 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)
|
||||
|
||||
"""Tests for the general importer functionality.
|
||||
"""
|
||||
import os
|
||||
|
|
@ -24,10 +27,10 @@ from zipfile import ZipFile
|
|||
from tarfile import TarFile
|
||||
from mock import patch
|
||||
|
||||
import _common
|
||||
from _common import unittest
|
||||
from test import _common
|
||||
from test._common import unittest
|
||||
from beets.util import displayable_path
|
||||
from helper import TestImportSession, TestHelper, has_program, capture_log
|
||||
from test.helper import TestImportSession, TestHelper, has_program, capture_log
|
||||
from beets import importer
|
||||
from beets.importer import albums_in_dir
|
||||
from beets.mediafile import MediaFile
|
||||
|
|
@ -1617,5 +1620,5 @@ class ImportPretendTest(_common.TestCase, ImportHelper):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import tempfile
|
||||
import shutil
|
||||
|
||||
from _common import unittest
|
||||
from test._common import unittest
|
||||
from beets import config
|
||||
from beets.library import Item, Album, Library
|
||||
from beetsplug.importfeeds import ImportFeedsPlugin
|
||||
|
|
@ -57,5 +60,5 @@ class ImportfeedsTestTest(unittest.TestCase):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -12,8 +12,11 @@
|
|||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
from _common import unittest
|
||||
from helper import TestHelper
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from test._common import unittest
|
||||
from test.helper import TestHelper
|
||||
|
||||
from beets.mediafile import MediaFile
|
||||
|
||||
|
|
@ -57,7 +60,7 @@ class InfoTest(unittest.TestCase, TestHelper):
|
|||
|
||||
out = self.run_with_output('album:yyyy')
|
||||
self.assertIn(items[0].path, out)
|
||||
self.assertIn('album: xxxx', out)
|
||||
self.assertIn(b'album: xxxx', out)
|
||||
|
||||
self.assertNotIn(items[1].path, out)
|
||||
|
||||
|
|
@ -68,7 +71,7 @@ class InfoTest(unittest.TestCase, TestHelper):
|
|||
|
||||
out = self.run_with_output('--library', 'album:xxxx')
|
||||
self.assertIn(item.path, out)
|
||||
self.assertIn('album: xxxx', out)
|
||||
self.assertIn(b'album: xxxx', out)
|
||||
|
||||
def test_collect_item_and_path(self):
|
||||
path = self.create_mediafile_fixture()
|
||||
|
|
@ -93,5 +96,5 @@ class InfoTest(unittest.TestCase, TestHelper):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -12,9 +12,12 @@
|
|||
# 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 mock import patch
|
||||
from _common import unittest
|
||||
from helper import TestHelper
|
||||
from test._common import unittest
|
||||
from test.helper import TestHelper
|
||||
|
||||
from beets.library import Item
|
||||
|
||||
|
|
@ -78,5 +81,5 @@ class KeyFinderTest(unittest.TestCase, TestHelper):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -14,14 +14,17 @@
|
|||
|
||||
"""Tests for the 'lastgenre' plugin."""
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from mock import Mock
|
||||
|
||||
import _common
|
||||
from _common import unittest
|
||||
from test import _common
|
||||
from test._common import unittest
|
||||
from beetsplug import lastgenre
|
||||
from beets import config
|
||||
|
||||
from helper import TestHelper
|
||||
from test.helper import TestHelper
|
||||
|
||||
|
||||
class LastGenrePluginTest(unittest.TestCase, TestHelper):
|
||||
|
|
@ -213,5 +216,5 @@ class LastGenrePluginTest(unittest.TestCase, TestHelper):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
|
||||
"""Tests for non-query database functions of Item.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import stat
|
||||
|
|
@ -23,9 +26,9 @@ import re
|
|||
import unicodedata
|
||||
import sys
|
||||
|
||||
import _common
|
||||
from _common import unittest
|
||||
from _common import item
|
||||
from test import _common
|
||||
from test._common import unittest
|
||||
from test._common import item
|
||||
import beets.library
|
||||
import beets.mediafile
|
||||
from beets import util
|
||||
|
|
@ -57,7 +60,7 @@ class StoreTest(_common.LibTestCase):
|
|||
self.i.store()
|
||||
new_year = self.lib._connection().execute(
|
||||
'select year from items where '
|
||||
'title="the title"').fetchone()['year']
|
||||
'title="the title"').fetchone()[b'year']
|
||||
self.assertEqual(new_year, 1987)
|
||||
|
||||
def test_store_only_writes_dirty_fields(self):
|
||||
|
|
@ -66,7 +69,7 @@ class StoreTest(_common.LibTestCase):
|
|||
self.i.store()
|
||||
new_genre = self.lib._connection().execute(
|
||||
'select genre from items where '
|
||||
'title="the title"').fetchone()['genre']
|
||||
'title="the title"').fetchone()[b'genre']
|
||||
self.assertEqual(new_genre, original_genre)
|
||||
|
||||
def test_store_clears_dirty_flags(self):
|
||||
|
|
@ -85,7 +88,7 @@ class AddTest(_common.TestCase):
|
|||
self.lib.add(self.i)
|
||||
new_grouping = self.lib._connection().execute(
|
||||
'select grouping from items '
|
||||
'where composer="the composer"').fetchone()['grouping']
|
||||
'where composer="the composer"').fetchone()[b'grouping']
|
||||
self.assertEqual(new_grouping, self.i.grouping)
|
||||
|
||||
def test_library_add_path_inserts_row(self):
|
||||
|
|
@ -95,7 +98,7 @@ class AddTest(_common.TestCase):
|
|||
self.lib.add(i)
|
||||
new_grouping = self.lib._connection().execute(
|
||||
'select grouping from items '
|
||||
'where composer="the composer"').fetchone()['grouping']
|
||||
'where composer="the composer"').fetchone()[b'grouping']
|
||||
self.assertEqual(new_grouping, self.i.grouping)
|
||||
|
||||
|
||||
|
|
@ -440,7 +443,7 @@ class DestinationTest(_common.TestCase):
|
|||
self.i.title = u'h\u0259d'
|
||||
self.lib.path_formats = [('default', '$title')]
|
||||
p = self.i.destination()
|
||||
self.assertFalse('?' in p)
|
||||
self.assertFalse(b'?' in p)
|
||||
# We use UTF-8 to encode Windows paths now.
|
||||
self.assertTrue(u'h\u0259d'.encode('utf8') in p)
|
||||
finally:
|
||||
|
|
@ -922,25 +925,25 @@ class PathStringTest(_common.TestCase):
|
|||
self.i = item(self.lib)
|
||||
|
||||
def test_item_path_is_bytestring(self):
|
||||
self.assert_(isinstance(self.i.path, str))
|
||||
self.assert_(isinstance(self.i.path, bytes))
|
||||
|
||||
def test_fetched_item_path_is_bytestring(self):
|
||||
i = list(self.lib.items())[0]
|
||||
self.assert_(isinstance(i.path, str))
|
||||
self.assert_(isinstance(i.path, bytes))
|
||||
|
||||
def test_unicode_path_becomes_bytestring(self):
|
||||
self.i.path = u'unicodepath'
|
||||
self.assert_(isinstance(self.i.path, str))
|
||||
self.assert_(isinstance(self.i.path, bytes))
|
||||
|
||||
def test_unicode_in_database_becomes_bytestring(self):
|
||||
self.lib._connection().execute("""
|
||||
update items set path=? where id=?
|
||||
""", (self.i.id, u'somepath'))
|
||||
i = list(self.lib.items())[0]
|
||||
self.assert_(isinstance(i.path, str))
|
||||
self.assert_(isinstance(i.path, bytes))
|
||||
|
||||
def test_special_chars_preserved_in_database(self):
|
||||
path = 'b\xe1r'
|
||||
path = 'b\xe1r'.encode('utf8')
|
||||
self.i.path = path
|
||||
self.i.store()
|
||||
i = list(self.lib.items())[0]
|
||||
|
|
@ -948,7 +951,7 @@ class PathStringTest(_common.TestCase):
|
|||
|
||||
def test_special_char_path_added_to_database(self):
|
||||
self.i.remove()
|
||||
path = 'b\xe1r'
|
||||
path = 'b\xe1r'.encode('utf8')
|
||||
i = item()
|
||||
i.path = path
|
||||
self.lib.add(i)
|
||||
|
|
@ -958,13 +961,13 @@ class PathStringTest(_common.TestCase):
|
|||
def test_destination_returns_bytestring(self):
|
||||
self.i.artist = u'b\xe1r'
|
||||
dest = self.i.destination()
|
||||
self.assert_(isinstance(dest, str))
|
||||
self.assert_(isinstance(dest, bytes))
|
||||
|
||||
def test_art_destination_returns_bytestring(self):
|
||||
self.i.artist = u'b\xe1r'
|
||||
alb = self.lib.add_album([self.i])
|
||||
dest = alb.art_destination(u'image.jpg')
|
||||
self.assert_(isinstance(dest, str))
|
||||
self.assert_(isinstance(dest, bytes))
|
||||
|
||||
def test_artpath_stores_special_chars(self):
|
||||
path = b'b\xe1r'
|
||||
|
|
@ -987,7 +990,7 @@ class PathStringTest(_common.TestCase):
|
|||
def test_unicode_artpath_becomes_bytestring(self):
|
||||
alb = self.lib.add_album([self.i])
|
||||
alb.artpath = u'somep\xe1th'
|
||||
self.assert_(isinstance(alb.artpath, str))
|
||||
self.assert_(isinstance(alb.artpath, bytes))
|
||||
|
||||
def test_unicode_artpath_in_database_decoded(self):
|
||||
alb = self.lib.add_album([self.i])
|
||||
|
|
@ -996,7 +999,7 @@ class PathStringTest(_common.TestCase):
|
|||
(u'somep\xe1th', alb.id)
|
||||
)
|
||||
alb = self.lib.get_album(alb.id)
|
||||
self.assert_(isinstance(alb.artpath, str))
|
||||
self.assert_(isinstance(alb.artpath, bytes))
|
||||
|
||||
|
||||
class PathTruncationTest(_common.TestCase):
|
||||
|
|
@ -1159,5 +1162,5 @@ def suite():
|
|||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
"""Stupid tests that ensure logging works as expected"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import logging as log
|
||||
from StringIO import StringIO
|
||||
|
||||
import beets.logging as blog
|
||||
from _common import unittest, TestCase
|
||||
from test._common import unittest, TestCase
|
||||
|
||||
|
||||
class LoggingTest(TestCase):
|
||||
|
|
@ -38,5 +41,5 @@ def suite():
|
|||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -14,14 +14,17 @@
|
|||
|
||||
"""Tests for the 'lyrics' plugin."""
|
||||
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import os
|
||||
import _common
|
||||
from test import _common
|
||||
import sys
|
||||
import re
|
||||
|
||||
from mock import MagicMock
|
||||
|
||||
from _common import unittest
|
||||
from test._common import unittest
|
||||
from beetsplug import lyrics
|
||||
from beets.library import Item
|
||||
from beets.util import confit
|
||||
|
|
@ -376,5 +379,5 @@ class LyricsGooglePluginTest(unittest.TestCase):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -14,8 +14,11 @@
|
|||
|
||||
"""Tests for MusicBrainz API wrapper.
|
||||
"""
|
||||
import _common
|
||||
from _common import unittest
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
from test import _common
|
||||
from test._common import unittest
|
||||
from beets.autotag import mb
|
||||
from beets import config
|
||||
import mock
|
||||
|
|
@ -63,7 +66,7 @@ class MBAlbumInfoTest(_common.TestCase):
|
|||
for i, recording in enumerate(tracks):
|
||||
track = {
|
||||
'recording': recording,
|
||||
'position': str(i + 1),
|
||||
'position': bytes(i + 1),
|
||||
}
|
||||
if track_length:
|
||||
# Track lengths are distinct from recording lengths.
|
||||
|
|
@ -483,5 +486,5 @@ class MBLibraryTest(unittest.TestCase):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -12,10 +12,13 @@
|
|||
# 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 mock import patch
|
||||
|
||||
from _common import unittest
|
||||
from helper import TestHelper,\
|
||||
from test._common import unittest
|
||||
from test.helper import TestHelper,\
|
||||
generate_album_info, \
|
||||
generate_track_info, \
|
||||
capture_log
|
||||
|
|
@ -124,5 +127,5 @@ class MbsyncCliTest(unittest.TestCase, TestHelper):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
|
|
@ -15,14 +15,17 @@
|
|||
"""Automatically-generated blanket testing for the MediaFile metadata
|
||||
layer.
|
||||
"""
|
||||
from __future__ import (division, absolute_import, print_function,
|
||||
unicode_literals)
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
import datetime
|
||||
import time
|
||||
|
||||
import _common
|
||||
from _common import unittest
|
||||
from test import _common
|
||||
from test._common import unittest
|
||||
from beets.mediafile import MediaFile, MediaField, Image, \
|
||||
MP3DescStorageStyle, StorageStyle, MP4StorageStyle, \
|
||||
ASFStorageStyle, ImageType
|
||||
|
|
@ -283,10 +286,10 @@ class GenreListTestMixin(object):
|
|||
|
||||
|
||||
field_extension = MediaField(
|
||||
MP3DescStorageStyle('customtag'),
|
||||
MP4StorageStyle('----:com.apple.iTunes:customtag'),
|
||||
StorageStyle('customtag'),
|
||||
ASFStorageStyle('customtag'),
|
||||
MP3DescStorageStyle(b'customtag'),
|
||||
MP4StorageStyle(b'----:com.apple.iTunes:customtag'),
|
||||
StorageStyle(b'customtag'),
|
||||
ASFStorageStyle(b'customtag'),
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -337,12 +340,14 @@ class ExtendedFieldTestMixin(object):
|
|||
def test_invalid_descriptor(self):
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
MediaFile.add_field('somekey', True)
|
||||
self.assertIn('must be an instance of MediaField', str(cm.exception))
|
||||
self.assertIn('must be an instance of MediaField',
|
||||
unicode(cm.exception))
|
||||
|
||||
def test_overwrite_property(self):
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
MediaFile.add_field('artist', MediaField())
|
||||
self.assertIn('property "artist" already exists', str(cm.exception))
|
||||
self.assertIn('property "artist" already exists',
|
||||
unicode(cm.exception))
|
||||
|
||||
|
||||
class ReadWriteTestBase(ArtTestMixin, GenreListTestMixin,
|
||||
|
|
@ -679,7 +684,7 @@ class ReadWriteTestBase(ArtTestMixin, GenreListTestMixin,
|
|||
# ReplayGain is float
|
||||
tags[key] = 1.0
|
||||
else:
|
||||
tags[key] = 'value\u2010%s' % key
|
||||
tags[key] = b'value\u2010%s' % key
|
||||
|
||||
for key in ['disc', 'disctotal', 'track', 'tracktotal', 'bpm']:
|
||||
tags[key] = 1
|
||||
|
|
@ -698,6 +703,7 @@ class ReadWriteTestBase(ArtTestMixin, GenreListTestMixin,
|
|||
tags['original_year'] = original_date.year
|
||||
tags['original_month'] = original_date.month
|
||||
tags['original_day'] = original_date.day
|
||||
|
||||
return tags
|
||||
|
||||
|
||||
|
|
@ -939,5 +945,5 @@ class MediaFieldTest(unittest.TestCase):
|
|||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == b'__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue