Skip to content

Perform calculations

find_formulas(dictionary)

finds all formulas in a nested dictionary

Parameters:

Name Type Description Default
dictionary dict[str, Any]

config dictionary

required

Returns:

Type Description
dict[tuple[str, ...], str]

dict[tuple[str, ...], str]: dictionary of formulas. Keys are a tuple of keys to access the value in the tree

Source code in configcalc/perform_calcs.py
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
def find_formulas(dictionary: dict[str, Any]) -> dict[tuple[str, ...], str]:
    """finds all formulas in a nested dictionary

    Args:
        dictionary (dict[str, Any]): config dictionary

    Returns:
        dict[tuple[str, ...], str]: dictionary of formulas. Keys are a tuple of keys to access the value in the tree
    """
    formulas = {}
    for key, value in dictionary.items():
        if isinstance(value, str) and value.startswith("="):
            formulas[(key,)] = value
        elif isinstance(value, dict):
            nested_dict = find_formulas(value)
            for nested_key, nested_value in nested_dict.items():
                formulas[(key, *nested_key)] = nested_value
    return formulas

find_var_ref_indices(parsed_lists)

find positions of var values in parsed formulas from the parser as a list of indices of all variables

Parameters:

Name Type Description Default
parsed_lists list[Any]

parsed formula

required

Returns:

Type Description
list[list[int]]

list[list[int]]: description

Source code in configcalc/perform_calcs.py
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
def find_var_ref_indices(parsed_lists: list[Any]) -> list[list[int]]:
    """find positions of var values in parsed formulas from the parser as a list of indices of all variables

    Args:
        parsed_lists (list[Any]): parsed formula

    Returns:
        list[list[int]]: _description_
    """
    """find positions as a list of indices of all variables in parsed lists from the parser"""
    base_elements_indices = []
    for i, element in enumerate(parsed_lists):
        # we have a var name
        if (
            isinstance(element, list)
            and isinstance(element[0], str)
            and element[0] not in MATH_FUNCTIONS
        ):
            # base_element = element[0]
            # print(element)
            base_elements_indices.append([i])
        elif isinstance(element, list):
            base_elements_indices.extend(
                [[i, *inner_indices] for inner_indices in find_var_ref_indices(element)]
            )
    return base_elements_indices

get_value_in_data(data, list_identifier)

get the value of a variable from its list identifier

Source code in configcalc/perform_calcs.py
80
81
82
83
84
85
def get_value_in_data(data: dict[str, Any], list_identifier: list[str | int]) -> Any:
    """get the value of a variable from its list identifier"""
    item = data
    for i_or_key in list_identifier:
        item = item[i_or_key]
    return item

perform_calculations(config, context_variables=None, number_type=NumberType.FLOAT)

resolves all possible calculations in config dictionary

Parameters:

Name Type Description Default
config dict[str, Any]

config dictionary as given by read_config_file

required
context_variables dict[str, Any] | None

additional variable values to use for calculations. Defaults to None.

None
number_type NumberType

number type to use (e.g. NumberType.DECIMAL). Defaults to FLOAT.

FLOAT

Returns:

Type Description
dict[str, Any]

dict[str, Any]: config dictionary with all calculations resolved

Source code in configcalc/perform_calcs.py
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
def perform_calculations(
    config: dict[str, Any],
    context_variables: dict[str, Any] | None = None,
    number_type: NumberType = NumberType.FLOAT,
) -> dict[str, Any]:
    """resolves all possible calculations in config dictionary

    Args:
        config (dict[str, Any]): config dictionary as given by read_config_file
        context_variables (dict[str, Any] | None, optional): additional variable values to use for calculations. Defaults to None.
        number_type (NumberType, optional): number type to use (e.g. NumberType.DECIMAL). Defaults to FLOAT.

    Returns:
        dict[str, Any]: config dictionary with all calculations resolved
    """

    if context_variables is None:
        context_variables = {}
    number_parser_element, number_parser_function = number_formatters[number_type]
    operand_parser = build_operand_parser(number_parser=number_parser_element)
    parse_any_value = functools.partial(_parse_any_value, operand_parser=operand_parser)
    formulas = find_formulas(config)
    for formula_position, formula in list(formulas.items()):
        parsed_formula = operand_parser.parse_string(formula).asList()
        parsed_formula_w_value = replace_vars_by_values(
            parsed_formula=parsed_formula,
            data=config,
            formula_position=list(formula_position),
            context_variables=context_variables,
            parse_any_value=parse_any_value,
        )
        calculated_value = calculate_formula_w_value(
            parsed_formula_w_value, parse_float=number_parser_function
        )
        set_deep(
            nested_list=config, indices=list(formula_position), value=calculated_value
        )
    return config