Packaging a Pluginο
This guide explains how to package and distribute a SpectroChemPy plugin.
Project structureο
A minimal plugin project looks like this:
spectrochempy-myplugin/
βββ pyproject.toml
βββ README.md
βββ LICENSE
βββ src/
β βββ myplugin/
β βββ __init__.py # Plugin class + reader/writer functions
βββ tests/
β βββ __init__.py
β βββ test_plugin.py
βββ .github/
βββ workflows/
βββ test.yml # CI configuration (optional)
pyproject.tomlο
The entry point group spectrochempy.plugins tells SpectroChemPy how
to discover your plugin automatically:
[build-system]
requires = ["setuptools>=64"]
build-backend = "setuptools.build_meta"
[project]
name = "spectrochempy-myplugin"
version = "0.1.0"
description = "My SpectroChemPy plugin"
requires-python = ">=3.11"
dependencies = [
"spectrochempy>=0.9.0.dev0,<0.10",
]
[project.entry-points."spectrochempy.plugins"]
myplugin = "myplugin:MyPlugin"
[tool.setuptools.packages.find]
where = ["src"]
[tool.pytest.ini_options]
testpaths = ["tests"]
Key points:
The entry point name (
myplugin) must match your pluginβsnameattribute.spectrochempymust be listed as a dependency with a compatibility range, e.g.spectrochempy>=0.9.0.dev0,<0.10.Use
requires-python = ">=3.11"to match SpectroChemPyβs minimum.Official plugins in the monorepo use a static
versionfield.setuptools_scmis not used because plugin and core tags share the same Git repository, which would cause version collisions.
Local editable developmentο
During local development, install the core package and each plugin in editable mode. This exercises the same entry-point discovery mechanism used by PyPI wheels:
pip install -e .
pip install -e plugins/spectrochempy-nmr
pip install -e plugins/spectrochempy-iris
pip install -e plugins/spectrochempy-cantera
The bundled plugins can also be installed with the helper:
python -m spectrochempy.ci.install_plugins --editable all
After installation, SpectroChemPy discovers the plugins automatically via
the spectrochempy.plugins entry point group.
Installing from SpectroChemPy extrasο
Users can install official plugins through SpectroChemPy extras:
pip install "spectrochempy[nmr]"
pip install "spectrochempy[iris]"
pip install "spectrochempy[plugins]"
The nmr extra installs the NMR plugin, currently including the TopSpin
reader and its NMR-specific dependencies. The plugins extra installs the
current official plugin set.
Experimental plugins such as spectrochempy-cantera are not included
in aggregate extras and must be installed directly:
pip install spectrochempy-cantera
__init__.py β the plugin classο
Your plugin class must implement the
SpectroChemPyPlugin protocol:
from spectrochempy.api.plugins import (
CORE_PLUGIN_API_VERSION,
SpectroChemPyPlugin,
)
class MyPlugin(SpectroChemPyPlugin):
name = "myplugin"
version = "0.1.0"
description = "My SpectroChemPy plugin"
spectrochempy_min_version = "0.9.0.dev0"
PLUGIN_API_VERSION = CORE_PLUGIN_API_VERSION
def register_readers(self) -> list[dict]:
return [...]
See Writing a Plugin for the full API reference.
Entry point discovery flowο
User runs
import spectrochempy(or callsscp.read_xxx).PluginManagerscansimportlib.metadata.entry_points(group="spectrochempy.plugins").Each entry point is loaded, instantiated, and validated.
Declarative hooks (
register_readers(), β¦) are collected.Contributions are registered in the plugin registry.
The plugin is marked
ACTIVE(orFAILEDif an error occurs).
Distribution (PyPI)ο
Official plugins that still live in the SpectroChemPy monorepo are published from the root workflow:
.github/workflows/publish_plugins.yml
GitHub Actions only executes workflows from the repository root, so workflows
stored inside plugins/<plugin>/.github/workflows/ are templates only while
the plugin remains in the monorepo. If a plugin is later moved to its own
repository, copy the template workflow to that repositoryβs root
.github/workflows/ directory.
The monorepo workflow uses PyPI Trusted Publishing. Each plugin distribution
must therefore have its own PyPI/TestPyPI trusted publisher configured with the
matching project name, for example spectrochempy-nmr.
For a manual local upload:
pip install build twine
python -m build
twine upload dist/*
Name your package spectrochempy-<name> to make it discoverable.
Release policyο
Plugins are released independently from the core package.
A core release tag such as
0.9.0publishes the core wheel only; it does not trigger plugin uploads.A plugin release tag such as
spectrochempy-nmr-v0.1.1triggers thepublish_plugins.ymlandbuild_package.ymlworkflows for that plugin only.The workflow uses
skip-existing: trueon PyPI so an already-published version never causes a hard failure.
Bumping a plugin versionο
Plugin versions are declared statically in the monorepo (setuptools-scm
is not used for plugins because plugin and core tags share the same Git
repository, which leads to version collisions).
The recommended way to release a plugin is through the
release_plugin.yml workflow:
Go to Actions β Release an official plugin in the GitHub UI.
Click Run workflow.
Enter: - Plugin name:
spectrochempy-nmr- Version:0.1.1The workflow bumps
pyproject.tomlandrecipe.yaml, commits, pushes to thepluginsbranch, and creates the release tagspectrochempy-nmr-v0.1.1automatically.The tag triggers CI which builds and publishes the wheel to PyPI and Anaconda.org.
Manual fallback:
# 1. Bump version in plugins/<name>/pyproject.toml
# 2. Bump version in plugins/<name>/recipe.yaml (conda)
# 3. Commit and push:
git add plugins/<name>/pyproject.toml plugins/<name>/recipe.yaml
git commit -m "Bump spectrochempy-<name> to 0.1.1"
git push upstream plugins
# 4. Create and push the release tag:
git tag spectrochempy-<name>-v0.1.1
git push upstream spectrochempy-<name>-v0.1.1
The tag is a pure CI trigger; the actual package version comes from
pyproject.toml (pip) and recipe.yaml (conda).
Distribution (conda)ο
Official plugins with a recipe.yaml in their root are built and
published to Anaconda.org automatically by build_package.yml.
Dev builds (pushes, PRs) are uploaded to the
devlabel:mamba install -c spectrocat/label/dev -c conda-forge spectrochempy-nmr
Stable builds (releases) are uploaded to the
mainlabel:mamba install -c spectrocat -c conda-forge spectrochempy-nmr
Plugin recipes should declare a bounded dependency on the core package,
e.g. spectrochempy >=0.9.0.dev0,<0.10.
The plugin-template directory is excluded from discovery; it is a
developer scaffold and must never be published.
CI / Testingο
A recommended CI workflow tests against multiple Python versions:
# .github/workflows/test.yml
jobs:
test:
strategy:
matrix:
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ["3.11", "3.12", "3.13"] # set via CI matrix
- name: Install SpectroChemPy
run: |
git clone https://github.com/spectrochempy/spectrochempy.git
pip install -e ./spectrochempy
- name: Install plugin
run: pip install -e ".[dev]"
- name: Run tests
run: python -m pytest tests/ -v
Use the PluginTestHarness (see Testing a Plugin) for isolated
testing without touching the global registry.
See alsoο
Writing a Plugin β Writing a plugin
Testing a Plugin β Testing a plugin