Plugin System¶
NeXusCreator automatically discovers generator and parser plugins that live under plugins/. Each
plugin can participate in generation (producing .nxd/YAML definitions) and/or parsing (building
variable libraries from inputs).
Built-in Plugins¶
SPEC (
plugins/spec_plugin.py) — generator + parser for SPEC scans.DTA/DAT (
plugins/dta_plugin.py) — generator + parser for batteries workflows (RAW, non-RAW, temperature datasets). Use-b batteriesto activate the folder generator.HDF5/NeXus (
plugins/hdf5_plugin.py) — generate definitions and variable libraries from existing NeXus/HDF5 files (--hdf5-option linksorextract).TIFF (
plugins/tiff_plugin.py) — create detector/data placeholders and NXdata links from TIFF images.PEAXIS (
plugins/peaxis_plugin.py) — folder generator and parsers for SIF/XAS/DAT inputs. Use-b peaxisto activate.YAML (
plugins/yaml_plugin.py) — generator + parser for YAML-format data files (.yaml,.yml). Supports SchemaPlacer-guided placement when--nxdl-rootis provided.MPES (
plugins/mpes_plugin.py) — generator + parser for MPES HDF5 inputs. Activated by-b mpes; useslibraries/mpes_utils.pyto locate the HDF5 file.JSON-LD (
plugins/jsonld_plugin.py) — generator + parser for fixed-width/delimited text files described via a CDI/Schema.org JSON-LD document (--jsonld-structure FILE). Pairs with SchemaPlacer for NXDL-guided placement.Diamond B18 XAFS (
plugins/diamond_ascii_plugin.py) — detects either the ASCII exports underdata/cdi-ddi/.../asciior the matching NeXus files under.../nexus, parses both into a single library, and emits anNXxas-compliant definition referencing every parsed variable.
Parser and Generator System¶
In addition to the plugin system, NeXusCreator includes a parser and generator system that provides a consistent and extensible way to handle different input formats and generate NeXus definitions.
Base Classes¶
BaseParser: Defines the interface for all parsers. Each parser must implement:
can_parse(input_path: str) -> bool: Checks if the parser can handle the given input path.parse(input_path: str) -> Dict[str, object]: Parses the input file and returns a flat library.
BaseGenerator: Defines the interface for all generators. Each generator must implement:
can_generate(input_path: str) -> bool: Checks if the generator can handle the given input path.generate(input_path: str) -> dict: Generates a NeXus-definition object from the input.
Managers¶
ParserManager: Manages the discovery and registration of parsers.
Discovers all parsers in the
parserspackage.Provides a method to get a parser for a specific file type.
GeneratorManager: Manages the discovery and registration of generators.
Discovers all generators in the
generatorspackage.Provides a method to get a generator for a specific file type.
Discovery and Registration¶
The system automatically discovers and registers parsers and generators by:
Importing all modules in the
parsersorgeneratorspackage.Finding all classes that inherit from
BaseParserorBaseGenerator.Instantiating these classes and sorting them by priority.
Usage¶
To use the parser and generator system:
from nexuscreator.parsers import get_parser_manager
from nexuscreator.generators import get_generator_manager
# Get a parser for a specific file type
parser_manager = get_parser_manager()
parser = parser_manager.get_parser("test.dta")
if parser:
library = parser.parse("test.dta")
# Get a generator for a specific file type
generator_manager = get_generator_manager()
generator = generator_manager.get_generator("test.dta")
if generator:
nexus_object = generator.generate("test.dta")
Creating a New Parser or Generator¶
To create a new parser or generator:
Create a new parser:
from nexuscreator.parsers.base import BaseParser
class MyParser(BaseParser):
id: str = 'my-parser'
priority: int = 10
def can_parse(self, input_path: str) -> bool:
return input_path.lower().endswith('.myformat')
def parse(self, input_path: str) -> Dict[str, object]:
# Parse the file and return a flat library
return {"key": "value"}
Create a new generator:
from nexuscreator.generators.base import BaseGenerator
class MyGenerator(BaseGenerator):
id: str = 'my-generator'
priority: int = 10
def can_generate(self, input_path: str) -> bool:
return input_path.lower().endswith('.myformat')
def generate(self, input_path: str) -> dict:
# Generate a NeXus-definition object from the input
return {"entry": {"@NX_class": "NXentry"}}
Benefits¶
Consistency: All parsers and generators follow a consistent interface.
Extensibility: New parsers and generators can be easily added by inheriting from the base classes.
Discoverability: The system automatically discovers and registers parsers and generators.
Testability: The new system is well-tested, ensuring reliability.
How Discovery Works¶
DefinitionGeneratorPluginimplementscan_generate()andgenerate_definition().DataParserPluginimplementscan_parse()andparse_to_library().Modules in
plugins/are imported automatically; no explicit registration is required.Plugins declare an
idand optionalpriorityto influence selection order.Optional external plugins can be imported from filesystem paths via
NEXUSCREATOR_PLUGIN_PATHS(path-separated list of.pyfiles or directories).
Create Your Own Plugin¶
Subclass
DefinitionGeneratorPluginand/orDataParserPlugin.Implement
can_*narrowly (extension, beamline, folder shape, etc.).Return:
generator: a valid
nexus_objectdictparser: a flat library dict compatible with placeholder injection
Set
priority(lower value wins) when multiple plugins could match.
Minimal parser + generator¶
from nexuscreator.plugins.base import DefinitionGeneratorPlugin, DataParserPlugin
class MyGenerator(DefinitionGeneratorPlugin):
id = "my-generator"
priority = 40
def can_generate(self, input_path, beamline, flags):
return input_path.lower().endswith(".abc")
def generate_definition(self, input_path, beamline, flags):
return {
"entry": {
"@NX_class": "NXentry",
"data": {
"@NX_class": "NXdata",
"@signal": "counts",
"@axes": "energy",
"energy": {"@dtype": "NX_FLOAT64[]", "@value": "energy"},
"counts": {"@dtype": "NX_FLOAT64[]", "@value": "counts"},
},
}
}
class MyParser(DataParserPlugin):
id = "my-parser"
priority = 40
def can_parse(self, input_path, beamline, flags):
return input_path.lower().endswith(".abc")
def parse_to_library(self, input_path, beamline, flags):
return {"energy": [1.0, 2.0, 3.0], "counts": [10.0, 20.0, 30.0]}
External plugin loading¶
You can keep plugins outside this repository and point NeXusCreator to them:
export NEXUSCREATOR_PLUGIN_PATHS="/path/to/my_plugins:/path/to/custom_plugin.py"
For plugin import diagnostics:
export NEXUSCREATOR_PLUGIN_DEBUG=1
Minimal Example¶
from nexuscreator.plugins.base import DefinitionGeneratorPlugin
class MyGenerator(DefinitionGeneratorPlugin):
id = "my-generator"
def can_generate(self, input_path, beamline, flags):
return input_path.endswith(".abc")
def generate_definition(self, input_path, beamline, flags):
# Return a NeXus definition object (dict-like)
return {"entry": {"@NX_class": "NXentry"}}
Tip: combine your plugin with SchemaPlacer to map variables into canonical NXDL paths automatically.