Dynamic Hooks and Filters Extension

The Dynamic Hooks/Filters extension allows registering callbacks from YAML instead of hardcoding registrations in plugin load(app) functions.

Overview

Key behavior:

  1. Registers itself on post_argument_parsing

  2. Reads hook/filter config from YAML

  3. Validates each callback against discovery registries

  4. Validates configured parameters against the callback’s Pydantic parameter model

  5. Registers validated callbacks into Cement’s hook/filter managers

Configuration Model

Legacy fallback (still supported)

vipr:
  hooks: {}
  filters: {}

The extension aggregates hooks/filters across all vipr.<workflow>.hooks|filters sections and falls back to vipr.hooks|filters when no workflow sections are found.

Required Fields

Field

Required

Description

class

yes

Fully-qualified class path

method

yes

Method name on that class

enabled

no

Defaults to true

weight

no

Defaults to 0 (lower runs earlier)

parameters

no

Must match callback’s Pydantic parameter model

Only class + method references are accepted. Standalone functions are not supported.

Examples

Example 1: Register a built-in normalizer filter

Decorator declaration (in code):

@discover_filter('INFERENCE_PREPROCESS_PRE_FILTER', enabled_in_config=False, weight=-10)
def normalize_filter(self, data, **kwargs):
    return data

YAML activation:

vipr:
  inference:
    filters:
      INFERENCE_PREPROCESS_PRE_FILTER:
      - class: vipr.plugins.normalizers.log_normalizer.LogNormalizer
        method: normalize_filter
        enabled: true
        weight: -10

Example 2: Register a hook with validated parameters

Decorator declaration (in code):

class MarginalDistributionsParams(BaseModel):
    min_bins: int = 100

@discover_hook(
    'INFERENCE_POSTPROCESS_PRE_PRE_FILTER_HOOK',
    parameters=MarginalDistributionsParams,
    enabled_in_config=False
)
def _create_marginal_distributions(self, app, data=None, **kwargs):
    ...

YAML activation:

vipr:
  inference:
    hooks:
      INFERENCE_POSTPROCESS_PRE_PRE_FILTER_HOOK:
      - class: vipr_reflectometry.flow_models.postprocess.marginal_distributions.MarginalDistributions
        method: _create_marginal_distributions
        enabled: true
        weight: 0
        parameters:
          min_bins: 120

Example 3: Multiple callbacks with weights

vipr:
  inference:
    hooks:
      INFERENCE_POSTPROCESS_PRE_PRE_FILTER_HOOK:
      - class: vipr_reflectometry.flow_models.postprocess.basic_corner_plot.BasicCornerPlot
        method: _create_basic_corner_plot
        enabled: true
        weight: 0

      - class: vipr_reflectometry.flow_models.postprocess.cluster.clustering.hook.ClusterHook
        method: _cluster_posterior_samples
        enabled: true
        weight: 1
        parameters:
          method: gmm
          n_components: 5
          n_init: 10

Security and Validation

1. Registry validation

A callback must exist in discovered hooks or filters (@discover_hook / @discover_filter).

2. Parameter schema validation

If YAML provides parameters, the target callback must expose an attached Pydantic model via discovery decorators. Unknown or invalid fields are rejected.

3. Content validation

The extension applies pattern checks to parameter values (for example shell-injection/path-traversal/python-injection patterns).

Plugin Availability Notes

  • Internal callbacks under vipr.plugins.<name>... require the plugin to be enabled.

  • Internal plugin config format is top-level:

plugin.normalizers:
  enabled: true
  • For external packages (for example vipr_reflectometry...), ensure the package is installed and importable in the active environment.

Troubleshooting

“Callback not in registry”

The configured class + method is not discovered.
Fix: add correct @discover_hook/@discover_filter declaration or update YAML path/method.

“Parameter validation failed”

YAML parameters do not match the callback’s Pydantic parameter model.
Fix: align parameter names/types with the discovered schema.

“Could not import class.method”

Import path is wrong or package/plugin is unavailable.
Fix: verify module path and install/enable the plugin.

“Dangerous pattern in parameter”

A parameter value matched a blocked security pattern.
Fix: review and sanitize the value.

Best Practices

  1. Use class-method callbacks only.

  2. Keep callback parameters defined via Pydantic models.

  3. Use workflow-local config (vipr.inference.hooks|filters) instead of global legacy structure.

  4. Use weights intentionally and document ordering in configs.

  5. Prefer maintained example configs from plugin repositories when possible.

See Also