Skip to content

Tools: Implement dynamic dictionary evaluation (ast_evaluator.py)

Summary:

The ASTevaluator class is a wrapper around a Python ASTeval interpreter that evaluates expressions of the form $(...) which are contained in strings nested Python objects (e.g., dictionaries, lists, sets, tuples).

The typical use case for this class is to evaluate expressions contained in the object read in from a YAML file, allowing to embed pieces of Python code inside the YAML expressions to be dynamically evaluated at run-time.

For examples look at the unit test of the ASTevaluator as well as below.

For details of the ASTeval interpreter see: https://docs.python.org/3/library/ast

Syntax:

Examples:

Here are a few snipplets to demonstrate the usage:

Simple Python Session:

>>> from scripts.tools.declarative_def_tools.ast_evaluator import ASTevaluator
>>> ast = ASTevaluator()
>>> dct = {"value": "$(sqrt(2))", "text": "$('%.2f' % value)"}
>>> processed = ast.eval(dct)
>>> processed.dump()
value = 1.4142135623730951
text = '1.41'
>>>

Import with Dynamic Parameters

Assume you have a YAML file as shown here (taken from the unit test):

defaults:
  v01_string: 'test'
  v02_bool:   True
  v03_float:  0.075
  v04_int:    17
  v05_dict:
    v06_selfref: $(v04_int)
    v07_int_div: $(v04_int // 10)
    v08_escape:  $!(blabla % 10)$
    v09_string:  $("a=%.5f" % v03_float)
    v10_forwref: $(v05_dict.v11_math)
    v11_math:    $(sqrt(4))
    v12_backref: $(v05_dict.v11_math)
    v13_string:  $(str("10"))
    v14_list:    [ $(1+2), $(17+4) ]
    v15_list:    $([ 1+2, 17+4 ])
    v16_tuple:   $(( 1, 2 ))
    v17_tuple:   $(( 1+2, "17+4" ))
    v18_string:  $("$(1+2)")
    v19_string:  $!($(1+2)
    v20_float:   $(pi)

This can be evaluated as follows:

>>> from scripts.tools.declarative_def_tools.ast_evaluator import ASTevaluator
>>> spec = yaml.safe_load("path/to/file.yaml")
>>> ast = ASTinterpreter()
>>> params = ast.eval(spec["defaults"], allow_self_ref=True)
>>> params.dump()
v01_string = 'test'
v02_bool = True
v03_float = 0.075
v04_int = 17
v05_dict.v06_selfref = 17
v05_dict.v07_int_div = 1
v05_dict.v08_escape = '$(blabla % 10)$'
v05_dict.v09_string = 'a=0.07500'
v05_dict.v10_forwref = 2.0 # or '$(sqrt(4))' if called with `try_resolve=False`
v05_dict.v11_math = 2.0
v05_dict.v12_backref = 2.0
v05_dict.v13_string = '10'
v05_dict.v14_list = [3, 21]
v05_dict.v15_list = [3, 21]
v05_dict.v16_tuple = (1, 2)
v05_dict.v17_tuple = (3, '17+4')
v05_dict.v18_string = '$(1+2)'
v05_dict.v19_string = '$(3'
v05_dict.v20_float = 3.141592653589793
>>>

By the AST evaluation call the dictionary params will get evaluated. The resulting values are denoted in the YAML code above for information.

Edited by Armin Schoisswohl

Merge request reports