Merge pull request #1217 from brunal/logging

Use a standard logger for the import log
This commit is contained in:
Bruno 2015-01-13 09:34:19 +01:00
commit a86fb19f92
7 changed files with 51 additions and 37 deletions

View file

@ -26,6 +26,7 @@ from tempfile import mkdtemp
from bisect import insort, bisect_left
from contextlib import contextmanager
import shutil
import time
from beets import logging
from beets import autotag
@ -174,14 +175,13 @@ class ImportSession(object):
"""Controls an import action. Subclasses should implement methods to
communicate with the user or otherwise make decisions.
"""
def __init__(self, lib, logfile, paths, query):
"""Create a session. `lib` is a Library object. `logfile` is a
file-like object open for writing or None if no logging is to be
performed. Either `paths` or `query` is non-null and indicates
def __init__(self, lib, loghandler, paths, query):
"""Create a session. `lib` is a Library object. `loghandler` is a
logging.Handler. Either `paths` or `query` is non-null and indicates
the source of files to be imported.
"""
self.lib = lib
self.logfile = logfile
self.logger = self._setup_logging(loghandler)
self.paths = paths
self.query = query
self.seen_idents = set()
@ -191,6 +191,14 @@ class ImportSession(object):
if self.paths:
self.paths = map(normpath, self.paths)
def _setup_logging(self, loghandler):
logger = logging.getLogger(__name__)
logger.propagate = False
if not loghandler:
loghandler = logging.NullHandler()
logger.handlers = [loghandler]
return logger
def set_config(self, config):
"""Set `config` property from global import config and make
implied changes.
@ -225,13 +233,10 @@ class ImportSession(object):
self.want_resume = config['resume'].as_choice([True, False, 'ask'])
def tag_log(self, status, paths):
"""Log a message about a given album to logfile. The status should
reflect the reason the album couldn't be tagged.
"""Log a message about a given album to the importer log. The status
should reflect the reason the album couldn't be tagged.
"""
if self.logfile:
print(u'{0} {1}'.format(status, displayable_path(paths)),
file=self.logfile)
self.logfile.flush()
self.logger.info(u'{0} {1}', status, displayable_path(paths))
def log_choice(self, task, duplicate=False):
"""Logs the task's current choice if it should be logged. If
@ -269,6 +274,7 @@ class ImportSession(object):
def run(self):
"""Run the import task.
"""
self.logger.info(u'import started {0}', time.asctime())
self.set_config(config['import'])
# Set up the pipeline.

View file

@ -92,3 +92,16 @@ if PY26:
return logger
my_manager.getLogger = new_getLogger
# Offer NullHandler in Python 2.6 to reduce the difference with never versions
if PY26:
class NullHandler(Handler):
def handle(self, record):
pass
def emit(self, record):
pass
def createLock(self):
self.lock = None

View file

@ -18,8 +18,6 @@ interface.
from __future__ import print_function
import os
import time
import codecs
import platform
import re
import shlex
@ -825,29 +823,22 @@ def import_files(lib, paths, query):
# Open the log.
if config['import']['log'].get() is not None:
logpath = config['import']['log'].as_filename()
logpath = syspath(config['import']['log'].as_filename())
try:
logfile = codecs.open(syspath(logpath), 'a', 'utf8')
loghandler = logging.FileHandler(logpath)
except IOError:
raise ui.UserError(u"could not open log file for writing: %s" %
displayable_path(logpath))
print(u'import started', time.asctime(), file=logfile)
raise ui.UserError(u"could not open log file for writing: "
u"{0}".format(displayable_path(loghandler)))
else:
logfile = None
loghandler = None
# Never ask for input in quiet mode.
if config['import']['resume'].get() == 'ask' and \
config['import']['quiet']:
config['import']['resume'] = False
session = TerminalImportSession(lib, logfile, paths, query)
try:
session.run()
finally:
# If we were logging, close the file.
if logfile:
print(u'', file=logfile)
logfile.close()
session = TerminalImportSession(lib, loghandler, paths, query)
session.run()
# Emit event.
plugins.send('import', lib=lib, paths=paths)

View file

@ -115,9 +115,9 @@ def album(lib=None):
# Dummy import session.
def import_session(lib=None, logfile=None, paths=[], query=[], cli=False):
def import_session(lib=None, loghandler=None, paths=[], query=[], cli=False):
cls = commands.TerminalImportSession if cli else importer.ImportSession
return cls(lib, logfile, paths, query)
return cls(lib, loghandler, paths, query)
# A test harness for all beets tests.

View file

@ -255,7 +255,7 @@ class TestHelper(object):
config['import']['autotag'] = False
config['import']['resume'] = False
return TestImportSession(self.lib, logfile=None, query=None,
return TestImportSession(self.lib, loghandler=None, query=None,
paths=[import_dir])
# Library fixtures methods

View file

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# This file is part of beets.
# Copyright 2015, Adrian Sampson.
#
@ -33,6 +34,7 @@ from beets.mediafile import MediaFile
from beets import autotag
from beets.autotag import AlbumInfo, TrackInfo, AlbumMatch
from beets import config
from beets import logging
class AutotagStub(object):
@ -209,7 +211,7 @@ class ImportHelper(TestHelper):
config['import']['link'] = link
self.importer = TestImportSession(
self.lib, logfile=None, query=None,
self.lib, loghandler=None, query=None,
paths=[import_dir or self.import_dir]
)
@ -1219,15 +1221,17 @@ class ImportDuplicateSingletonTest(unittest.TestCase, TestHelper):
class TagLogTest(_common.TestCase):
def test_tag_log_line(self):
sio = StringIO.StringIO()
session = _common.import_session(logfile=sio)
handler = logging.StreamHandler(sio)
session = _common.import_session(loghandler=handler)
session.tag_log('status', 'path')
assert 'status path' in sio.getvalue()
self.assertIn('status path', sio.getvalue())
def test_tag_log_unicode(self):
sio = StringIO.StringIO()
session = _common.import_session(logfile=sio)
session.tag_log('status', 'caf\xc3\xa9')
assert 'status caf' in sio.getvalue()
handler = logging.StreamHandler(sio)
session = _common.import_session(loghandler=handler)
session.tag_log('status', u'café') # send unicode
self.assertIn(u'status café', sio.getvalue())
class ResumeImportTest(unittest.TestCase, TestHelper):

View file

@ -91,7 +91,7 @@ class TerminalImportSessionSetup(object):
self.io = DummyIO()
self.io.install()
self.importer = TestTerminalImportSession(
self.lib, logfile=None, query=None, io=self.io,
self.lib, loghandler=None, query=None, io=self.io,
paths=[import_dir or self.import_dir],
)