wolfhece._plugin_loader

Companion plugin loader.

Discovers, validates, and loads companion plugins from a plugins directory.

Plugin layout

Each plugin lives in its own subdirectory containing at least two files:

plugin.toml

Machine-readable metadata (required). See the schema below.

companion.py

Python module that defines (and exports) the companion class (required).

Example directory tree:

wolfhece/data/plugins/
├── _template/                    ← ignored (starts with ``_``)
│   ├── plugin.toml
│   └── companion.py
└── my_feature/
    ├── plugin.toml
    └── companion.py

plugin.toml schema

[plugin]
name          = "my_feature"          # unique slug (required)
display_name  = "My Feature"          # human-readable label (defaults to name)
version       = "1.0.0"              # semver string (required)
author        = "Jane Doe"           # (required)
email         = "jane@example.com"   # optional
description   = "Short description." # optional
entry_class   = "MyFeatureCompanion" # companion class in companion.py (required)
created       = "2026-01-15"         # optional ISO date
updated       = "2026-05-22"         # optional ISO date

[compatibility]
requires_wolfhece = ">=2.2"          # optional, informational only
min_python        = "3.11"            # optional "major.minor" constraint

Warning

Loading a plugin executes arbitrary Python code from companion.py. Only load plugins from trusted sources.

Module Contents

wolfhece._plugin_loader._logger[source]
wolfhece._plugin_loader.PLUGINS_DIR: pathlib.Path[source]
wolfhece._plugin_loader.BUILTIN_PLUGINS_DIR: pathlib.Path[source]
wolfhece._plugin_loader._MANIFEST_FILENAME = 'plugin.toml'[source]
wolfhece._plugin_loader._COMPANION_FILENAME = 'companion.py'[source]
wolfhece._plugin_loader._MODULE_PREFIX = '_wolfhece_plugin_'[source]
class wolfhece._plugin_loader.PluginManifest[source]

Parsed metadata from plugin.toml.

name: str[source]
display_name: str[source]
version: str[source]
author: str[source]
entry_class: str[source]
email: str = ''[source]
description: str = ''[source]
created: str = ''[source]
updated: str = ''[source]
requires_wolfhece: str = ''[source]
min_python: str = ''[source]
classmethod from_dict(data: dict) PluginManifest[source]

Build from a parsed plugin.toml dict.

class wolfhece._plugin_loader.PluginInfo[source]

A discovered plugin — manifest, resolved class, and runtime status.

manifest: PluginManifest[source]
path: pathlib.Path[source]
companion_class: type | None = None[source]
enabled: bool = True[source]
load_error: str = ''[source]
property loaded: bool[source]

True if the companion class was successfully imported.

property name: str[source]
property display_name: str[source]
exception wolfhece._plugin_loader.PluginValidationError(path: pathlib.Path, errors: list[str])[source]

Bases: ValueError

Inheritance diagram of wolfhece._plugin_loader.PluginValidationError

Raised when a plugin directory does not pass validation.

path[source]
errors: list[str][source]
wolfhece._plugin_loader.validate_plugin_dir(plugin_dir: pathlib.Path) list[str][source]

Return a list of validation error strings (empty list = OK).

Checks:

  • The path is an existing directory.

  • plugin.toml exists and is valid TOML.

  • Required keys name, version, author, entry_class are present.

  • name is a slug-like identifier (only letters, digits, -, _).

  • min_python constraint is satisfied by the running interpreter (if set).

  • companion.py exists.

This function never raises — all problems are returned as strings.

wolfhece._plugin_loader.load_plugin(plugin_dir: pathlib.Path) PluginInfo[source]

Load and validate one plugin from plugin_dir.

Parameters:

plugin_dir – Path to the plugin subdirectory.

Raises:
  • PluginValidationError – if the directory fails validation.

  • ImportError – if companion.py cannot be imported.

  • AttributeError – if the entry class is not found in the module.

  • TypeError – if the entry class does not subclass AbstractCompanion.

Returns:

A fully populated PluginInfo with companion_class set.

wolfhece._plugin_loader.discover_plugins(directory: pathlib.Path | str | None = None) list[PluginInfo][source]

Discover all plugin directories under directory.

Skips subdirectories whose name starts with _ or . (template / draft folders) so they can coexist safely with live plugins.

Invalid or failing plugins are not raised — they are returned as PluginInfo objects with load_error set and companion_class = None.

When two valid plugins share the same name, the first one (alphabetical) wins and the duplicate is logged then skipped.

Parameters:

directory – Root plugins directory. Defaults to wolfhece/data/plugins.

Returns:

List of PluginInfo objects, one per discovered subdirectory (failures included).

wolfhece._plugin_loader._make_error_info(sub: pathlib.Path, error_msg: str) PluginInfo[source]

Build a placeholder PluginInfo for a plugin that failed to load.

wolfhece._plugin_loader.discover_all_plugins(user_directory: pathlib.Path | str | None = None) list[PluginInfo][source]

Discover both built-in and user plugins, returning a combined list.

Built-in plugins (from BUILTIN_PLUGINS_DIR) are listed first, followed by user plugins (from user_directory or PLUGINS_DIR). Duplicate plugin names (same slug in both directories) are resolved in favour of the built-in version — the user plugin is skipped with a warning.

Parameters:

user_directory – Directory to scan for user plugins. Defaults to PLUGINS_DIR.

Returns:

Combined list of PluginInfo objects.