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:
Adrian Sampson 2015-01-26 17:02:07 -08:00
commit b8dab9cf9f
119 changed files with 736 additions and 398 deletions

View file

@ -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>'

View file

@ -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

View file

@ -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'))

View file

@ -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,

View file

@ -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()):

View file

@ -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

View file

@ -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)

View file

@ -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):

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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'),
)

View file

@ -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, {})

View file

@ -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)

View file

@ -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]

View file

@ -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:

View file

@ -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),
}))

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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'}

View file

@ -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

View file

@ -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

View file

@ -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__)

View file

@ -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

View file

@ -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

View file

@ -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))

View file

@ -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

View file

@ -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

View file

@ -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:

View file

@ -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:

View file

@ -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):

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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}',

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -15,6 +15,9 @@
"""Shows file metadata.
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)
import os
from beets.plugins import BeetsPlugin

View file

@ -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

View file

@ -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

View file

@ -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'#'):

View file

@ -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()

View file

@ -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'&nbsp;', u' ')

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 = {

View file

@ -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

View file

@ -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

View file

@ -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))

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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()

View file

@ -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

View file

@ -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:

View file

@ -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)

View file

@ -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())

View file

@ -1,3 +1,6 @@
from __future__ import (division, absolute_import, print_function,
unicode_literals)
from beets.plugins import BeetsPlugin
from beets import ui

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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')

View file

@ -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