Inspect plugin contracts and discovery
A plugin must be installed and registered before the CLI can discover it.
Core defines configuration and lifecycle contracts; the Rust r2x executable
owns installed-package discovery and generated command help.
This tutorial first inspects a complete class without requiring external model data.
Inspect a complete plugin
Section titled “Inspect a complete plugin”>>> import inspect>>> from r2x_core import Plugin, PluginConfig, PluginContext, System>>> from rust_ok import Ok, Result>>> class DemoConfig(PluginConfig):... scenario: str = "reference">>> class BuildDemo(Plugin[DemoConfig]):... def on_build(self) -> Result[System, str]:... return Ok(System(name=self.config.scenario))>>> plugin = BuildDemo.from_context(PluginContext(config=DemoConfig()))>>> # Expected: this class implements a build hook, not a hidden parser registry.>>> sorted(name for name, value in vars(BuildDemo).items() if name.startswith("on_") and callable(value))['on_build']>>> list(inspect.signature(BuildDemo.on_build).parameters)['self']>>> DemoConfig.model_json_schema()["properties"]["scenario"]["default"]'reference'>>> plugin.run().system.name'reference'The hook list and schema above come from the actual class and configuration, not a hand-written catalog claiming ReEDS or PLEXOS behavior. A real parser that reads files is demonstrated in Build a parser.
Inspect a Python 3.12 generic transform
Section titled “Inspect a Python 3.12 generic transform”This example uses PEP 695 type parameters and requires Python 3.12 or newer.
The ... def line is valid here: it continues the statement started by
>>> @expose_plugin. An undecorated top-level definition would start with >>> def.
The type parameter bound supports static checking; it is not a replacement for
runtime validation of plugin configuration.
>>> from r2x_core import expose_plugin, PluginConfig, System>>> from rust_ok import Ok, Result
>>> class BaseTransformConfig(PluginConfig):... pass
>>> class ScaleConfig(BaseTransformConfig):... factor: float = 1.0
>>> class RotateConfig(BaseTransformConfig):... angle: float = 0.0
>>> @expose_plugin... def generic_transform[C: BaseTransformConfig](... system: System,... config: C,... ) -> Result[System, str]:... """Generic transform accepting constrained config types."""... system.name = f"{system.name}_transformed"... return Ok(system)
>>> scale_cfg = ScaleConfig(factor=2.5)>>> result = generic_transform(System(name="grid"), scale_cfg)>>> # Expected: the typed transform executed and changed the system name.>>> result.unwrap().name'grid_transformed'Register an installable package
Section titled “Register an installable package”For a class parser, the package declares its module and class in r2x.parsers.
For an exposed function transform, use r2x.transforms.
Names in these entry points are the CLI references; Python class names are not
automatically executable commands.
The complete CLI fixture package
contains actual package metadata and can be installed without licensed model data.
Inspect installed references with the Rust CLI
Section titled “Inspect installed references with the Rust CLI”After installing that fixture with the CLI tutorial, these commands inspect its
real create and scale references:
r2x list r2x-tutorialr2x run create --helpr2x run scale --helpThere is no plugins list subcommand or Python-module CLI invocation.
If discovery differs, use CLI troubleshooting.
The function-plugin guide explains
configuration and callable contracts with checked examples.