mirror of
https://github.com/beetbox/beets.git
synced 2025-12-06 16:42:42 +01:00
Improve logging management for plugins: fixes
Delete the remaining usages of BeetsPlugin.listen(). Since BeetsPlugin.listeners are wrapped by a loglevel-setting function, we cannot easily check their unicity anymore. BeetsPlugin._raw_listeners set holds the raw listeners. Legacy plugins that did not handle enough arguments in their listenings functions may break: dedicated code is now deleted for it would not work with the decorated listeners. Tests got fixed. Some modifications were done empirically: if it passes then it's okay.
This commit is contained in:
parent
4578c4f0e1
commit
327b62b610
5 changed files with 24 additions and 24 deletions
|
|
@ -18,7 +18,6 @@ from __future__ import (division, absolute_import, print_function,
|
||||||
unicode_literals)
|
unicode_literals)
|
||||||
|
|
||||||
import traceback
|
import traceback
|
||||||
import inspect
|
|
||||||
import re
|
import re
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
@ -180,17 +179,21 @@ class BeetsPlugin(object):
|
||||||
mediafile.MediaFile.add_field(name, descriptor)
|
mediafile.MediaFile.add_field(name, descriptor)
|
||||||
library.Item._media_fields.add(name)
|
library.Item._media_fields.add(name)
|
||||||
|
|
||||||
|
_raw_listeners = None
|
||||||
listeners = None
|
listeners = None
|
||||||
|
|
||||||
def register_listener(self, event, func):
|
def register_listener(self, event, func):
|
||||||
"""Add a function as a listener for the specified event.
|
"""Add a function as a listener for the specified event.
|
||||||
"""
|
"""
|
||||||
func = self._set_log_level(logging.WARNING, func)
|
wrapped_func = self._set_log_level(logging.WARNING, func)
|
||||||
|
|
||||||
if self.listeners is None:
|
cls = self.__class__
|
||||||
self.listeners = defaultdict(list)
|
if cls.listeners is None or cls._raw_listeners is None:
|
||||||
if func not in self.listeners[event]:
|
cls._raw_listeners = defaultdict(list)
|
||||||
self.listeners[event].append(func)
|
cls.listeners = defaultdict(list)
|
||||||
|
if func not in cls._raw_listeners[event]:
|
||||||
|
cls._raw_listeners[event].append(func)
|
||||||
|
cls.listeners[event].append(wrapped_func)
|
||||||
|
|
||||||
template_funcs = None
|
template_funcs = None
|
||||||
template_fields = None
|
template_fields = None
|
||||||
|
|
@ -440,9 +443,7 @@ def send(event, **arguments):
|
||||||
results = []
|
results = []
|
||||||
for handler in event_handlers()[event]:
|
for handler in event_handlers()[event]:
|
||||||
# Don't break legacy plugins if we want to pass more arguments
|
# Don't break legacy plugins if we want to pass more arguments
|
||||||
argspec = inspect.getargspec(handler).args
|
result = handler(**arguments)
|
||||||
args = dict((k, v) for k, v in arguments.items() if k in argspec)
|
|
||||||
result = handler(**args)
|
|
||||||
if result is not None:
|
if result is not None:
|
||||||
results.append(result)
|
results.append(result)
|
||||||
return results
|
return results
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,7 @@ class AcoustidPlugin(plugins.BeetsPlugin):
|
||||||
|
|
||||||
if self.config['auto']:
|
if self.config['auto']:
|
||||||
self.register_listener('import_task_start', self.fingerprint_task)
|
self.register_listener('import_task_start', self.fingerprint_task)
|
||||||
|
self.register_listener('import_task_apply', apply_acoustid_metadata)
|
||||||
|
|
||||||
def fingerprint_task(self, task, session):
|
def fingerprint_task(self, task, session):
|
||||||
return fingerprint_task(self._log, task, session)
|
return fingerprint_task(self._log, task, session)
|
||||||
|
|
@ -211,7 +212,6 @@ def fingerprint_task(log, task, session):
|
||||||
acoustid_match(log, item.path)
|
acoustid_match(log, item.path)
|
||||||
|
|
||||||
|
|
||||||
@AcoustidPlugin.listen('import_task_apply')
|
|
||||||
def apply_acoustid_metadata(task, session):
|
def apply_acoustid_metadata(task, session):
|
||||||
"""Apply Acoustid metadata (fingerprint and ID) to the task's items.
|
"""Apply Acoustid metadata (fingerprint and ID) to the task's items.
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -140,10 +140,11 @@ def apply_matches(d):
|
||||||
# Plugin structure and hook into import process.
|
# Plugin structure and hook into import process.
|
||||||
|
|
||||||
class FromFilenamePlugin(plugins.BeetsPlugin):
|
class FromFilenamePlugin(plugins.BeetsPlugin):
|
||||||
pass
|
def __init__(self):
|
||||||
|
super(FromFilenamePlugin, self).__init__()
|
||||||
|
self.register_listener('import_task_start', filename_task)
|
||||||
|
|
||||||
|
|
||||||
@FromFilenamePlugin.listen('import_task_start')
|
|
||||||
def filename_task(task, session):
|
def filename_task(task, session):
|
||||||
"""Examine each item in the task to see if we can extract a title
|
"""Examine each item in the task to see if we can extract a title
|
||||||
from the filename. Try to match all filenames to a number of
|
from the filename. Try to match all filenames to a number of
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,10 @@ class Permissions(BeetsPlugin):
|
||||||
u'file': 644
|
u'file': 644
|
||||||
})
|
})
|
||||||
|
|
||||||
|
self.register_listener('item_imported', permissions)
|
||||||
|
self.register_listener('album_imported', permissions)
|
||||||
|
|
||||||
|
|
||||||
@Permissions.listen('item_imported')
|
|
||||||
@Permissions.listen('album_imported')
|
|
||||||
def permissions(lib, item=None, album=None):
|
def permissions(lib, item=None, album=None):
|
||||||
"""Running the permission fixer.
|
"""Running the permission fixer.
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ class TestHelper(helper.TestHelper):
|
||||||
def setup_plugin_loader(self):
|
def setup_plugin_loader(self):
|
||||||
# FIXME the mocking code is horrific, but this is the lowest and
|
# FIXME the mocking code is horrific, but this is the lowest and
|
||||||
# earliest level of the plugin mechanism we can hook into.
|
# earliest level of the plugin mechanism we can hook into.
|
||||||
|
self.load_plugins()
|
||||||
self._plugin_loader_patch = patch('beets.plugins.load_plugins')
|
self._plugin_loader_patch = patch('beets.plugins.load_plugins')
|
||||||
self._plugin_classes = set()
|
self._plugin_classes = set()
|
||||||
load_plugins = self._plugin_loader_patch.start()
|
load_plugins = self._plugin_loader_patch.start()
|
||||||
|
|
@ -95,7 +96,7 @@ class ItemWriteTest(unittest.TestCase, TestHelper):
|
||||||
|
|
||||||
class EventListenerPlugin(plugins.BeetsPlugin):
|
class EventListenerPlugin(plugins.BeetsPlugin):
|
||||||
pass
|
pass
|
||||||
self.event_listener_plugin = EventListenerPlugin
|
self.event_listener_plugin = EventListenerPlugin()
|
||||||
self.register_plugin(EventListenerPlugin)
|
self.register_plugin(EventListenerPlugin)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
|
|
@ -298,19 +299,15 @@ class ListenersTest(unittest.TestCase, TestHelper):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
d = DummyPlugin()
|
d = DummyPlugin()
|
||||||
self.assertEqual(DummyPlugin.listeners['cli_exit'], [d.dummy])
|
self.assertEqual(DummyPlugin._raw_listeners['cli_exit'], [d.dummy])
|
||||||
|
|
||||||
d2 = DummyPlugin()
|
d2 = DummyPlugin()
|
||||||
DummyPlugin.register_listener('cli_exit', d.dummy)
|
self.assertEqual(DummyPlugin._raw_listeners['cli_exit'],
|
||||||
self.assertEqual(DummyPlugin.listeners['cli_exit'],
|
|
||||||
[d.dummy, d2.dummy])
|
[d.dummy, d2.dummy])
|
||||||
|
|
||||||
@DummyPlugin.listen('cli_exit')
|
d.register_listener('cli_exit', d2.dummy)
|
||||||
def dummy(lib):
|
self.assertEqual(DummyPlugin._raw_listeners['cli_exit'],
|
||||||
pass
|
[d.dummy, d2.dummy])
|
||||||
|
|
||||||
self.assertEqual(DummyPlugin.listeners['cli_exit'],
|
|
||||||
[d.dummy, d2.dummy, dummy])
|
|
||||||
|
|
||||||
|
|
||||||
def suite():
|
def suite():
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue