diff --git a/beets/autotag/art.py b/beets/autotag/art.py index 682f22a98..2a6a692c8 100644 --- a/beets/autotag/art.py +++ b/beets/autotag/art.py @@ -8,20 +8,17 @@ # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: -# +# # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. -"""Finding album art for tagged albums.""" - +"""Finding album art for tagged albums. +""" import urllib -import sys import logging import os import re -from beets.autotag.mb import album_for_id - IMAGE_EXTENSIONS = ['png', 'jpg', 'jpeg'] COVER_NAMES = ['cover', 'front', 'art', 'album', 'folder'] @@ -134,19 +131,3 @@ def art_for_album(album, path): else: log.debug('No ASIN available: no art found.') return None - - -# Smoke test. - -if __name__ == '__main__': - aid = sys.argv[1] - album = album_for_id(aid) - if not album: - print 'album not found' - else: - fn = art_for_album(album, None) - if fn: - print fn - print len(open(fn).read())/1024 - else: - print 'no art found' diff --git a/beets/importer.py b/beets/importer.py index 5b6dc5ba2..16b4720a1 100644 --- a/beets/importer.py +++ b/beets/importer.py @@ -15,6 +15,8 @@ """Provides the basic, interface-agnostic workflow for importing and autotagging music files. """ +from __future__ import print_function + import os import logging import pickle @@ -55,7 +57,7 @@ def tag_log(logfile, status, path): reflect the reason the album couldn't be tagged. """ if logfile: - print >>logfile, '%s %s' % (status, path) + print('{0} {1}'.format(status, path), file=logfile) logfile.flush() def log_choice(config, task, duplicate=False): diff --git a/beets/ui/__init__.py b/beets/ui/__init__.py index f19baf14d..2384f2ad9 100644 --- a/beets/ui/__init__.py +++ b/beets/ui/__init__.py @@ -16,6 +16,8 @@ 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 + import os import locale import optparse @@ -106,7 +108,7 @@ def print_(*strings): txt = u'' if isinstance(txt, unicode): txt = txt.encode(_encoding(), 'replace') - print txt + print(txt) def input_options(options, require=False, prompt=None, fallback_prompt=None, numrange=None, default=None, color=False, max_width=72): diff --git a/beets/ui/commands.py b/beets/ui/commands.py index 7a46482d3..9830c62c3 100644 --- a/beets/ui/commands.py +++ b/beets/ui/commands.py @@ -15,6 +15,8 @@ """This module provides the default commands for beets' command-line interface. """ +from __future__ import print_function + import logging import sys import os @@ -87,10 +89,10 @@ def _showdiff(field, oldval, newval, color): fields_cmd = ui.Subcommand('fields', help='show fields available for queries and format strings') def fields_func(lib, config, opts, args): - print "Available item fields:" - print " " + "\n ".join([key for key in library.ITEM_KEYS]) - print "\nAvailable album fields:" - print " " + "\n ".join([key for key in library.ALBUM_KEYS]) + print("Available item fields:") + print(" " + "\n ".join([key for key in library.ITEM_KEYS])) + print("\nAvailable album fields:") + print(" " + "\n ".join([key for key in library.ALBUM_KEYS])) fields_cmd.func = fields_func default_commands.append(fields_cmd) @@ -651,7 +653,7 @@ def import_files(lib, paths, copy, move, write, autot, logpath, art, threaded, except IOError: raise ui.UserError(u"could not open log file for writing: %s" % displayable_path(logpath)) - print >>logfile, 'import started', time.asctime() + print('import started', time.asctime(), file=logfile) else: logfile = None @@ -690,7 +692,7 @@ def import_files(lib, paths, copy, move, write, autot, logpath, art, threaded, finally: # If we were logging, close the file. if logfile: - print >>logfile, '' + print('', file=logfile) logfile.close() # Emit event. @@ -1035,16 +1037,16 @@ default_commands.append(stats_cmd) # version: Show current beets version. def show_version(lib, config, opts, args): - print 'beets version %s' % beets.__version__ + print_('beets version %s' % beets.__version__) # Show plugins. names = [] for plugin in plugins.find_plugins(): modname = plugin.__module__ names.append(modname.split('.')[-1]) if names: - print 'plugins:', ', '.join(names) + print_('plugins:', ', '.join(names)) else: - print 'no plugins loaded' + print_('no plugins loaded') version_cmd = ui.Subcommand('version', help='output version information') version_cmd.func = show_version diff --git a/beets/util/enumeration.py b/beets/util/enumeration.py index 7c4c1939c..f4968025a 100644 --- a/beets/util/enumeration.py +++ b/beets/util/enumeration.py @@ -120,7 +120,7 @@ class Enumerated(object): >>> class Garment(Enumerated): ... values = 'hat glove belt poncho lederhosen suspenders' ... def wear(self): - ... print 'now wearing a ' + self.name + ... print('now wearing a ' + self.name) ... >>> Garment.poncho.wear() now wearing a poncho diff --git a/beets/util/functemplate.py b/beets/util/functemplate.py index 2fca94673..c03c4a208 100644 --- a/beets/util/functemplate.py +++ b/beets/util/functemplate.py @@ -25,6 +25,8 @@ 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 + import re import ast import dis @@ -548,9 +550,9 @@ if __name__ == '__main__': interp_time = timeit.timeit('_tmpl.interpret(_vars, _funcs)', 'from __main__ import _tmpl, _vars, _funcs', number=10000) - print interp_time + print(interp_time) comp_time = timeit.timeit('_tmpl.substitute(_vars, _funcs)', 'from __main__ import _tmpl, _vars, _funcs', number=10000) - print comp_time - print 'Speedup:', interp_time / comp_time + print(comp_time) + print('Speedup:', interp_time / comp_time) diff --git a/beets/util/pipeline.py b/beets/util/pipeline.py index fd1de80b4..b81db3c7f 100644 --- a/beets/util/pipeline.py +++ b/beets/util/pipeline.py @@ -30,6 +30,8 @@ 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 + import Queue from threading import Thread, Lock import sys @@ -392,20 +394,20 @@ if __name__ == '__main__': # in parallel. def produce(): for i in range(5): - print 'generating %i' % i + print('generating %i' % i) time.sleep(1) yield i def work(): num = yield while True: - print 'processing %i' % num + print('processing %i' % num) time.sleep(2) num = yield num*2 def consume(): while True: num = yield time.sleep(1) - print 'received %i' % num + print('received %i' % num) ts_start = time.time() Pipeline([produce(), work(), consume()]).run_sequential() ts_seq = time.time() @@ -413,21 +415,21 @@ if __name__ == '__main__': ts_par = time.time() Pipeline([produce(), (work(), work()), consume()]).run_parallel() ts_end = time.time() - print 'Sequential time:', ts_seq - ts_start - print 'Parallel time:', ts_par - ts_seq - print 'Multiply-parallel time:', ts_end - ts_par - print + print('Sequential time:', ts_seq - ts_start) + print('Parallel time:', ts_par - ts_seq) + print('Multiply-parallel time:', ts_end - ts_par) + print() # Test a pipeline that raises an exception. def exc_produce(): for i in range(10): - print 'generating %i' % i + print('generating %i' % i) time.sleep(1) yield i def exc_work(): num = yield while True: - print 'processing %i' % num + print('processing %i' % num) time.sleep(3) if num == 3: raise Exception() @@ -437,5 +439,5 @@ if __name__ == '__main__': num = yield #if num == 4: # raise Exception() - print 'received %i' % num + print('received %i' % num) Pipeline([exc_produce(), exc_work(), exc_consume()]).run_parallel(1) diff --git a/beetsplug/bench.py b/beetsplug/bench.py index 6dffe6d73..b5b89db2d 100644 --- a/beetsplug/bench.py +++ b/beetsplug/bench.py @@ -12,6 +12,10 @@ # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. +"""Some simple performance benchmarks for beets. +""" +from __future__ import print_function + from beets.plugins import BeetsPlugin from beets import ui from beets import vfs @@ -34,7 +38,7 @@ def benchmark(lib, prof): 'paths.withaunique.prof') else: interval = timeit.timeit(_build_tree, number=1) - print 'With %aunique:', interval + print('With %aunique:', interval) # And with %aunique replaceed with a "cheap" no-op function. lib.path_formats = [ @@ -46,7 +50,7 @@ def benchmark(lib, prof): 'paths.withoutaunique.prof') else: interval = timeit.timeit(_build_tree, number=1) - print 'Without %aunique:', interval + print('Without %aunique:', interval) class BenchmarkPlugin(BeetsPlugin): """A plugin for performing some simple performance benchmarks. diff --git a/beetsplug/bpd/__init__.py b/beetsplug/bpd/__init__.py index 2170445a8..0a238396a 100644 --- a/beetsplug/bpd/__init__.py +++ b/beetsplug/bpd/__init__.py @@ -16,6 +16,7 @@ Beets library. Attempts to implement a compatible protocol to allow use of the wide range of MPD clients. """ +from __future__ import print_function import bluelet import re @@ -536,7 +537,7 @@ class BaseServer(object): """Memory profiling for debugging.""" from guppy import hpy heap = hpy().heap() - print heap + print(heap) class Connection(object): """A connection between a client and the server. Handles input and @@ -789,9 +790,9 @@ class Server(BaseServer): """ # Path is ignored. Also, the real MPD does this asynchronously; # this is done inline. - print 'Building directory tree...' + print('Building directory tree...') self.tree = vfs.libtree(self.lib) - print '... done.' + print('... done.') self.updated_time = time.time() diff --git a/beetsplug/bpd/gstplayer.py b/beetsplug/bpd/gstplayer.py index 2317a4300..b100f33bc 100644 --- a/beetsplug/bpd/gstplayer.py +++ b/beetsplug/bpd/gstplayer.py @@ -15,6 +15,7 @@ """A wrapper for the GStreamer Python bindings that exposes a simple music player. """ +from __future__ import print_function import gst import sys @@ -83,7 +84,7 @@ class GstPlayer(object): # error self.player.set_state(gst.STATE_NULL) err, debug = message.parse_error() - print "Error: " + str(err) + print("Error: " + str(err)) self.playing = False def _set_volume(self, volume): diff --git a/beetsplug/lyrics.py b/beetsplug/lyrics.py index c6ce30055..97de23cbe 100644 --- a/beetsplug/lyrics.py +++ b/beetsplug/lyrics.py @@ -14,6 +14,8 @@ """Fetches, embeds, and displays lyrics. """ +from __future__ import print_function + import urllib import re import logging @@ -83,7 +85,7 @@ def extract_text(html, starttag): parts.append(html[pos:match.start()]) break else: - print 'no closing tag found!' + print('no closing tag found!') return lyrics = ''.join(parts) diff --git a/beetsplug/mbcollection.py b/beetsplug/mbcollection.py index 67da9e69e..9e524f780 100644 --- a/beetsplug/mbcollection.py +++ b/beetsplug/mbcollection.py @@ -12,6 +12,8 @@ #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 print_function + from beets.plugins import BeetsPlugin from beets.ui import Subcommand from beets import ui @@ -44,9 +46,9 @@ def update_collection(lib, config, opts, args): albums = [a.mb_albumid for a in lib.albums() if a.mb_albumid] # Submit to MusicBrainz. - print 'Updating MusicBrainz collection {0}...'.format(collection_id) + print('Updating MusicBrainz collection {0}...'.format(collection_id)) submit_albums(collection_id, albums) - print '...MusicBrainz collection updated.' + print('...MusicBrainz collection updated.') update_mb_collection_cmd = Subcommand('mbupdate', help='Update MusicBrainz collection') diff --git a/beetsplug/mpdupdate.py b/beetsplug/mpdupdate.py index 80c58e3bf..d33c0f612 100644 --- a/beetsplug/mpdupdate.py +++ b/beetsplug/mpdupdate.py @@ -20,6 +20,7 @@ Put something like the following in your .beetsconfig to configure: port = 6600 password = seekrit """ +from __future__ import print_function from beets.plugins import BeetsPlugin from beets import ui @@ -60,20 +61,20 @@ def update_mpd(host='localhost', port=6600, password=None): """Sends the "update" command to the MPD server indicated, possibly authenticating with a password first. """ - print 'Updating MPD database...' + print('Updating MPD database...') s = BufferedSocket() s.connect(host, port) resp = s.readline() if 'OK MPD' not in resp: - print 'MPD connection failed:', repr(resp) + print('MPD connection failed:', repr(resp)) return if password: s.send('password "%s"\n' % password) resp = s.readline() if 'OK' not in resp: - print 'Authentication failed:', repr(resp) + print('Authentication failed:', repr(resp)) s.send('close\n') s.close() return @@ -81,11 +82,11 @@ def update_mpd(host='localhost', port=6600, password=None): s.send('update\n') resp = s.readline() if 'updating_db' not in resp: - print 'Update failed:', repr(resp) + print('Update failed:', repr(resp)) s.send('close\n') s.close() - print '... updated.' + print('... updated.') options = { 'host': 'localhost', diff --git a/beetsplug/rdm.py b/beetsplug/rdm.py index 51c1583a3..63779e8d2 100644 --- a/beetsplug/rdm.py +++ b/beetsplug/rdm.py @@ -12,14 +12,13 @@ # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. +"""Get a random song or album from the library. +""" from beets.plugins import BeetsPlugin from beets.ui import Subcommand, decargs, print_ from beets.util.functemplate import Template import random -"""Get a random song or album from the library. -""" - def random_item(lib, config, opts, args): query = decargs(args) path = opts.path diff --git a/test/test_importer.py b/test/test_importer.py index 2a4618d52..dd091a316 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -16,6 +16,7 @@ """ import os import shutil +import StringIO import _common from _common import unittest @@ -827,6 +828,17 @@ class ArtFetchTest(unittest.TestCase, _common.ExtraAsserts): art.art_for_album = lambda a, b: artdest self._fetch_art(True) +class TagLogTest(unittest.TestCase): + def test_tag_log_line(self): + sio = StringIO.StringIO() + importer.tag_log(sio, 'status', 'path') + assert 'status path' in sio.getvalue() + + def test_tag_log_unicode(self): + sio = StringIO.StringIO() + importer.tag_log(sio, 'status', 'caf\xc3\xa9') + assert 'status caf' in sio.getvalue() + def suite(): return unittest.TestLoader().loadTestsFromName(__name__)