Developing VIPR Plugins

Start from the Example

The best way to create a plugin is to copy and adapt the example plugin in example-plugin/.

Minimal Plugin - Step by Step

This follows the structure of example-plugin/.

1. Project Configuration (pyproject.toml)

[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "vipr-log-file"  # PyPI package name
version = "0.1.0"
dependencies = ["vipr"]

[project.entry-points."vipr.plugins"]
log_file = "vipr_log_file:load"  # entry_point_name = "package:function"

[tool.setuptools.packages.find]
where = ["."]
include = ["vipr_log_file*"]

2. Package Structure

vipr_log_file/          # Package name (matches entry point target)
└── __init__.py         # Contains load(app) function

3. Implementation (init.py)

def load(app):
    """Plugin initialization - called by VIPR"""
    app.log.info("Loading log_file plugin")
    
    # Register hook
    def write_logs_to_file(app):
        # Your plugin logic here
        pass
    
    # Register with weight to control execution order
    # Hooks are executed from lowest to highest weight value
    app.hook.register('INFERENCE_COMPLETE_HOOK', write_logs_to_file, weight=250)

Note on weights: The weight parameter controls execution order for hooks. Hooks are executed from lowest to highest weight value, regardless of registration order. This allows plugins to ensure their hooks run at the right time in relation to other plugins.

Installation

cd example-plugin/
pip install -e .  # Development mode

Plugin is automatically discovered via entry points.

Optional: Plugin Control

Create vipr-plugins.yaml in your working directory to disable a plugin:

plugin.log_file:
  enabled: false

Note: log_file matches the entry point name in pyproject.toml, NOT the package name.

Packaged Example Configs

Plugins can expose example configurations for the web frontend and Discovery API.

Directory Convention

Example configs must be packaged YAML files located under:

<plugin_package>/<group>/examples/configs/*.yaml

or

<plugin_package>/<group>/examples/configs/*.yml

Examples:

vipr_reflectometry/reflectorch/examples/configs/PTCDI-C3.yaml
vipr_reflectometry/reflectorch/examples/configs/FePt_DN.yaml
vipr_reflectometry/flow_models/examples/configs/Fe_Pt_DN_NSF.yaml

The path segment immediately before examples/configs becomes the example group.

How Discovery Derives Metadata

VIPR scans installed plugin packages registered via the vipr.plugins entry point group.

For each matching YAML file:

  • plugin is derived from the plugin entry point name

  • group is derived from the path segment immediately before examples/configs

  • id is built as <plugin>.<group>.<file_stem>

Example:

vipr_reflectometry/reflectorch/examples/configs/FePt_DN.yaml

becomes:

reflectometry.reflectorch.FePt_DN

Requirements

For example configs to be discoverable:

  • the plugin must be installed in the current Python environment

  • the YAML files must be included as package data

  • the config must reference handlers, hooks, and filters that are available in the current runtime

  • callbacks with enabled: false are ignored during availability checks

Packaging Note

Make sure the example files are included in the built package, for example via MANIFEST.in or package-data configuration.

Complete Working Example

See example-plugin/ for the full implementation that:

  • Registers a hook

  • Writes logs to a file after inference

  • Shows proper project structure

Copy it and adapt for your needs.