Plugin API Policy
SpectroChemPy plugins expose public APIs in two complementary places. Choose the location from the kind of operation, not from the plugin name.
Package/plugin namespaces
Use scp.<plugin>.* for functions that create objects, read files, or run
global plugin-level workflows. These functions do not operate on an existing
NDDataset instance as their parent object.
Examples:
scp.nmr.read_topspin(...)
scp.iris.IRIS(...)
scp.iris.batch_iris(...)
The legacy alias scp.read_topspin(...) is kept as a compatibility layer for
existing code. When the NMR plugin is installed, it delegates through the
plugin reader registry to scp.nmr.read_topspin(...). When the plugin is not
installed, the core stub raises a MissingPluginError with the install hint
pip install spectrochempy[nmr].
Dataset accessors
Use dataset.<plugin>.* only for operations that genuinely use the parent
NDDataset as input. The accessor callable receives the dataset as its first
argument.
Examples:
dataset.iris.kernel_matrix(...)
Avoid dataset accessors for I/O, object creation, or high-level scientific workflows. In particular, do not add APIs such as:
dataset.read_topspin(...)
dataset.nmr.read_topspin(...)
dataset.nmr.phase(...)
dataset.nmr.apodize(...)
For NMR, the high-level scientific API is Experiment:
dataset = scp.nmr.read(path)
experiment = scp.nmr.Experiment(dataset)
spectrum = experiment.process(
apodization="em", lb=10.0, phase="manual", phc0=45.0
)
Low-level NMR operations (apodization, phasing, FFT) already exist as
NDDataset methods (dataset.em(...), dataset.pk(...),
dataset.fft()). The NMR-specific orchestration and scientific
interpretation belong exclusively to Experiment, avoiding two concurrent
high-level APIs.
Current implementation note
The current plugin registry stores namespaced dataset accessors as string keys
such as "iris.kernel_matrix". At runtime,
DatasetPluginAccessor exposes this as dataset.iris.kernel_matrix(...).
This is an incremental mechanism, not a final accessor-class design.
A future cleanup may move mature domains toward real accessor classes, but the public policy should remain stable:
I/O, object creation, and global workflows belong at
scp.<plugin>.*.Operations on an existing dataset belong at
dataset.<plugin>.*.Legacy aliases are thin compatibility layers, not new primary APIs.
Namespace conventions
Official plugin namespaces should be short, stable, and domain-oriented. They
represent the scientific or technical domain exposed to users, for example
scp.iris or scp.nmr. Experimental plugin namespaces such as
scp.cantera follow the same naming convention but are not yet stable.
Avoid creating a second namespace
for the same domain unless there is a clear migration plan.
Core I/O namespaces such as jcamp, csv, omnic, opus,
matlab, spc, soc, wire, quadera, and labspec
are reserved. Plugins must not claim these names, to prevent shadowing
and keep scp.<domain> unambiguous.
Reserved public root symbols
A plugin’s short I/O namespace must not collide with a public scp symbol.
Registration refuses the namespace with a controlled warning whenever its name
matches an existing public scp symbol — a public function or class, an
NDDataset method exposed at root, a compatibility alias, a public
submodule, a core I/O namespace, or a plot-profile function. The rejected
name is recorded in spectrochempy.core.io_namespaces._REJECTED_IO_NAMESPACES
for introspection.
The reader behind a refused namespace is unaffected: it remains available
through its explicit read_<format> function (for example
scp.read_simpson / scp.<plugin>.read_simpson). Never rely on a short
namespace that matches a public root symbol, and never build a hybrid object
that is both callable and carries .read.
For the other plugin-provided root surfaces (root_exports, reader exports,
analysis and simulation extensions), the guarantee is resolution
priority: whenever a name is a public scp symbol, root attribute access
always resolves to the core symbol, regardless of plugin installation or
discovery order. These surfaces are not rejected at registration time.
I/O namespace names colliding with a public scp symbol are rejected at
registration; all other plugin root surfaces are resolved core-first, so
the core symbol always wins.
Documentation and examples should prefer namespace APIs, such as
scp.iris.IRIS(), over root-level compatibility
aliases such as scp.IRIS. Compatibility aliases may remain in
tests when they intentionally protect old user code.