# HG changeset patch # User Ludovic Chabant # Date 1493351669 25200 # Node ID 7d83b9484b98efad4b52e3beb8f597d23d0384d3 # Parent 71c4f43d8fc16bed760e41bd49fc4c9734b2b6f4 plugins: Add support for "ad-hoc" local plugins. These are loose `.py` files inside of the `plugins` folder of a website. They're loaded along with other normal (packaged) plugins. diff -r 71c4f43d8fc1 -r 7d83b9484b98 piecrust/__init__.py --- a/piecrust/__init__.py Thu Apr 27 20:53:18 2017 -0700 +++ b/piecrust/__init__.py Thu Apr 27 20:54:29 2017 -0700 @@ -4,6 +4,7 @@ TEMPLATES_DIR = 'templates' THEME_DIR = 'theme' THEMES_DIR = 'themes' +PLUGINS_DIR = 'plugins' CONFIG_PATH = 'config.yml' THEME_CONFIG_PATH = 'theme_config.yml' diff -r 71c4f43d8fc1 -r 7d83b9484b98 piecrust/app.py --- a/piecrust/app.py Thu Apr 27 20:53:18 2017 -0700 +++ b/piecrust/app.py Thu Apr 27 20:54:29 2017 -0700 @@ -7,7 +7,7 @@ from piecrust import ( RESOURCES_DIR, CACHE_DIR, TEMPLATES_DIR, ASSETS_DIR, - THEME_DIR, + THEME_DIR, PLUGINS_DIR, CONFIG_PATH, THEME_CONFIG_PATH) from piecrust.appconfig import PieCrustConfiguration from piecrust.cache import ExtensibleCache, NullExtensibleCache @@ -127,6 +127,10 @@ return os.path.join(RESOURCES_DIR, 'theme') @cached_property + def plugins_dir(self): + return self._get_dir(PLUGINS_DIR) + + @cached_property def cache_dir(self): return os.path.join(self.root_dir, CACHE_DIR, self.cache_key) diff -r 71c4f43d8fc1 -r 7d83b9484b98 piecrust/plugins/base.py --- a/piecrust/plugins/base.py Thu Apr 27 20:53:18 2017 -0700 +++ b/piecrust/plugins/base.py Thu Apr 27 20:54:29 2017 -0700 @@ -1,5 +1,8 @@ +import os.path +import sys import logging import importlib +import importlib.util logger = logging.getLogger(__name__) @@ -113,9 +116,24 @@ plugin.initialize(self.app) def _loadPlugin(self, plugin_name): + mod_name = 'piecrust_%s' % plugin_name try: - mod = importlib.import_module('piecrust_' + plugin_name) + # Import from the current environment. + mod = importlib.import_module(mod_name) except ImportError as ex: + mod = None + + if mod is None: + # Import as a loose Python file from the plugins dir. + pfile = os.path.join(self.app.plugins_dir, plugin_name + '.py') + if os.path.isfile(pfile): + spec = importlib.util.spec_from_file_location(plugin_name, + pfile) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + sys.modules[mod_name] = mod + + if mod is None: logger.error("Failed to load plugin '%s'." % plugin_name) logger.error(ex) return