Source code for eclypse.workflow.trigger.bucket
"""Module for TriggerBucket class.
It is used to managed a set of conditions that can trigger an EclypseEvent in the
simulation workflow. It allows for a flexible configuration of triggers, including
conditions for activation and maximum trigger counts
"""
from __future__ import annotations
from typing import (
TYPE_CHECKING,
)
from eclypse.utils.constants import MAX_FLOAT
from eclypse.workflow.trigger.cascade import CascadeTrigger
if TYPE_CHECKING:
from eclypse.utils._logging import Logger
from eclypse.utils.types import TriggerCondition
from eclypse.workflow.event.event import EclypseEvent
from eclypse.workflow.trigger import Trigger
[docs]
class TriggerBucket:
"""A class to represent a bucket of triggers for an event."""
[docs]
def __init__(
self,
triggers: Trigger | list[Trigger] | None = None,
condition: TriggerCondition = "any",
max_triggers: int = int(MAX_FLOAT),
):
"""Initialize the trigger.
Args:
triggers (Trigger | list[Trigger] | None): A single trigger or
a list of triggers that can activate the event. Defaults to None.
condition (str): The condition for the triggers to fire the event. If "any",
the event fires if any trigger is active. If "all", the event fires only
if all triggers are active. Defaults to "any".
max_triggers (int | None): The maximum number of times the trigger
can be called. Defaults to `no limit`.
"""
triggers = (
(triggers if isinstance(triggers, list) else [triggers]) if triggers else []
)
self.event: EclypseEvent | None = None
self.triggers = triggers
self.condition = condition
self.max_triggers = max_triggers
self._manual_activation: int = 0
self._n_triggers: int = 0
self._n_executions: int = 0
[docs]
def prepare(self):
"""Prepare the trigger for use.
This method can be overridden in subclasses to perform any necessary
initialization before the trigger is used.
"""
for trigger in self.triggers:
trigger.prepare()
[docs]
def trigger(self, trigger_event: EclypseEvent | None = None) -> bool:
"""Check if the trigger should fire.
Returns:
bool: True if the trigger should fire, False otherwise.
"""
if self._n_triggers >= self.max_triggers:
triggerable = False
elif triggerable := self._manual_activation > 0:
self._manual_activation -= 1
else:
t_conditions = []
_triggers: list[Trigger] = []
if trigger_event:
_triggers = [t for t in self.triggers if isinstance(t, CascadeTrigger)]
else:
_triggers = [
t for t in self.triggers if not isinstance(t, CascadeTrigger)
]
for trigger in _triggers:
c = trigger.trigger(trigger_event)
t_conditions.append(c)
triggerable = (
(any(t_conditions) if self.condition == "any" else all(t_conditions))
if t_conditions
else False
)
if triggerable:
self._n_triggers += 1
return triggerable
[docs]
def reset(self):
"""Reset the trigger state."""
for trigger in self.triggers:
trigger.reset()
self._n_executions += 1
def __repr__(self) -> str:
"""Return a string representation of the trigger."""
return f"{self.__class__.__name__}"
[docs]
def logger(self) -> Logger:
"""Get the logger for the event.
Returns:
Logger: The logger for the event if it exists, otherwise None.
"""
if self.event is None:
raise ValueError("Event is not set for this trigger bucket.")
return self.event.logger