tutor/tutor/plugins/v1.py

77 lines
2.2 KiB
Python

import importlib.util
import os
from glob import glob
import pkg_resources
from tutor import hooks
from .base import PLUGINS_ROOT
@hooks.Actions.CORE_READY.add()
def _discover_module_plugins() -> None:
"""
Discover .py files in the plugins root folder.
"""
with hooks.Contexts.PLUGINS.enter():
for path in glob(os.path.join(PLUGINS_ROOT, "*.py")):
discover_module(path)
@hooks.Actions.CORE_READY.add()
def _discover_entrypoint_plugins() -> None:
"""
Discover all plugins that declare a "tutor.plugin.v1" entrypoint.
"""
with hooks.Contexts.PLUGINS.enter():
for entrypoint in pkg_resources.iter_entry_points("tutor.plugin.v1"):
discover_package(entrypoint)
def discover_module(path: str) -> None:
"""
Install a plugin written as a single file module.
"""
name = os.path.splitext(os.path.basename(path))[0]
# Add plugin to the list of installed plugins
hooks.Filters.PLUGINS_INSTALLED.add_item(name)
# Add plugin information
hooks.Filters.PLUGINS_INFO.add_item((name, path))
# Import module on enable
load_plugin_action = hooks.Actions.PLUGIN_LOADED(name)
@load_plugin_action.add()
def load() -> None:
# https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly
spec = importlib.util.spec_from_file_location("tutor.plugin.v1.{name}", path)
if spec is None or spec.loader is None:
raise ValueError("Plugin could not be found: {path}")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
def discover_package(entrypoint: pkg_resources.EntryPoint) -> None:
"""
Install a plugin from a python package.
"""
name = entrypoint.name
# Add plugin to the list of installed plugins
hooks.Filters.PLUGINS_INSTALLED.add_item(name)
# Add plugin information
if entrypoint.dist is None:
raise ValueError(f"Could not read plugin version: {name}")
hooks.Filters.PLUGINS_INFO.add_item((name, entrypoint.dist.version))
# Import module on enable
load_plugin_action = hooks.Actions.PLUGIN_LOADED(name)
@load_plugin_action.add()
def load() -> None:
entrypoint.load()