From 71a5a5b02fa3991dbe01bb20ed85bb87de3c8c10 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Fri, 12 Oct 2012 21:55:54 -0700 Subject: [PATCH] only load plugins from specified modules Eliminate the __subclasses__ trick for finding all plugins. Now we explicitly look in each plugin module for a plugin class. This allows us to import plugin modules with unintentionally loading them. This lets us reuse the image embedding machinery without copypasta. --- beets/plugins.py | 16 ++++++++++------ beetsplug/convert.py | 24 ++---------------------- docs/changelog.rst | 2 ++ 3 files changed, 14 insertions(+), 28 deletions(-) diff --git a/beets/plugins.py b/beets/plugins.py index 0752422e4..ca93b9d0a 100755 --- a/beets/plugins.py +++ b/beets/plugins.py @@ -22,7 +22,6 @@ from collections import defaultdict from beets import mediafile PLUGIN_NAMESPACE = 'beetsplug' -DEFAULT_PLUGINS = [] # Plugins using the Last.fm API can share the same API key. LASTFM_KEY = '2dc3914abf35f0d9c92d97d8f8e42b43' @@ -151,24 +150,29 @@ class BeetsPlugin(object): return func return helper +_classes = set() def load_plugins(names=()): """Imports the modules for a sequence of plugin names. Each name must be the name of a Python module under the "beetsplug" namespace package in sys.path; the module indicated should contain the - BeetsPlugin subclasses desired. A default set of plugins is also - loaded. + BeetsPlugin subclasses desired. """ - for name in itertools.chain(names, DEFAULT_PLUGINS): + for name in names: modname = '%s.%s' % (PLUGIN_NAMESPACE, name) try: try: - __import__(modname, None, None) + namespace = __import__(modname, None, None) except ImportError as exc: # Again, this is hacky: if exc.args[0].endswith(' ' + name): log.warn('** plugin %s not found' % name) else: raise + else: + for obj in getattr(namespace, name).__dict__.values(): + if isinstance(obj, type) and issubclass(obj, BeetsPlugin): + _classes.add(obj) + except: log.warn('** error loading plugin %s' % name) log.warn(traceback.format_exc()) @@ -181,7 +185,7 @@ def find_plugins(): """ load_plugins() plugins = [] - for cls in BeetsPlugin.__subclasses__(): + for cls in _classes: # Only instantiate each plugin class once. if cls not in _instances: _instances[cls] = cls() diff --git a/beetsplug/convert.py b/beetsplug/convert.py index 089962c21..c148a2bf3 100644 --- a/beetsplug/convert.py +++ b/beetsplug/convert.py @@ -22,34 +22,14 @@ from subprocess import Popen, PIPE import imghdr from beets.plugins import BeetsPlugin -from beets import ui, library, util, mediafile +from beets import ui, library, util +from beetsplug.embedart import _embed log = logging.getLogger('beets') DEVNULL = open(os.devnull, 'wb') conf = {} -def _embed(path, items): - """Embed an image file, located at `path`, into each item. - """ - data = open(util.syspath(path), 'rb').read() - kindstr = imghdr.what(None, data) - if kindstr not in ('jpeg', 'png'): - log.error('A file of type %s is not allowed as coverart.' % kindstr) - return - log.debug('Embedding album art.') - for item in items: - try: - f = mediafile.MediaFile(util.syspath(item.path)) - except mediafile.UnreadableFileError as exc: - log.warn('Could not embed art in {0}: {1}'.format( - repr(item.path), exc - )) - continue - f.art = data - f.save() - - def encode(source, dest): log.info('Started encoding ' + source) temp_dest = dest + '~' diff --git a/docs/changelog.rst b/docs/changelog.rst index 837fb3bed..b7bc7ea6b 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -48,6 +48,8 @@ Changelog * Fix a VFS bug leading to a crash in the :doc:`/plugins/bpd` when files had non-ASCII extensions. * Add a human-readable error message when writing files' tags fails. +* Changed plugin loading so that modules can be imported without + unintentionally loading the plugins they contain. .. _Tomahawk resolver: http://beets.radbox.org/blog/tomahawk-resolver.html