spaCR plugin SDK

The plugin SDK lets a separately installed Python package add assays, importers, analysis utilities, settings panels, model-zoo entries and report sections without editing spaCR. Plugins use Python package entry points, so spaCR discovers them at startup and keeps them available to both the Qt application and spacr-run.

The current SDK API is 1.0. Only the major version controls compatibility: a plugin declaring API 1.x works with spaCR’s 1.x SDK. A malformed or failing plugin is isolated and reported by spacr-plugins doctor; it cannot replace a built-in module or prevent spaCR from starting.

Minimal plugin

Declare the entry point in the plugin package’s pyproject.toml:

[project.entry-points."spacr.plugins"]
my_assays = "my_spacr_plugin:plugin"

Then expose a manifest:

from spacr.plugins import AppContribution, SpacrPlugin

plugin = SpacrPlugin(
    name="My laboratory assays",
    version="0.1.0",
    api_version="1.0",
    apps=(
        AppContribution(
            key="organelle_contact",
            name="Organelle Contact",
            description="Measure contact sites from a processed plate.",
            kind="assay",
            section="results",
            stage="alpha",
            entrypoint="my_spacr_plugin.pipeline:run",
            defaults="my_spacr_plugin.pipeline:default_settings",
            categories={
                "Input": ("src", "table"),
                "Detection": ("distance_px", "min_area"),
                "Output": ("save_figures",),
            },
            tooltips={
                "src": "Processed spaCR plate folder.",
                "distance_px": "Maximum membrane-to-membrane distance.",
            },
            labels={"distance_px": "Contact distance (px)"},
            docs_url="https://example.org/my-plugin/api/",
            aliases=("contacts",),
            validator="my_spacr_plugin.pipeline:validate",
            drop_handler="my_spacr_plugin.qt:PlateDropHandler",
            requires=("src — a processed spaCR plate",),
            writes=("<src>/measurements/contact_sites.csv",),
        ),
    ),
)

The pipeline callable receives one settings dictionary. The defaults callable must accept an optional settings dictionary and return a dictionary. A validator returns spacr.validate.Problem objects (or equivalent mappings). All processing still runs through spaCR’s worker, journal, cancellation and reproducibility paths.

Settings and custom screens

The generic settings screen is preferred: declare categories, tooltips and optional labels on spacr.plugins.AppContribution. The UI then provides the normal Run/Stop controls, console, progress reporting, API links, drag-and-drop fallback and remote-submit action.

For a layout the generic screen cannot express, set screen_factory to a module:callable. The callable is invoked as factory(app_key=...) and must return a PySide6.QtWidgets.QWidget. A custom drop_handler must be a subclass of spacr.qt.dnd_handlers.DropHandler. icon may name a spaCR semantic icon or an absolute image path; otherwise the normal puzzle piece fallback is used.

Model providers

Add a spacr.plugins.ModelProviderContribution. Its zero-argument callable returns an iterable of spacr.model_zoo.ModelEntry objects or the mappings accepted by spaCR’s JSON model catalogue.

from spacr.plugins import ModelProviderContribution

ModelProviderContribution(
    key="lab_models",
    provider="my_spacr_plugin.models:catalogue",
)

Providers must be read-only during catalogue discovery. Downloads remain an explicit Model Zoo action. A provider exception is shown by spacr-plugins doctor and built-in models remain available.

Report sections

A spacr.plugins.ReportSectionContribution builder receives a read-only spacr.plugins.ReportContext and returns a spacr.report.Section:

from spacr.plugins import ReportSectionContribution
from spacr.report import Section

def build_contacts(context):
    return Section(
        key="organelle_contacts",
        title="Organelle contacts",
        body_html="<p>Contact-site results.</p>",
        text_lines=["Contact-site results."],
    )

contact_report = ReportSectionContribution(
    key="organelle_contacts",
    title="Organelle contacts",
    builder="my_spacr_plugin.report:build_contacts",
    after="statistics",
)

If the builder raises, the generated report contains a visible problem chapter with the exception instead of silently omitting the section.

Translations

SpacrPlugin.translations maps spaCR language codes to English-source / translated-text mappings. Supported codes are sv, de, es, zh_CN, pt, hi, ko, is and fr. Missing strings fall back to English.

Development and diagnostics

During local development only, point SPACR_PLUGIN_MODULES at a comma-separated list of module:attribute references. Set SPACR_DISABLE_PLUGINS=1 to start spaCR without third-party plugins.

SPACR_PLUGIN_MODULES=my_spacr_plugin:plugin spacr-plugins list
spacr-plugins doctor
spacr-plugins doctor --json

The public SDK lives in spacr.plugins; the diagnostics command lives in spacr.cli_plugins.

API reference

Versioned extension SDK for third-party spaCR plugins.

Plugins are ordinary Python distributions exposing one entry point in the spacr.plugins group. The entry point may resolve to a SpacrPlugin, a mapping accepted by plugin_from_mapping(), or a zero-argument factory returning either. Discovery is lazy, deterministic and failure-isolated: one malformed plugin is recorded in diagnostics() without preventing spaCR or the remaining plugins from loading.

For editable/local development, SPACR_PLUGIN_MODULES may contain a comma-separated list of module or module:attribute references. Installed plugins should always use package entry points instead.

Setting SPACR_DISABLE_PLUGINS to 1, true, yes or on (case-insensitively) skips discovery entirely, so no plugin loads from either source.

class spacr.plugins.AppContribution(key: str, name: str, description: str, entrypoint: str, defaults: str, section: str = 'results', stage: str = 'alpha', kind: str = 'analysis', categories: ~typing.Mapping[str, ~typing.Sequence[str]] = <factory>, tooltips: ~typing.Mapping[str, str] = <factory>, labels: ~typing.Mapping[str, str] = <factory>, docs_url: str = '', aliases: ~typing.Tuple[str, ...] = (), validator: str = '', screen_factory: str = '', drop_handler: str = '', icon: str = '', requires: ~typing.Tuple[str, ...] = (), writes: ~typing.Tuple[str, ...] = (), call_style: str = 'settings')[source]

Bases: object

One runnable GUI/headless application contributed by a plugin.

Discovery rejects the contribution with ValueError when section, stage, kind or call_style falls outside the fixed vocabulary listed below, when key does not match ^[a-z][a-z0-9_]{1,63}$, or when any non-empty module:callable reference is malformed.

Variables:
  • key – identifier the CLI accepts and the GUI registers under; must match ^[a-z][a-z0-9_]{1,63}$. Reusing another plugin’s key fails that plugin’s load; colliding with a built-in app skips the contribution and records a diagnostic.

  • name – human-readable title shown in the sidebar and screen header; cannot be blank.

  • description – one-line blurb used as the app intro and the spacr-run --list summary; cannot be blank.

  • entrypoint – "module:callable" reference to the callable that does the work.

  • defaults – "module:callable" reference to a helper returning the settings dictionary; called with {} and retried with no argument.

  • section – sidebar group; one of "core", "data", "models", "results" or "toxo".

  • stage – maturity annotation; one of "alpha", "beta" or "stable".

  • kind – what the app is; one of "assay", "importer", "analysis" or "utility".

  • categories – settings-screen tabs, mapping a tab name to the setting keys it holds; empty means the generic ungrouped layout.

  • tooltips – hover text per setting key.

  • labels – display label per setting key, overriding the generated one.

  • docs_url – address the settings screen’s API link opens.

  • aliases – extra names the CLI and spacr.validate resolve to key.

  • validator – optional "module:callable" reference to a callable taking the settings dict and returning spacr.validate.Problem objects or equivalent mappings.

  • screen_factory – optional "module:callable" reference to a factory returning a QWidget, replacing the generic settings screen; it is always invoked as factory(app_key=...) and so must accept that keyword.

  • drop_handler – optional "module:callable" reference to a spacr.qt.dnd_handlers.DropHandler subclass.

  • icon – absolute image path, or the name of a spaCR semantic icon; empty falls back to the puzzle-piece icon.

  • requires – settings the user must supply, phrased for a human.

  • writes – what the app leaves on disk.

  • call_style – "settings" for fn(settings_dict); "folder" for a callable taking a bare path.

aliases: Tuple[str, ...] = ()[source]
call_style: str = 'settings'[source]
categories: Mapping[str, Sequence[str]][source]
defaults: str[source]
description: str[source]
docs_url: str = ''[source]
drop_handler: str = ''[source]
entrypoint: str[source]
icon: str = ''[source]
key: str[source]
kind: str = 'analysis'[source]
labels: Mapping[str, str][source]
name: str[source]
requires: Tuple[str, ...] = ()[source]
screen_factory: str = ''[source]
section: str = 'results'[source]
stage: str = 'alpha'[source]
tooltips: Mapping[str, str][source]
validator: str = ''[source]
writes: Tuple[str, ...] = ()[source]
class spacr.plugins.ModelProviderContribution(key: str, provider: str)[source]

Bases: object

Immutable record naming a plugin’s model-zoo provider.

Parameters:
  • key – identifier for the provider; must match ^[a-z][a-z0-9_]{1,63}$ and be unique across all loaded plugins.

  • provider – "module:callable" reference string – not the callable itself – resolved at catalogue time to a zero-argument callable returning model-zoo entries or entry mappings.

key: str[source]
provider: str[source]
class spacr.plugins.PluginDiagnostic(plugin: str, severity: str, message: str, exception: str = '')[source]

Bases: object

One discovery or contribution error visible to users and logs.

Parameters:
  • plugin – entry-point or manifest name identifying the plugin that could not be loaded.

  • severity – diagnostic level, such as "error" or "warning".

  • message – concise user-facing account of the failed operation.

  • exception – captured exception text with the technical cause; empty when no exception accompanied the diagnostic.

exception: str = ''[source]
message: str[source]
plugin: str[source]
severity: str[source]
class spacr.plugins.ReportContext(src: Any, artifacts: Mapping[str, Any], runs: Tuple[Mapping[str, Any], ...], options: Mapping[str, Any])[source]

Bases: object

Read-only inputs passed to plugin report-section builders.

Parameters:
  • src – source folder or object from which the core report is built.

  • artifacts – named core report artifacts available for reuse by the plugin section.

  • runs – immutable sequence of recorded run summaries associated with the report source.

  • options – report-generation options supplied by the caller.

artifacts: Mapping[str, Any][source]
options: Mapping[str, Any][source]
runs: Tuple[Mapping[str, Any], ...][source]
src: Any[source]
class spacr.plugins.ReportSectionContribution(key: str, title: str, builder: str, after: str = 'statistics')[source]

Bases: object

Immutable record naming a builder that adds one report section.

spacr.report.collect_report() resolves and calls the builder, and substitutes a visible problem section if it fails.

Parameters:
  • key – stable section identifier; plugin validation requires ^[a-z][a-z0-9_]{1,63}$ and discovery rejects duplicate contribution keys.

  • title – fallback section heading used when the builder returns no title and when the builder fails; cannot be blank.

  • builder – "module:callable" reference resolved at report collection to a callable taking ReportContext and returning a spacr.report.Section.

  • after – existing section key after which this section is inserted; an unmatched key appends it to the report.

after: str = 'statistics'[source]
builder: str[source]
key: str[source]
title: str[source]
class spacr.plugins.SpacrPlugin(name: str, version: str, api_version: str = '1.0', apps: ~typing.Tuple[~spacr.plugins.AppContribution, ...] = (), model_providers: ~typing.Tuple[~spacr.plugins.ModelProviderContribution, ...] = (), report_sections: ~typing.Tuple[~spacr.plugins.ReportSectionContribution, ...] = (), translations: ~typing.Mapping[str, ~typing.Mapping[str, str]] = <factory>)[source]

Bases: object

Validated plugin manifest returned by a spacr.plugins entry point.

Parameters:
  • name – human-readable plugin name used in diagnostics and discovery output.

  • version – version of the plugin distribution, reported to users without being interpreted by spaCR.

  • api_version – plugin SDK version the manifest targets; its major version must match PLUGIN_API_VERSION.

  • apps – runnable applications the plugin adds to the GUI and headless registry.

  • model_providers – providers that extend the model-zoo catalogue.

  • report_sections – builders that insert plugin-owned sections into generated reports.

  • translations – locale-to-message mappings that translate the plugin’s own visible strings.

api_version: str = '1.0'[source]
apps: Tuple[AppContribution, ...] = ()[source]
model_providers: Tuple[ModelProviderContribution, ...] = ()[source]
name: str[source]
report_sections: Tuple[ReportSectionContribution, ...] = ()[source]
translations: Mapping[str, Mapping[str, str]][source]
version: str[source]
spacr.plugins.diagnostics() → Tuple[PluginDiagnostic, ...][source]

Return discovery and runtime contribution failures.

spacr.plugins.discover_plugins() → Tuple[SpacrPlugin, ...][source]

Return every valid discovered plugin in deterministic order.

Returns an empty tuple, with no diagnostic recorded, when SPACR_DISABLE_PLUGINS is set to 1, true, yes or on (case-insensitively): nothing is imported at all. The result is cached; reload_plugins() discards the cache and discovers again.

spacr.plugins.get_app(key: str) → AppContribution | None[source]

Return a contributed app by key, or None.

spacr.plugins.load_object(reference: str) → Any[source]

Import and return module:attribute (nested attributes supported).

spacr.plugins.model_providers() → Tuple[Tuple[str, ModelProviderContribution], ...][source]

Return (plugin_name, provider) model-zoo contributions.

spacr.plugins.plugin_apps() → Tuple[AppContribution, ...][source]

Return all contributed applications.

spacr.plugins.plugin_from_mapping(value: Mapping[str, Any]) → SpacrPlugin[source]

Validate a mapping and return its immutable SpacrPlugin.

spacr.plugins.record_diagnostic(plugin: str, message: str, exception: Any = '', severity: str = 'error') → None[source]

Record a model/report/runtime plugin failure without aborting spaCR.

spacr.plugins.reload_plugins() → Tuple[SpacrPlugin, ...][source]

Clear the discovery cache and discover again (primarily for tests/dev).

spacr.plugins.report_sections() → Tuple[Tuple[str, ReportSectionContribution], ...][source]

Return (plugin_name, section) report contributions.