Skip to content

formula_rule

Module for Formula Rule class

!!! classes Formula Rule

FormulaRule (RuleBase, IMultiCellBasedRule)

Implementation for the Formula rule

Source code in rules/formula_rule.py
class FormulaRule(RuleBase, IMultiCellBasedRule):
    """Implementation for the Formula rule"""

    formula_output_name: str = "formula_result"

    def __init__(self, name: str, input_variable_names: List[str], formula: str):
        super().__init__(name, input_variable_names)
        self._formula = formula
        self._byte_code = None
        self._setup_environment()

    def validate(self, logger: ILogger) -> bool:
        try:
            byte_code = _compile_restricted(
                f"{self.formula_output_name} = {self._formula}",
                filename="<inline code>",
                mode="exec",
            )
            local_variables = dict.fromkeys(self.input_variable_names, 1.0)
            exec(byte_code, self._global_variables, local_variables)

        except (SyntaxError, NameError) as exception:
            logger.log_error(f"Could not create formula function: {exception}")
            return False

        return True

    @property
    def formula(self) -> str:
        """Multiplier property"""
        return self._formula

    def execute(self, values: Dict[str, float], logger: ILogger) -> float:
        """Calculates the formula based on the
        Args:
            values (DataArray): values to Formula
        Returns:
            float: Calculated float
        """

        if not self._byte_code:
            self._byte_code = _compile_restricted(
                f"{self.formula_output_name} = {self._formula}",
                filename="<inline code>",
                mode="exec",
            )

        local_variables = values.copy()

        try:
            exec(self._byte_code, self._global_variables, local_variables)

        except SyntaxError as exception:
            logger.log_error(f"The formula can not be executed. {exception}")

        return float(local_variables[self.formula_output_name])

    def _setup_environment(self):
        # use standard libraries that are considered safe
        self._safe_modules_dict = {
            "math": math,
            "numpy": numpy,
        }

        # Global data available in restricted code
        self._global_variables = {
            "__builtins__": {**_safe_builtins, "__import__": self._safe_import},
            **self._safe_modules_dict,
        }

        self._byte_code = None

    def _safe_import(self, name, *args, **kwargs):
        # Redefine import, to only import from safe modules
        if name not in self._safe_modules_dict:
            raise _ArgumentError(None, f"Importing {name!r} is not allowed!")
        return __import__(name, *args, **kwargs)

formula: str property readonly

Multiplier property

execute(self, values, logger)

Calculates the formula based on the

Parameters:

Name Type Description Default
values DataArray

values to Formula

required

Returns:

Type Description
float

Calculated float

Source code in rules/formula_rule.py
def execute(self, values: Dict[str, float], logger: ILogger) -> float:
    """Calculates the formula based on the
    Args:
        values (DataArray): values to Formula
    Returns:
        float: Calculated float
    """

    if not self._byte_code:
        self._byte_code = _compile_restricted(
            f"{self.formula_output_name} = {self._formula}",
            filename="<inline code>",
            mode="exec",
        )

    local_variables = values.copy()

    try:
        exec(self._byte_code, self._global_variables, local_variables)

    except SyntaxError as exception:
        logger.log_error(f"The formula can not be executed. {exception}")

    return float(local_variables[self.formula_output_name])

validate(self, logger)

Validates if the rule is valid

Returns:

Type Description
bool

wether the rule is valid

Source code in rules/formula_rule.py
def validate(self, logger: ILogger) -> bool:
    try:
        byte_code = _compile_restricted(
            f"{self.formula_output_name} = {self._formula}",
            filename="<inline code>",
            mode="exec",
        )
        local_variables = dict.fromkeys(self.input_variable_names, 1.0)
        exec(byte_code, self._global_variables, local_variables)

    except (SyntaxError, NameError) as exception:
        logger.log_error(f"Could not create formula function: {exception}")
        return False

    return True