Before getting started, let us discuss the eval function. The eval function considers the “String” like a python expression and returns the result as an integer. It evaluates whether the given statement is a legal python statement, and if it is, it will get executed.
By using the eval module, strings can be processed easily without converting to some other format.
Let me make you understand using an example:
In the normal case:
string_value = '10 + 5'
print(string_value)
The output is 10 + 5.
By using eval:
string_value = '10 + 5'
result = eval(string_value)
print(result)
The output is 15, i.e., the string has been processed, and the output we received is an integer.
The eval module is also used to process expressions that do not have an explicit value, as in the code below
a = 10
b = 5
string_value = 'a + b'
result = eval(string_value)
In this case, eval searches for the variable value in the global scope and then calculates the expression.
List of variables in a dictionary can also be used, as shown in the example below.
string_value = 'a + b'
result = eval(string_value, {'a': 10, 'b': 5})
print(result)
The output will be 15. The eval function searches for the string_value variable and will assign the values of a and b directly to the string value. When we print the result we get 15.
The safe_eval module is an implementation of the built-in Python eval module with some modifications.
The codes that have been written using eval can also be written using safe_eval module:
string = '3+5'
value = safe_eval(string)
print(value)
string_value = 'a + b'
result = safe_eval(string_value, {'a': 10, 'b': 5})
print(result)
On calling safe_eval, Odoo executes python’s eval module by default. We can even change safe_eval mode by replacing it with another module, ‘exec’, which is a python built-in module.
string_value = "c = a + b"
value = {'c': 1}
print('value_before', value)
# value_before' {'c': 1}
safe_eval(string_value, {'a': 4, 'b': 7}, value, mode="exec", nocopy=True)
print('value_after', value)
# value_after' {'c': 11}
On passing the c = a + b expression into the eval module, it returns an error, c=a+b is not a proper expression for eval, some call this sort of expression as statement. If c=a+b is passed the exec module, it will not cause any error. But the exec module will not return any value, so we need to enter the third argument in safe_eval, namely the locals_dict argument, as in the above code, the value is a “value” variable, to store the calculated result. Along with that, we need to set the value of the nocopy argument to True when we call the safe_eval module with exec mode; otherwise, the value of the “value” variable will not change.
The safe_eval module blacklists some expressions, but when we execute the same expressions with eval, it returns no error. For example,
string_value = "__import__('odoo').tools.float_round(a/b,pricision)"
Passing the string_value to the eval module causes no error and will return the correct value.
eval_value = eval(my_string, {'a': 15, 'b': 2, 'pricision': 0})
On passing to safe_aval module will cause an error as shown below:
safe_eval_value = safe_eval(my_string, {'a': 15, 'b': 2, 'pricision': 0})