Source code for asv.plugin_manager
# Licensed under a 3-clause BSD style license - see LICENSE.rst
import importlib
import pkgutil
import re
import sys
from . import commands, plugins
from .console import log
[docs]
ENV_PLUGIN_REGEXES = [
r"\.virtualenv$",
r"\.conda$",
r"\.rattler$",
r"\.uv$",
]
[docs]
class PluginManager:
"""
A class to load and manage plugins.
By default in asv, plugins are searched for in the :py:mod:`asv.plugins`
namespace package and in the :py:mod:`asv.commands` package.
Then, any modules specified in the ``plugins`` entry in the
``asv.conf.json`` file are loaded.
"""
def __init__(self):
[docs]
def load_plugins(self, package):
prefix = package.__name__ + "."
for module_finder, name, ispkg in pkgutil.iter_modules(package.__path__, prefix):
try:
mod = importlib.import_module(name)
self.init_plugin(mod)
self._plugins.append(mod)
except ModuleNotFoundError as err:
if any(re.search(regex, name) for regex in ENV_PLUGIN_REGEXES):
continue # Fine to not have these
else:
log.error(f"Couldn't load {name} because\n{err}")
[docs]
def _load_plugin_by_name(self, name):
prefix = plugins.__name__ + "."
for module_finder, module_name, ispkg in pkgutil.iter_modules(plugins.__path__, prefix):
if name in module_name:
mod = importlib.import_module(module_name)
return mod
return None
[docs]
def import_plugin(self, name):
extended = False
if name.startswith("."):
extended = True
sys.path.insert(0, ".")
name = name[1:]
try:
if extended:
mod = importlib.import_module(name)
else:
mod = self._load_plugin_by_name(name)
if mod:
self.init_plugin(mod)
self._plugins.append(mod)
finally:
if extended:
del sys.path[0]
[docs]
def init_plugin(self, mod):
if hasattr(mod, "setup"):
mod.setup()
[docs]
def run_hook(self, hook_name, args, kwargs):
for plugin in self._plugins:
if hasattr(plugin, hook_name):
getattr(plugin, hook_name)(*args, **kwargs)
[docs]
plugin_manager = PluginManager()
plugin_manager.load_plugins(commands)
plugin_manager.load_plugins(plugins)
commands.__doc__ = commands._make_docstring()