Extension SDK and Registry#

EEGPrep discovers external Python extensions through the eegprep.extensions entry-point group. An entry point should load a lightweight register() function, and that function must return an eegprep.ExtensionSpec. The register function may import the SDK, read small metadata constants, and declare lazy targets, but it should not import heavy processing, GUI, or machine-learning modules.

Extension specs are declarative. Actions and pop_* functions use LazyImport("package.module", "callable_name") so GUI startup and registry inspection do not import the callable modules. Packaged help and data resources are checked during validation because missing user-facing resources should be visible before an extension is activated.

Minimal extension entry point#

from eegprep import ExtensionAction, ExtensionSpec, LazyImport

def register():
    return ExtensionSpec(
        name="my_extension",
        display_name="My Extension",
        version="1.0.0",
        api_version="1",
        package_name="eegprep-ext-my-extension",
        actions=(
            ExtensionAction(
                name="my_extension.run",
                target=LazyImport("my_extension.actions", "run"),
            ),
        ),
    )

The package advertises the function through standard Python package metadata:

[project.entry-points."eegprep.extensions"]
my_extension = "my_extension.register:register"

Status model#

ExtensionRegistry.discover() returns deterministic ExtensionRecord objects. Records remain visible when an extension fails so one broken package does not crash EEGPrep startup. Status values are bundled, installed, curated, disabled, incompatible, failed_import, invalid_spec, missing_dependency, and unknown.

Bundled EEGPrep plugin ports are exposed as bundled extension records for inventory purposes. The GUI menu builder, Extension Manager, help lookup, and eegprep-console all consume the shared runtime registry so bundled and external extension contributions follow one status and lazy-loading model.

Catalog and Governance#

Extension Manager catalog loading lives in eegprep.extension_catalog. Catalog submission validation lives in eegprep.extension_catalog_validation and is also available as the eegprep-validate-extension-catalog console script. Static validation checks JSON schema version, required metadata, naming, URLs, license, maintainer contact, docs, conflicts, curation status, and compatibility fields without requiring the extension package to be installed.

Stricter validation can also check installed package versions, required dependencies, the eegprep.extensions entry point, import failures, and whether the imported ExtensionSpec matches the catalog metadata.

See Extension Curation and Catalog Policy for the official curation policy, trust message, compatibility rules, catalog submission format, and naming recommendations.

Author Test Harness#

ExtensionTestHarness provides reusable assertions for extension authors. It checks that a spec validates, menus reference declared actions or pop_* functions, help resources exist, lazy targets load, and callable actions or pop_* functions return history-aware (EEG, com) results when tested by the author.

Extension Manager and catalog#

plugin_menu(show=False) returns the Extension Manager inventory for scripts and eegprep-console. The inventory is built from registry records plus a metadata-only curated catalog loaded from packaged resources, a local catalog_path=, or EEGPREP_EXTENSION_CATALOG. Catalog entries are advisory metadata: package names, repository/documentation links, maintainers, capabilities, and safe install-command strings. They never contain code zips, and EEGPrep never executes install or update commands.

Extension Manager catalogs use catalog_kind: "extension_manager". The curation submission validator uses catalog_kind: "extension_curation" so local manager catalogs and catalog-repository submissions cannot be confused.

Use load_extension_catalog() to inspect a local catalog before passing it to plugin_menu:

catalog = eegprep.load_extension_catalog("lab-extension-catalog.json")
plugins = eegprep.plugin_menu(catalog=catalog, show=False)

build_safe_install_commands() and build_safe_update_commands() return copyable strings such as uv add eegprep-ext-foo or pip install git+https://github.com/example/eegprep-ext-foo.git. They do not run subprocesses.

Authoring examples#

Checked-in authoring packages live under examples/extensions. Start with the template package there, then compare the focused variants for signal transforms, file import/export, GUI dialogs, plot/browser callbacks, and optional dependencies. The same directory includes a developer checklist for GUI parity, console/history behavior, EEG data semantics, package data, dependencies, tests, and version compatibility.

API Reference#

eegprep.CATALOG_SCHEMA_VERSION

int([x]) -> integer int(x, base=10) -> integer

eegprep.CatalogValidationIssue(message[, ...])

One catalog metadata validation issue.

eegprep.CatalogValidationOptions([...])

Validation switches for local and future catalog-CI checks.

eegprep.CatalogValidationReport([errors, ...])

Catalog validation result with blocking errors and non-blocking warnings.

eegprep.EXTENSION_COMPATIBILITY_POLICY

str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

eegprep.EXTENSION_CURATION_POLICY_URL

str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

eegprep.EXTENSION_NAMING_PREFIX

str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

eegprep.EXTENSION_TRUST_MESSAGE

str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

eegprep.ExtensionSpec(name[, display_name, ...])

Declarative metadata returned by an eegprep.extensions entry point.

eegprep.ExtensionRegistry(*[, ...])

Discover, validate, and report EEGPrep extensions.

eegprep.ExtensionRecord(name, status[, ...])

A discovered extension plus status and validation details.

eegprep.ExtensionStatus(value)

Registry status for an extension record.

eegprep.ExtensionSourceType(value)

Source category declared by an extension.

eegprep.ExtensionCatalog([entries, source, ...])

Loaded extension catalog plus source diagnostics.

eegprep.ExtensionCatalogEntry(name[, ...])

Curated metadata for an EEGPrep extension, without bundled code.

eegprep.CatalogSourceType(value)

Install/source categories accepted by the curated catalog.

eegprep.ExtensionAction(name, target[, ...])

Declarative action contributed by an extension.

eegprep.ExtensionPopFunction(name, target[, ...])

Declarative pop_* function contributed by an extension.

eegprep.ExtensionMenu([path, action, label, ...])

Declarative menu contribution for an extension action.

eegprep.ExtensionDependency(package[, ...])

Python distribution required by an extension.

eegprep.ExtensionResource(package, path)

Packaged resource declared by an extension.

eegprep.ExtensionLoadError

Raised when a lazily referenced extension object cannot be loaded.

eegprep.ExtensionValidationResult([...])

Validation errors grouped by registry status category.

eegprep.ExtensionTestHarness(spec)

Assertion helper for extension author test suites.

eegprep.LazyImport(module, attr)

Reference to an object that should be imported only when used.

eegprep.assert_extension_entry_point_loads(...)

Assert that an eegprep.extensions entry point loads to a usable spec.

eegprep.check_extension_compatibility(spec, *)

Check extension API, EEGPrep version, and dependency compatibility.

eegprep.discover_extensions(*[, ...])

Discover EEGPrep extensions with the default registry settings.

eegprep.extension_version_satisfies(version, ...)

Return whether version satisfies a simple PEP 440-style specifier.

eegprep.load_catalog_entries(path)

Load catalog entries from a JSON file or a directory of JSON files.

eegprep.validate_catalog_entries(entries, *)

Validate catalog metadata entries.

eegprep.validate_catalog_file(path, *[, options])

Validate catalog metadata loaded from path.

eegprep.validate_extension_spec(spec, *[, ...])

Validate an extension spec without importing its lazy action targets.

eegprep.load_extension_catalog([catalog_path])

Load the packaged or local metadata-only extension catalog.

eegprep.build_safe_install_commands(entry)

Return copyable install commands for a catalog entry without executing them.

eegprep.build_safe_update_commands(entry)

Return copyable update commands for a catalog entry without executing them.

External extension SDK and discovery registry for EEGPrep.

class eegprep.extensions.ExtensionAction(name, target, display_name='', description='', capabilities=<factory>)

Bases: object

Declarative action contributed by an extension.

Parameters:
name: str
target: LazyImport
display_name: str = ''
description: str = ''
capabilities: tuple[str, ...]
load()

Load the callable target for this action.

Return type:

Any

class eegprep.extensions.ExtensionDependency(package, version_spec='', optional=False)

Bases: object

Python distribution required by an extension.

Parameters:
  • package (str)

  • version_spec (str)

  • optional (bool)

package: str
version_spec: str = ''
optional: bool = False
exception eegprep.extensions.ExtensionLoadError

Bases: RuntimeError

Raised when a lazily referenced extension object cannot be loaded.

class eegprep.extensions.ExtensionMenu(path=<factory>, action='', label='', tag='', userdata='', separator=False, enabled=True, checked=False, visibility='always', insert_after='', insert_before='', children=<factory>)

Bases: object

Declarative menu contribution for an extension action.

Parameters:
path: tuple[str, ...]
action: str = ''
label: str = ''
tag: str = ''
userdata: str = ''
separator: bool = False
enabled: bool = True
checked: bool = False
visibility: str = 'always'
insert_after: str = ''
insert_before: str = ''
children: tuple[ExtensionMenu, ...]
class eegprep.extensions.ExtensionPopFunction(name, target, description='')

Bases: object

Declarative pop_* function contributed by an extension.

Parameters:
name: str
target: LazyImport
description: str = ''
load()

Load the callable target for this pop_* function.

Return type:

Any

class eegprep.extensions.ExtensionRecord(name, status, spec=None, source_type=ExtensionSourceType.UNKNOWN, package_name='', entry_point_name='', enabled=True, errors=<factory>)

Bases: object

A discovered extension plus status and validation details.

Parameters:
name: str
status: ExtensionStatus
spec: ExtensionSpec | None = None
source_type: ExtensionSourceType = 'unknown'
package_name: str = ''
entry_point_name: str = ''
enabled: bool = True
errors: tuple[str, ...]
property is_active: bool

Return whether this record can contribute runtime behavior.

class eegprep.extensions.ExtensionRegistry(*, disabled_extensions=None, include_bundled=True, include_entry_points=True, entry_point_group='eegprep.extensions', entry_points_provider=<function entry_points>, current_version=None, version_provider=<function version>)

Bases: object

Discover, validate, and report EEGPrep extensions.

Parameters:
  • disabled_extensions (set[str] | list[str] | tuple[str, ...] | None)

  • include_bundled (bool)

  • include_entry_points (bool)

  • entry_point_group (str)

  • entry_points_provider (EntryPointsProvider)

  • current_version (str | None)

  • version_provider (VersionProvider)

property records: tuple[ExtensionRecord, ...]

Return records from the latest discovery pass.

discover(*, include_plugins=True)

Discover extensions and return deterministic registry records.

Parameters:

include_plugins (bool)

Return type:

tuple[ExtensionRecord, …]

get(name)

Return the latest record for name if present.

Parameters:

name (str)

Return type:

ExtensionRecord | None

class eegprep.extensions.ExtensionResource(package, path)

Bases: object

Packaged resource declared by an extension.

Parameters:
package: str
path: str
exists()

Return whether the packaged resource exists.

Return type:

bool

read_text(encoding='utf-8')

Read this resource as text.

Parameters:

encoding (str)

Return type:

str

read_bytes()

Read this resource as bytes.

Return type:

bytes

class eegprep.extensions.ExtensionSourceType(value)

Bases: str, Enum

Source category declared by an extension.

BUNDLED = 'bundled'
INSTALLED = 'installed'
CURATED = 'curated'
UNKNOWN = 'unknown'
class eegprep.extensions.ExtensionSpec(name, display_name='', version='', api_version='1', package_name='', entry_point_name='', source_type=ExtensionSourceType.INSTALLED, description='', docs_url='', maintainer='', capabilities=<factory>, dependencies=<factory>, menus=<factory>, actions=<factory>, pop_functions=<factory>, help_resources=<factory>, package_data_resources=<factory>, eegprep_requires='')

Bases: object

Declarative metadata returned by an eegprep.extensions entry point.

Parameters:
name: str
display_name: str = ''
version: str = ''
api_version: str = '1'
package_name: str = ''
entry_point_name: str = ''
source_type: ExtensionSourceType | str = 'installed'
description: str = ''
docs_url: str = ''
maintainer: str = ''
capabilities: tuple[str, ...]
dependencies: tuple[ExtensionDependency, ...]
menus: tuple[ExtensionMenu, ...]
actions: tuple[ExtensionAction, ...]
pop_functions: tuple[ExtensionPopFunction, ...]
help_resources: tuple[ExtensionResource, ...]
package_data_resources: tuple[ExtensionResource, ...]
eegprep_requires: str = ''
class eegprep.extensions.ExtensionStatus(value)

Bases: str, Enum

Registry status for an extension record.

BUNDLED = 'bundled'
INSTALLED = 'installed'
CURATED = 'curated'
DISABLED = 'disabled'
INCOMPATIBLE = 'incompatible'
FAILED_IMPORT = 'failed_import'
INVALID_SPEC = 'invalid_spec'
MISSING_DEPENDENCY = 'missing_dependency'
UNKNOWN = 'unknown'
class eegprep.extensions.ExtensionValidationResult(invalid_spec=<factory>, incompatible=<factory>, missing_dependency=<factory>)

Bases: object

Validation errors grouped by registry status category.

Parameters:
invalid_spec: tuple[str, ...]
incompatible: tuple[str, ...]
missing_dependency: tuple[str, ...]
property ok: bool

Return whether validation found no blocking errors.

property errors: tuple[str, ...]

Return all validation errors in status-priority order.

class eegprep.extensions.LazyImport(module, attr)

Bases: object

Reference to an object that should be imported only when used.

Parameters:
module: str
attr: str
load()

Import and return the referenced object.

Return type:

Any

eegprep.extensions.check_extension_compatibility(spec, *, current_version=None, version_provider=<function version>, check_dependencies=True)

Check extension API, EEGPrep version, and dependency compatibility.

This is the compatibility-policy entry point for catalog validation, author tests, and manager status messaging. It does not verify packaged resources, so callers can run it before installing optional help or data files into a test fixture.

Parameters:
Return type:

ExtensionValidationResult

eegprep.extensions.compare_extension_versions(left, right)

Compare two PEP 440 versions, returning -1, 0, or 1.

Parameters:
Return type:

int

eegprep.extensions.discover_extensions(*, disabled_extensions=None, include_plugins=True, include_bundled=True, include_entry_points=True)

Discover EEGPrep extensions with the default registry settings.

Parameters:
Return type:

tuple[ExtensionRecord, …]

eegprep.extensions.extension_api_major_version(version)

Return the integer major component for an extension API/version string.

Parameters:

version (str)

Return type:

int

eegprep.extensions.extension_entry_point_package_name(entry_point)

Return the distribution name associated with an extension entry point.

Parameters:

entry_point (Any)

Return type:

str

eegprep.extensions.extension_status_is_active(status)

Return whether an extension status can contribute runtime behavior.

Parameters:

status (ExtensionStatus | str)

Return type:

bool

eegprep.extensions.extension_status_is_installed(status)

Return whether an extension status represents an installed package/port.

Parameters:

status (ExtensionStatus | str)

Return type:

bool

eegprep.extensions.extension_version_satisfies(version, specifier)

Return whether version satisfies a simple PEP 440-style specifier.

Parameters:
  • version (str)

  • specifier (str)

Return type:

bool

eegprep.extensions.extension_version_spec_is_valid(specifier)

Return whether specifier is a valid EEGPrep extension version spec.

Parameters:

specifier (str)

Return type:

bool

eegprep.extensions.select_extension_entry_points(provider, group)

Return entry points from providers with modern or legacy selection APIs.

Parameters:
Return type:

tuple[Any, …]

eegprep.extensions.validate_extension_spec(spec, *, current_version=None, version_provider=<function version>, check_compatibility=True, check_dependencies=True, check_resources=True)

Validate an extension spec without importing its lazy action targets.

Parameters:
Return type:

ExtensionValidationResult

Runtime Extension Manager catalog loading for EEGPrep.

This module loads the metadata-only catalog that the Extension Manager dialog and console inventory display, and builds copyable (never executed) install/update commands. The submission-curation CI validator lives in eegprep.extension_catalog_validation.

class eegprep.extension_catalog.CatalogSourceType(value)

Bases: str, Enum

Install/source categories accepted by the curated catalog.

PYPI = 'pypi'
GIT = 'git'
LOCAL = 'local'
PRIVATE = 'private'
class eegprep.extension_catalog.ExtensionCatalog(entries=<factory>, source='', errors=<factory>)

Bases: object

Loaded extension catalog plus source diagnostics.

Parameters:
entries: tuple[ExtensionCatalogEntry, ...]
source: str = ''
errors: tuple[str, ...]
property available: bool

Return whether the catalog was loaded without diagnostics.

by_name()

Return entries keyed by normalized extension name.

Return type:

dict[str, ExtensionCatalogEntry]

by_package()

Return entries keyed by normalized Python package name.

Return type:

dict[str, ExtensionCatalogEntry]

class eegprep.extension_catalog.ExtensionCatalogEntry(name, display_name='', version='', package_name='', description='', maintainer='', docs_url='', source_type=CatalogSourceType.PYPI, source_url='', repository_url='', capabilities=<factory>, eegprep_requires='')

Bases: object

Curated metadata for an EEGPrep extension, without bundled code.

Parameters:
name: str
display_name: str = ''
version: str = ''
package_name: str = ''
description: str = ''
maintainer: str = ''
docs_url: str = ''
source_type: CatalogSourceType = 'pypi'
source_url: str = ''
repository_url: str = ''
capabilities: tuple[str, ...]
eegprep_requires: str = ''
property install_target: str

Return the package-manager target for this catalog entry.

property source_label: str

Return user-facing source text for the catalog entry.

eegprep.extension_catalog.build_safe_install_commands(entry)

Return copyable install commands for a catalog entry without executing them.

Parameters:

entry (ExtensionCatalogEntry)

Return type:

dict[str, str]

eegprep.extension_catalog.build_safe_update_commands(entry)

Return copyable update commands for a catalog entry without executing them.

Parameters:

entry (ExtensionCatalogEntry)

Return type:

dict[str, str]

eegprep.extension_catalog.load_extension_catalog(catalog_path=None)

Load the packaged or local metadata-only extension catalog.

Parameters:

catalog_path (str | PathLike[str] | None) – Optional JSON catalog path. When omitted, the EEGPREP_EXTENSION_CATALOG environment variable is checked before the packaged resources/extension_catalog.json fallback.

Returns:

The parsed catalog. Invalid or unavailable catalogs return an empty catalog with errors populated; they do not trigger network access.

Return type:

ExtensionCatalog

eegprep.extension_catalog.parse_extension_catalog(data, *, source='inline')

Parse a catalog JSON object into validated metadata entries.

Parameters:
Return type:

ExtensionCatalog

Submission-curation validator for EEGPrep extension catalog metadata.

This module powers the eegprep-validate-extension-catalog curation CI command. It is separate from the runtime Extension Manager catalog loader in eegprep.extension_catalog; the two share only a handful of catalog constants and the _is_web_url helper.

class eegprep.extension_catalog_validation.CatalogValidationIssue(message, entry_id='', field='')

Bases: object

One catalog metadata validation issue.

Parameters:
message: str
entry_id: str = ''
field: str = ''
format()

Return a concise human-readable issue line.

Return type:

str

class eegprep.extension_catalog_validation.CatalogValidationOptions(allow_private=False, check_installed=False, check_import=False, current_eegprep_version=None, version_provider=<function version>, entry_points_provider=<function entry_points>)

Bases: object

Validation switches for local and future catalog-CI checks.

Parameters:
  • allow_private (bool)

  • check_installed (bool)

  • check_import (bool)

  • current_eegprep_version (str | None)

  • version_provider (Any)

  • entry_points_provider (Any)

allow_private: bool = False
check_installed: bool = False
check_import: bool = False
current_eegprep_version: str | None = None
version_provider()

Get the version string for the named package.

Parameters:

distribution_name – The name of the distribution package to query.

Returns:

The version string for the package as defined in the package’s “Version” metadata key.

entry_points_provider()

Return EntryPoint objects for all installed packages.

Pass selection parameters (group or name) to filter the result to entry points matching those properties (see EntryPoints.select()).

For compatibility, returns SelectableGroups object unless selection parameters are supplied. In the future, this function will return EntryPoints instead of SelectableGroups even when no selection parameters are supplied.

For maximum future compatibility, pass selection parameters or invoke .select with parameters on the result.

Returns:

EntryPoints or SelectableGroups for all installed packages.

Return type:

EntryPoints | SelectableGroups

class eegprep.extension_catalog_validation.CatalogValidationReport(errors=<factory>, warnings=<factory>)

Bases: object

Catalog validation result with blocking errors and non-blocking warnings.

Parameters:
errors: tuple[CatalogValidationIssue, ...]
warnings: tuple[CatalogValidationIssue, ...]
property ok: bool

Return whether the catalog metadata has no blocking errors.

format()

Return a readable validation summary.

Return type:

str

eegprep.extension_catalog_validation.load_catalog_entries(path)

Load catalog entries from a JSON file or a directory of JSON files.

Parameters:

path (str | Path)

Return type:

tuple[dict[str, Any], …]

eegprep.extension_catalog_validation.main(argv=None)

Run the catalog validator command-line interface.

Parameters:

argv (list[str] | None)

Return type:

int

eegprep.extension_catalog_validation.validate_catalog_entries(entries, *, options=None)

Validate catalog metadata entries.

Static validation does not require an installed extension package. Set check_installed to verify distribution metadata and entry points, and check_import to import the declared entry point through the registry.

Parameters:
Return type:

CatalogValidationReport

eegprep.extension_catalog_validation.validate_catalog_file(path, *, options=None)

Validate catalog metadata loaded from path.

Parameters:
Return type:

CatalogValidationReport

Reusable assertions for EEGPrep extension authors.

class eegprep.extension_testing.ExtensionTestHarness(spec)

Bases: object

Assertion helper for extension author test suites.

Parameters:

spec (ExtensionSpec)

classmethod from_entry_point(entry_point_name, *, entry_points_provider=<function entry_points>, current_version=None, version_provider=<function version>)

Load an extension spec from the eegprep.extensions entry-point group.

Parameters:
  • entry_point_name (str)

  • entry_points_provider (Any)

  • current_version (str | None)

  • version_provider (Any)

Return type:

ExtensionTestHarness

assert_spec_valid(*, current_version=None, version_provider=<function version>, check_resources=True)

Assert that the spec passes EEGPrep registry validation.

Parameters:
  • current_version (str | None)

  • version_provider (Any)

  • check_resources (bool)

Return type:

None

assert_menus_register()

Assert that every declared menu references a declared action or pop_* function.

Return type:

None

assert_help_resources_exist()

Assert that every declared help resource is packaged and readable.

Return type:

None

assert_actions_load()

Assert that every declared action lazy target loads to a callable object.

Return type:

None

assert_pop_functions_load()

Assert that every declared pop_* lazy target loads to a callable object.

Return type:

None

assert_action_callable(action_name)

Load and return one action target, asserting that it is callable.

Parameters:

action_name (str)

Return type:

Any

assert_pop_function_callable(pop_function_name)

Load and return one pop_* target, asserting that it is callable.

Parameters:

pop_function_name (str)

Return type:

Any

assert_action_history_result(action_name, *args, **kwargs)

Call an action and assert it returns an EEGLAB-style (EEG, com) result.

Parameters:
Return type:

tuple[Any, str]

assert_pop_function_history_result(pop_function_name, *args, **kwargs)

Call a pop_* function with return_com=True and assert (EEG, com) output.

Parameters:
  • pop_function_name (str)

  • args (Any)

  • kwargs (Any)

Return type:

tuple[Any, str]

assert_all_static_contracts()

Assert static spec, menu, help, action, and pop_* loading contracts.

Return type:

None

eegprep.extension_testing.assert_extension_entry_point_loads(entry_point_name, *, entry_points_provider=<function entry_points>, current_version=None, version_provider=<function version>)

Assert that an eegprep.extensions entry point loads to a usable spec.

Parameters:
  • entry_point_name (str)

  • entry_points_provider (Any)

  • current_version (str | None)

  • version_provider (Any)

Return type:

ExtensionSpec