haniwers.v1.config.overrider#
Configuration override and validation helper.
This module provides a unified interface for applying CLI option overrides to configuration objects with automatic validation. It eliminates the need for repetitive _apply_overrides() functions and manual validation in each command file.
Usage Example: from haniwers.v1.config.overrider import ConfigOverrider
# Load base configuration
loader = ConfigLoader(config_path)
cfg = loader.config
# Apply CLI overrides with automatic validation
overrider = ConfigOverrider(cfg)
overrider.apply_device_overrides(
port=port,
baudrate=baudrate,
timeout=timeout,
label=device_label,
)
overrider.apply_sampler_overrides(
workspace=workspace,
filename_prefix=filename_prefix,
events_per_file=events_per_file,
)
# Validate all configurations at once
overrider.validate("device", "sampler")
Benefits: - Single responsibility: Override and validate in one place - DRY principle: No duplicate override logic across commands - Type safety: Leverages Pydantic validation - Clear error messages: Unified error handling - Maintainability: Changes to override logic only need to be made once
Module Contents#
Classes#
Apply CLI option overrides to configuration with automatic validation. |
API#
- class haniwers.v1.config.overrider.ConfigOverrider(config: haniwers.v1.config.model.HaniwersConfig)#
Apply CLI option overrides to configuration with automatic validation.
This class centralizes the logic for applying CLI option overrides to configuration objects. It provides type-safe overriding with automatic Pydantic validation, eliminating repetitive code in command handlers.
Attributes: config: The HaniwersConfig object to override _override_log: List of applied overrides for debugging
Example: >>> loader = ConfigLoader(“config.toml”) >>> cfg = loader.config >>> overrider = ConfigOverrider(cfg) >>> overrider.apply_device_overrides(port=“/dev/ttyUSB0”) >>> overrider.validate(“device”, “sampler”)
Initialization
Initialize ConfigOverrider.
Args: config: HaniwersConfig object to apply overrides to
- _apply_override(config_obj: Any, key: str, value: Any, section: str) None#
Apply a single override if value is not None.
Args: config_obj: Configuration object (e.g., cfg.device) key: Attribute name to override value: New value (override only if not None) section: Section name for logging (e.g., “device”, “sampler”)
- apply_device_overrides(port: Optional[str] = None, baudrate: Optional[int] = None, timeout: Optional[float] = None, label: Optional[str] = None) None#
Apply CLI overrides to DeviceConfig.
Args: port: Serial port path (e.g., /dev/ttyUSB0) baudrate: Serial communication speed (e.g., 9600) timeout: Serial read timeout in seconds label: Device configuration label
- apply_sampler_overrides(workspace: Optional[pathlib.Path] = None, filename_prefix: Optional[str] = None, filename_suffix: Optional[str] = None, events_per_file: Optional[int] = None, number_of_files: Optional[int] = None, duration: Optional[float] = None, stream_mode: Optional[bool] = None, mode: Optional[str] = None, label: Optional[str] = None) None#
Apply CLI overrides to SamplerConfig.
Args: workspace: Output directory for data files filename_prefix: Output filename prefix filename_suffix: Output filename suffix events_per_file: Number of events per output file number_of_files: Maximum number of output files duration: Measurement duration in seconds stream_mode: Enable continuous streaming mode: Data collection mode (count_based or time_based) label: Sampler configuration label
- apply_mocker_overrides(label: Optional[str] = None, csv_path: Optional[pathlib.Path] = None, shuffle: Optional[bool] = None, speed: Optional[float] = None, jitter: Optional[float] = None, loop: Optional[bool] = None) None#
Apply CLI overrides to MockerConfig.
Args: label: Mocker configuration label csv_path: CSV file to replay shuffle: Randomize event order speed: Playback speed multiplier jitter: Timing jitter for random generation loop: Repeat CSV data when reaching end
- apply_sensor_overrides(thresholds: Optional[dict[int, int]] = None, centers: Optional[dict[int, int]] = None, center: Optional[int] = None, nsteps: Optional[int] = None, step_size: Optional[int] = None, threshold: Optional[int] = None) None#
Apply CLI overrides to SensorConfig objects.
This method supports multiple override modes:
Selective threshold override: Use thresholds dict to set both threshold and center values for specific channels (e.g., {1: 280, 3: 320})
Selective center override: Use centers dict to set only center values for specific channels (e.g., {1: 280, 2: 320})
Global parameter override: Apply nsteps/step_size/threshold to all sensors
Global center override: Apply same center value to all sensors
Args: thresholds: Dict mapping channel ID to threshold value. Sets both threshold and center to the same value. Example: {1: 280, 2: 320, 3: 300} Only specified channels will be updated centers: Dict mapping channel ID to center value. Sets only the center value for scanning. Example: {1: 300, 2: 350} Only specified channels will be updated center: Center threshold value for all sensors Overrides centers dict if both specified nsteps: Number of steps from center (applied to all sensors) step_size: Step size between measurements (applied to all sensors) threshold: Current detection threshold (applied to all sensors)
Raises: KeyError: If channel ID in thresholds/centers dict doesn’t exist in config
Example: >>> # Override specific channels with threshold and center >>> overrider.apply_sensor_overrides( … thresholds={1: 280, 3: 320}, … nsteps=10, … step_size=1 … ) >>> >>> # Override specific channels with only center values >>> overrider.apply_sensor_overrides( … centers={1: 300, 2: 350}, … nsteps=5 … ) >>> >>> # Override all channels with same center value >>> overrider.apply_sensor_overrides( … center=300, … nsteps=5 … ) >>> >>> # Set threshold for all channels >>> overrider.apply_sensor_overrides( … threshold=500 … )
- validate_device() haniwers.v1.config.model.DeviceConfig#
Validate DeviceConfig after overrides.
Returns: Validated DeviceConfig object
Raises: ValidationError: If validation fails
- validate_sampler() haniwers.v1.config.model.SamplerConfig#
Validate SamplerConfig after overrides.
Returns: Validated SamplerConfig object
Raises: ValidationError: If validation fails
- validate_mocker() haniwers.v1.config.model.MockerConfig#
Validate MockerConfig after overrides.
Returns: Validated MockerConfig object
Raises: ValidationError: If validation fails
- validate_sensors() dict[str, haniwers.v1.config.model.SensorConfig]#
Validate all SensorConfig objects after overrides.
Validates each sensor in the sensors dictionary (typically ch1, ch2, ch3).
Returns: Dictionary of validated SensorConfig objects with same keys
Raises: ValidationError: If any sensor validation fails
- validate(*sections: str) None#
Validate specified configuration sections.
This flexible method allows commands to validate only the sections they actually use, avoiding unnecessary validation errors.
Args: *sections: Section names to validate Valid values: “device”, “sampler”, “mocker”, “sensors” If no sections specified, validates all sections.
Raises: ValidationError: If any validation fails ValueError: If invalid section name provided
Example: >>> # Validate only device and sampler >>> overrider.validate(“device”, “sampler”) >>> >>> # Validate sensors for threshold scanning >>> overrider.validate(“device”, “sensors”) >>> >>> # Validate all sections >>> overrider.validate()
- validate_all() None#
Validate all configuration sections.
Validates device, sampler, mocker, and sensor configurations. This is a convenience method equivalent to validate() with no args.
Raises: ValidationError: If any validation fails
- get_override_summary() str#
Get a summary of all applied overrides.
Returns: Formatted string showing all overrides for debugging
Example: >>> overrider.get_override_summary() ‘Overrides applied:\n device.port = /dev/ttyUSB0\n sampler.workspace = data/’