Extending MSNoise with Plugins
Added in version 1.4.
Changed in version 2.0: New entry point groups for workflow topology, config sets,
and job types. Stable import surface via msnoise.plugins.
MSNoise supports plugins — external Python packages that extend the default
preprocess → CC → stack → mwcs/stretching/wavelet → dv/v workflow with
new processing steps, new job types, or new web-admin pages.
Stable import surface
Plugin code should import from msnoise.plugins rather than from
msnoise.core.* directly. This protects plugins from internal restructuring:
from msnoise.plugins import (
connect,
get_config, update_config,
get_params,
get_workflow_chains, get_workflow_order,
get_next_lineage_batch, is_next_job_for_step,
massive_update_job, propagate_downstream,
xr_get_ccf, xr_save_ccf,
get_stations, get_station_pairs,
)
MSNoise plugin stable re-export surface.
Plugin packages should import from here rather than from msnoise.core.*
directly, so that internal restructuring in MSNoise does not silently break
plugins.
Entry point groups (declare in your pyproject.toml):
[project.entry-points."msnoise.plugins.table_def"]
myplugin = "myplugin.tabledef:get_table_def"
[project.entry-points."msnoise.plugins.workflow_chains"]
myplugin = "myplugin.workflow:get_chains"
[project.entry-points."msnoise.plugins.workflow_order"]
myplugin = "myplugin.workflow:get_order"
[project.entry-points."msnoise.plugins.jobtypes"]
myplugin = "myplugin.jobs:get_jobtypes"
[project.entry-points."msnoise.plugins.commands"]
myplugin = "myplugin.cli:cli"
pyproject.toml entry points
Declare all entry points in your pyproject.toml:
[project.entry-points."msnoise.plugins.commands"]
myplugin = "myplugin.cli:cli"
[project.entry-points."msnoise.plugins.jobtypes"]
myplugin = "myplugin.jobs:get_jobtypes"
[project.entry-points."msnoise.plugins.workflow_chains"]
myplugin = "myplugin.workflow:get_chains"
[project.entry-points."msnoise.plugins.workflow_order"]
myplugin = "myplugin.workflow:get_order"
[project.entry-points."msnoise.plugins.table_def"]
myplugin = "myplugin.tabledef:MyPluginConfig"
Alternatively, using the legacy setup.py format:
entry_points = {
"msnoise.plugins.commands": ["myplugin = myplugin.cli:cli"],
"msnoise.plugins.jobtypes": ["myplugin = myplugin.jobs:get_jobtypes"],
"msnoise.plugins.workflow_chains":["myplugin = myplugin.workflow:get_chains"],
"msnoise.plugins.workflow_order": ["myplugin = myplugin.workflow:get_order"],
"msnoise.plugins.table_def": ["myplugin = myplugin.tabledef:MyPluginConfig"],
}
Entry point groups
msnoise.plugins.commands
Adds a click.Group (or click.Command) to the msnoise
CLI. Once the plugin is declared in the project’s plugins config key and
the package is installed, the command appears under msnoise plugin:
# myplugin/cli.py
import click
@click.group()
def cli():
"""My Plugin commands."""
@cli.command()
def compute():
"""Run my custom computation."""
from .compute import main
main()
$ msnoise plugin myplugin compute
msnoise.plugins.jobtypes
Registers custom job types that are created during msnoise new_jobs.
The callable must return a list of dicts with name and after keys:
# myplugin/jobs.py
def get_jobtypes():
return [
{"name": "MYPLUGIN", "after": "scan_archive"},
]
Supported after values: "scan_archive", "new_files".
msnoise.plugins.workflow_chains
Adds new categories to the workflow DAG. The callable must return a dict
with the same schema as msnoise.core.workflow._BUILTIN_WORKFLOW_CHAINS.
Once registered, the category is automatically valid in msnoise new_jobs
--after, in job propagation, MSNoiseResult, and
msnoise utils run_workflow:
# myplugin/workflow.py
def get_chains():
return {
"my_dtt": {
"next_steps": ["my_dtt_dvv"],
"is_entry_point": False,
"is_terminal": False,
"abbrev": "mdtt",
"display_name": "My dt/t",
"level": 7,
"cli": ["plugin", "myplugin", "compute_dtt"], # ← required for run_workflow
},
"my_dtt_dvv": {
"next_steps": [],
"is_entry_point": False,
"is_terminal": True,
"abbrev": "mdvv",
"display_name": "My dv/v Aggregate",
"level": 8,
"cli": ["plugin", "myplugin", "compute_dvv"], # ← required for run_workflow
},
}
Note
The "cli" key maps the category to the msnoise sub-command token
list used by msnoise utils run_workflow. Pass-through categories
(no worker, no jobs) should use "cli": None. If omitted, the category
is silently skipped by run_workflow.
msnoise.plugins.workflow_order
Appends new category names to the canonical display order used by the
admin UI and msnoise config list:
# myplugin/workflow.py
def get_order():
return ["my_dtt", "my_dtt_dvv"]
msnoise.plugins.table_def
Exposes a plugin’s SQLAlchemy config table class so that
get_config() and
update_config() can access it via the
plugin= argument:
# myplugin/tabledef.py
from sqlalchemy import Column, String
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class MyPluginConfig(Base):
__tablename__ = "myplugin-config"
name = Column(String(255), primary_key=True)
value = Column(String(255))
def get_table_def():
return MyPluginConfig
Usage from Python:
from msnoise.plugins import connect, get_config
db = connect()
val = get_config(db, "myparam", plugin="MyPlugin")
Declaring the plugin in a project
After installing the plugin package, declare its package name in the
project’s plugins global configuration key (comma-separated, no spaces):
$ msnoise config set plugins myplugin
# or for multiple plugins:
$ msnoise config set plugins myplugin,anotherplugin
The plugin will then appear in msnoise plugin and its workflow categories
will be available in msnoise new_jobs --after.
Minimal plugin structure
msnoise-myplugin/
├── pyproject.toml
└── myplugin/
├── __init__.py
├── cli.py ← click commands
├── compute.py ← worker main()
├── jobs.py ← get_jobtypes()
├── tabledef.py ← SQLAlchemy config table
└── workflow.py ← get_chains(), get_order()