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.
This commit is contained in:
Adrian Sampson 2012-10-12 21:55:54 -07:00
parent e316d0ea30
commit 71a5a5b02f
3 changed files with 14 additions and 28 deletions

View file

@ -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()

View file

@ -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 + '~'

View file

@ -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