Merge remote-tracking branch 'refs/remotes/beetbox/master'

This commit is contained in:
Rob McGhee 2016-07-20 21:13:32 +01:00
commit 84b8cf0ab5
18 changed files with 68 additions and 51 deletions

5
.gitignore vendored
View file

@ -84,3 +84,8 @@ ENV/
# Rope project settings
.ropeproject
# PyDev and Eclipse project settings
/.project
/.pydevproject
/.settings

View file

@ -17,14 +17,13 @@ matrix:
env: {TOX_ENV: py35-test}
# - python: pypy
# - env: {TOX_ENV: pypy-test}
- python: 2.7
env: {TOX_ENV: py27-flake8}
- python: 3.4
env: {TOX_ENV: py34-flake8}
- python: 2.7
env: {TOX_ENV: docs}
allow_failures:
- python: 3.4
env: {TOX_ENV: py34-test}
- python: 3.5
# Non-Python dependencies.

View file

@ -327,6 +327,11 @@ def _recommendation(results):
return rec
def _sort_candidates(candidates):
"""Sort candidates by distance."""
return sorted(candidates, key=lambda match: match.distance)
def _add_candidate(items, results, info):
"""Given a candidate AlbumInfo object, attempt to add the candidate
to the output dictionary of AlbumMatch objects. This involves
@ -443,7 +448,7 @@ def tag_album(items, search_artist=None, search_album=None,
_add_candidate(items, candidates, info)
# Sort and get the recommendation.
candidates = sorted(candidates.values())
candidates = _sort_candidates(candidates.values())
rec = _recommendation(candidates)
return cur_artist, cur_album, candidates, rec
@ -471,16 +476,16 @@ def tag_item(item, search_artist=None, search_title=None,
candidates[track_info.track_id] = \
hooks.TrackMatch(dist, track_info)
# If this is a good match, then don't keep searching.
rec = _recommendation(sorted(candidates.values()))
rec = _recommendation(_sort_candidates(candidates.values()))
if rec == Recommendation.strong and \
not config['import']['timid']:
log.debug(u'Track ID match.')
return sorted(candidates.values()), rec
return _sort_candidates(candidates.values()), rec
# If we're searching by ID, don't proceed.
if search_ids:
if candidates:
return sorted(candidates.values()), rec
return _sort_candidates(candidates.values()), rec
else:
return [], Recommendation.none
@ -496,6 +501,6 @@ def tag_item(item, search_artist=None, search_title=None,
# Sort by distance and return with recommendation.
log.debug(u'Found {0} candidates.', len(candidates))
candidates = sorted(candidates.values())
candidates = _sort_candidates(candidates.values())
rec = _recommendation(candidates)
return candidates, rec

View file

@ -944,7 +944,7 @@ class ArchiveImportTask(SentinelImportTask):
return False
for path_test, _ in cls.handlers():
if path_test(path):
if path_test(util.py3_path(path)):
return True
return False
@ -990,7 +990,7 @@ class ArchiveImportTask(SentinelImportTask):
try:
extract_to = mkdtemp()
archive = handler_class(self.toppath, mode='r')
archive = handler_class(util.py3_path(self.toppath), mode='r')
archive.extractall(extract_to)
finally:
archive.close()

View file

@ -443,8 +443,7 @@ def move(path, dest, replace=False):
path = syspath(path)
dest = syspath(dest)
if os.path.exists(dest) and not replace:
raise FilesystemError(u'file exists', 'rename', (path, dest),
traceback.format_exc())
raise FilesystemError(u'file exists', 'rename', (path, dest))
# First, try renaming the file.
try:
@ -469,13 +468,19 @@ def link(path, dest, replace=False):
path = syspath(path)
dest = syspath(dest)
if os.path.exists(dest) and not replace:
raise FilesystemError(u'file exists', 'rename', (path, dest),
traceback.format_exc())
raise FilesystemError(u'file exists', 'rename', (path, dest))
try:
os.symlink(path, dest)
except OSError:
raise FilesystemError(u'Operating system does not support symbolic '
u'links.', 'link', (path, dest),
except NotImplementedError:
# raised on python >= 3.2 and Windows versions before Vista
raise FilesystemError(u'OS does not support symbolic links.'
'link', (path, dest), traceback.format_exc())
except OSError as exc:
# TODO: Windows version checks can be removed for python 3
if hasattr('sys', 'getwindowsversion'):
if sys.getwindowsversion()[0] < 6: # is before Vista
exc = u'OS does not support symbolic links.'
raise FilesystemError(exc, 'link', (path, dest),
traceback.format_exc())

View file

@ -640,8 +640,8 @@ class Command(object):
"""A command issued by the client for processing by the server.
"""
command_re = re.compile(br'^([^ \t]+)[ \t]*')
arg_re = re.compile(br'"((?:\\"|[^"])+)"|([^ \t"]+)')
command_re = re.compile(r'^([^ \t]+)[ \t]*')
arg_re = re.compile(r'"((?:\\"|[^"])+)"|([^ \t"]+)')
def __init__(self, s):
"""Creates a new `Command` from the given string, `s`, parsing
@ -656,11 +656,10 @@ class Command(object):
if match[0]:
# Quoted argument.
arg = match[0]
arg = arg.replace(b'\\"', b'"').replace(b'\\\\', b'\\')
arg = arg.replace('\\"', '"').replace('\\\\', '\\')
else:
# Unquoted argument.
arg = match[1]
arg = arg.decode('utf8')
self.args.append(arg)
def run(self, conn):

View file

@ -29,9 +29,9 @@ from six.moves import urllib
from beets import ui
import gi
from gi.repository import GLib, Gst
gi.require_version('Gst', '1.0')
from gi.repository import GLib, Gst # noqa ignore=E402
Gst.init(None)

View file

@ -47,7 +47,7 @@ def replace_ext(path, ext):
The new extension must not contain a leading dot.
"""
ext_dot = util.bytestring_path('.' + ext)
ext_dot = b'.' + ext
return os.path.splitext(path)[0] + ext_dot
@ -68,7 +68,7 @@ def get_format(fmt=None):
.format(fmt)
)
except ConfigTypeError:
command = config['convert']['formats'][fmt].get(bytes)
command = config['convert']['formats'][fmt].get(str)
extension = fmt
# Convenience and backwards-compatibility shortcuts.
@ -428,7 +428,9 @@ class ConvertPlugin(BeetsPlugin):
# Create a temporary file for the conversion.
tmpdir = self.config['tmpdir'].get()
fd, dest = tempfile.mkstemp('.' + ext, dir=tmpdir)
if tmpdir:
tmpdir = util.py3_path(util.bytestring_path(tmpdir))
fd, dest = tempfile.mkstemp(util.py3_path(b'.' + ext), dir=tmpdir)
os.close(fd)
dest = util.bytestring_path(dest)
_temp_files.append(dest) # Delete the transcode later.

View file

@ -24,7 +24,7 @@ import os
import re
from beets.plugins import BeetsPlugin
from beets.util import mkdirall, normpath, syspath, bytestring_path
from beets.util import mkdirall, normpath, syspath, bytestring_path, link
from beets import config
M3U_DEFAULT_NAME = 'imported.m3u'
@ -131,7 +131,7 @@ class ImportFeedsPlugin(BeetsPlugin):
for path in paths:
dest = os.path.join(feedsdir, os.path.basename(path))
if not os.path.exists(syspath(dest)):
os.symlink(syspath(path), syspath(dest))
link(path, dest)
if 'echo' in formats:
self._log.info(u"Location of imported music:")

View file

@ -25,6 +25,7 @@ The scraper script used is available here:
https://gist.github.com/1241307
"""
import pylast
import codecs
import os
import yaml
import traceback
@ -140,7 +141,8 @@ class LastGenrePlugin(plugins.BeetsPlugin):
c14n_filename = C14N_TREE
if c14n_filename:
c14n_filename = normpath(c14n_filename)
genres_tree = yaml.load(open(c14n_filename, 'r'))
genres_file = codecs.open(c14n_filename, 'r', encoding='utf-8')
genres_tree = yaml.load(genres_file)
flatten_tree(genres_tree, [], self.c14n_branches)
@property

View file

@ -137,8 +137,7 @@ class PlayPlugin(BeetsPlugin):
else:
open_args = [self._create_tmp_playlist(paths)]
self._log.debug(u'executing command: {} {}', command_str,
util.text_string(b' '.join(open_args)))
self._log.debug(u'executing command: {} {!r}', command_str, open_args)
try:
util.interactive_open(open_args, command_str)
except OSError as exc:

View file

@ -308,9 +308,9 @@ class CommandBackend(Backend):
def format_supported(self, item):
"""Checks whether the given item is supported by the selected tool.
"""
if 'mp3gain' in self.command and item.format != 'MP3':
if b'mp3gain' in self.command and item.format != 'MP3':
return False
elif 'aacgain' in self.command and item.format not in ('MP3', 'AAC'):
elif b'aacgain' in self.command and item.format not in ('MP3', 'AAC'):
return False
return True

View file

@ -53,7 +53,7 @@ log.setLevel(logging.DEBUG)
_item_ident = 0
# OS feature test.
HAVE_SYMLINK = hasattr(os, 'symlink')
HAVE_SYMLINK = sys.platform != 'win32'
def item(lib=None):

View file

@ -422,6 +422,7 @@ class TestHelper(object):
# Running beets commands
def run_command(self, *args):
sys.argv = ['beet'] # avoid leakage from test suite args
if hasattr(self, 'lib'):
lib = self.lib
else:

View file

@ -30,7 +30,7 @@ from mock import patch
from test import _common
from test._common import unittest
from beets.util import displayable_path, bytestring_path
from beets.util import displayable_path, bytestring_path, py3_path
from test.helper import TestImportSession, TestHelper, has_program, capture_log
from beets import importer
from beets.importer import albums_in_dir
@ -355,9 +355,9 @@ class NonAutotaggedImportTest(_common.TestCase, ImportHelper):
def create_archive(session):
(handle, path) = mkstemp(dir=session.temp_dir)
(handle, path) = mkstemp(dir=py3_path(session.temp_dir))
os.close(handle)
archive = ZipFile(path, mode='w')
archive = ZipFile(py3_path(path), mode='w')
archive.write(os.path.join(_common.RSRC, b'full.mp3'),
'full.mp3')
archive.close()
@ -414,7 +414,7 @@ class ImportTarTest(ImportZipTest):
def create_archive(self):
(handle, path) = mkstemp(dir=self.temp_dir)
os.close(handle)
archive = TarFile(path, mode='w')
archive = TarFile(py3_path(path), mode='w')
archive.add(os.path.join(_common.RSRC, b'full.mp3'),
'full.mp3')
archive.close()

View file

@ -46,7 +46,7 @@ class KeyFinderTest(unittest.TestCase, TestHelper):
item.load()
self.assertEqual(item['initial_key'], 'C#m')
self.command_output.assert_called_with(
['KeyFinder', '-f', util.syspath(item.path)])
[b'KeyFinder', b'-f', util.syspath(item.path)])
def test_add_key_on_import(self):
self.command_output.return_value = 'dbm'

View file

@ -48,7 +48,7 @@ class TypesPluginTest(unittest.TestCase, TestHelper):
# Match in range
out = self.list(u'myint:1..3')
self.assertIn(b'aaa', out)
self.assertIn('aaa', out)
def test_album_integer_modify_and_query(self):
self.config['types'] = {'myint': u'int'}
@ -64,7 +64,7 @@ class TypesPluginTest(unittest.TestCase, TestHelper):
# Match in range
out = self.list_album(u'myint:1..3')
self.assertIn(b'aaa', out)
self.assertIn('aaa', out)
def test_float_modify_and_query(self):
self.config['types'] = {'myfloat': u'float'}
@ -76,7 +76,7 @@ class TypesPluginTest(unittest.TestCase, TestHelper):
# Match in range
out = self.list(u'myfloat:-10..0')
self.assertIn(b'aaa', out)
self.assertIn('aaa', out)
def test_bool_modify_and_query(self):
self.config['types'] = {'mybool': u'bool'}

View file

@ -774,7 +774,7 @@ class ConfigTest(unittest.TestCase, TestHelper, _common.Assertions):
])
def test_cli_config_option(self):
config_path = os.path.join(self.temp_dir, 'config.yaml')
config_path = os.path.join(self.temp_dir, b'config.yaml')
with open(config_path, 'w') as file:
file.write('anoption: value')
@ -785,7 +785,7 @@ class ConfigTest(unittest.TestCase, TestHelper, _common.Assertions):
with open(self.user_config_path, 'w') as file:
file.write('anoption: value')
cli_config_path = os.path.join(self.temp_dir, 'config.yaml')
cli_config_path = os.path.join(self.temp_dir, b'config.yaml')
with open(cli_config_path, 'w') as file:
file.write('anoption: cli overwrite')
@ -798,7 +798,7 @@ class ConfigTest(unittest.TestCase, TestHelper, _common.Assertions):
with open(env_config_path, 'w') as file:
file.write('anoption: value')
cli_config_path = os.path.join(self.temp_dir, 'config.yaml')
cli_config_path = os.path.join(self.temp_dir, b'config.yaml')
with open(cli_config_path, 'w') as file:
file.write('anoption: cli overwrite')
@ -807,8 +807,8 @@ class ConfigTest(unittest.TestCase, TestHelper, _common.Assertions):
# @unittest.skip('Difficult to implement with optparse')
# def test_multiple_cli_config_files(self):
# cli_config_path_1 = os.path.join(self.temp_dir, 'config.yaml')
# cli_config_path_2 = os.path.join(self.temp_dir, 'config_2.yaml')
# cli_config_path_1 = os.path.join(self.temp_dir, b'config.yaml')
# cli_config_path_2 = os.path.join(self.temp_dir, b'config_2.yaml')
#
# with open(cli_config_path_1, 'w') as file:
# file.write('first: value')
@ -823,9 +823,9 @@ class ConfigTest(unittest.TestCase, TestHelper, _common.Assertions):
#
# @unittest.skip('Difficult to implement with optparse')
# def test_multiple_cli_config_overwrite(self):
# cli_config_path = os.path.join(self.temp_dir, 'config.yaml')
# cli_config_path = os.path.join(self.temp_dir, b'config.yaml')
# cli_overwrite_config_path = os.path.join(self.temp_dir,
# 'overwrite_config.yaml')
# b'overwrite_config.yaml')
#
# with open(cli_config_path, 'w') as file:
# file.write('anoption: value')
@ -838,7 +838,7 @@ class ConfigTest(unittest.TestCase, TestHelper, _common.Assertions):
# self.assertEqual(config['anoption'].get(), 'cli overwrite')
def test_cli_config_paths_resolve_relative_to_user_dir(self):
cli_config_path = os.path.join(self.temp_dir, 'config.yaml')
cli_config_path = os.path.join(self.temp_dir, b'config.yaml')
with open(cli_config_path, 'w') as file:
file.write('library: beets.db\n')
file.write('statefile: state')
@ -856,7 +856,7 @@ class ConfigTest(unittest.TestCase, TestHelper, _common.Assertions):
def test_cli_config_paths_resolve_relative_to_beetsdir(self):
os.environ['BEETSDIR'] = util.py3_path(self.beetsdir)
cli_config_path = os.path.join(self.temp_dir, 'config.yaml')
cli_config_path = os.path.join(self.temp_dir, b'config.yaml')
with open(cli_config_path, 'w') as file:
file.write('library: beets.db\n')
file.write('statefile: state')
@ -878,7 +878,7 @@ class ConfigTest(unittest.TestCase, TestHelper, _common.Assertions):
os.path.join(os.getcwd(), 'foo.db'))
def test_cli_config_file_loads_plugin_commands(self):
cli_config_path = os.path.join(self.temp_dir, 'config.yaml')
cli_config_path = os.path.join(self.temp_dir, b'config.yaml')
with open(cli_config_path, 'w') as file:
file.write('pluginpath: %s\n' % _common.PLUGINPATH)
file.write('plugins: test')