ConfigValidator#

class bamengine.config.validator.ConfigValidator[source]#

Bases: object

Centralized validation for simulation configuration.

All validation happens once at Simulation.init() to ensure:

  • Type correctness

  • Valid parameter ranges

  • Relationship constraints between parameters

  • Clear error messages with actionable feedback

This class is stateless and uses only static methods. All validation logic is centralized here rather than scattered across the codebase.

Examples

Validate a complete configuration:

>>> from bamengine.config import ConfigValidator
>>> cfg = {
...     "n_firms": 100,
...     "n_households": 500,
...     "h_rho": 0.1,
...     "beta": 2.5,
... }
>>> ConfigValidator.validate_config(cfg)  # No exception = valid

Validate only types:

>>> cfg = {"n_firms": 100, "h_rho": 0.1}
>>> ConfigValidator._validate_types(cfg)  # Valid
>>> cfg = {"n_firms": "100"}
>>> ConfigValidator._validate_types(cfg)
ValueError: Config parameter 'n_firms' must be int, got str

Validate only ranges:

>>> cfg = {"h_rho": 0.5}
>>> ConfigValidator._validate_ranges(cfg)  # Valid
>>> cfg = {"h_rho": 1.5}
>>> ConfigValidator._validate_ranges(cfg)
ValueError: Config parameter 'h_rho' must be <= 1.0, got 1.5

Notes

The ConfigValidator ensures validation happens once, upfront, rather than during simulation execution. This provides better error messages and avoids runtime overhead.

See also

Config

Configuration dataclass validated by this class

bamengine.simulation.Simulation.init

Entry point that triggers validation

VALID_LOG_LEVELS = {'CRITICAL', 'DEBUG', 'ERROR', 'INFO', 'TRACE', 'WARNING'}#
static validate_config(cfg)[source]#

Validate all configuration parameters.

This is the main entry point for configuration validation. It runs all validation checks in sequence: types, ranges, relationships, and logging.

Parameters:

cfg (dict) – Configuration dictionary to validate. Should contain simulation parameters like n_firms, n_households, h_rho, etc.

Raises:

ValueError – If any validation check fails (type error, out of range, invalid pipeline/logging config).

Examples

Valid configuration passes silently:

>>> from bamengine.config import ConfigValidator
>>> cfg = {"n_firms": 100, "h_rho": 0.1, "beta": 2.5}
>>> ConfigValidator.validate_config(cfg)  # No exception

Invalid type raises ValueError:

>>> cfg = {"n_firms": "100"}
>>> ConfigValidator.validate_config(cfg)
ValueError: Config parameter 'n_firms' must be int, got str

Out of range raises ValueError:

>>> cfg = {"h_rho": 1.5}
>>> ConfigValidator.validate_config(cfg)
ValueError: Config parameter 'h_rho' must be <= 1.0, got 1.5

Notes

This method is called by Simulation.init() before any initialization occurs, ensuring fail-fast behavior with clear error messages.

See also

_validate_types

Type checking for configuration parameters

_validate_ranges

Range validation for configuration parameters

_validate_relationships

Cross-parameter constraint validation

_validate_logging

Logging configuration validation

static validate_pipeline_path(pipeline_path)[source]#

Validate pipeline path exists and is readable.

Checks that the given path points to an existing, readable file. Issues warning if file doesn’t have .yml or .yaml extension.

Parameters:

pipeline_path (str) – Path to pipeline YAML file.

Raises:

ValueError – If path does not exist or is not a file.

Warns:

UserWarning – If file doesn’t have .yml or .yaml extension.

Examples

Valid path passes silently:

>>> from bamengine.config import ConfigValidator
>>> import tempfile
>>> from pathlib import Path
>>> with tempfile.NamedTemporaryFile(suffix=".yml", delete=False) as f:
...     f.write(b"events: []")
...     path = f.name
>>> ConfigValidator.validate_pipeline_path(path)
>>> Path(path).unlink()  # cleanup

Non-existent path raises ValueError:

>>> ConfigValidator.validate_pipeline_path("/nonexistent.yml")
ValueError: Pipeline path '/nonexistent.yml' does not exist

Notes

This method only checks path validity, not YAML structure or event names. Use validate_pipeline_yaml() for full validation.

See also

validate_pipeline_yaml

Validate pipeline YAML structure and events

static validate_pipeline_yaml(yaml_path, params=None)[source]#

Validate pipeline YAML file structure and event references.

Checks that:

  1. YAML is valid and has ‘events’ key

  2. All event names exist in the registry

  3. All parameter placeholders can be substituted

  4. Event spec syntax is valid (repeat, interleave)

Parameters:
  • yaml_path (str) – Path to pipeline YAML file.

  • params (dict[str, int], optional) – Parameters available for substitution (e.g., {“max_M”: 4}). If None, no parameter substitution is performed.

Raises:

ValueError – If YAML structure is invalid, references unknown events, or contains unsubstituted placeholders.

Examples

Valid pipeline YAML passes silently:

>>> from bamengine.config import ConfigValidator
>>> import tempfile
>>> from pathlib import Path
>>> yaml_content = '''
... events:
...   - firms_decide_desired_production
...   - labor_market_round x 4
... '''
>>> with tempfile.NamedTemporaryFile(
...     mode="w", suffix=".yml", delete=False
... ) as f:
...     f.write(yaml_content)
...     path = f.name
>>> ConfigValidator.validate_pipeline_yaml(path)
>>> Path(path).unlink()  # cleanup

Unknown event raises ValueError:

>>> yaml_content = '''
... events:
...   - nonexistent_event
... '''
>>> with tempfile.NamedTemporaryFile(
...     mode="w", suffix=".yml", delete=False
... ) as f:
...     f.write(yaml_content)
...     path = f.name
>>> ConfigValidator.validate_pipeline_yaml(path)
ValueError: Event 'nonexistent_event' not found in registry...
>>> Path(path).unlink()  # cleanup

Notes

This validation is called by Simulation.init() after path validation. It ensures all event names are registered before attempting to load the pipeline.

See also

validate_pipeline_path

Validate path exists

bamengine.core.pipeline.Pipeline.from_yaml

Loads validated pipeline