# How to avoid using exec() and eval() in Python

I wrote a script to execute a service on the Forestry TEP platform via its REST API. This service has certain input parameters, some of them are numerical values, other strings or files. The current workflow is:

1. There is a configuration file that has options for file and literal inputs. Each option is a dictionary, where each key is equal to one parameter of the service I want to execute. Example of such file:

file_inputs= {"cfg" : "forest_flux/FTEP_service/cfg.ini",
"parsawen" : "forest_flux/FTEP_service/parsawen.csv",
"weather" : "forestflux/data/fin_01/weather/weather_2004.csv"}
literal_inputs = {"version" : 3}

2. In the script, I read the cfg and iterate over items in these dictionaries. For each key,value pair, I use exec() to store the value in a class variable of the same name. For file inputs, I first upload the file on the platform and store the file's location on the platform in the variable.

    input_files_dict = json.loads(cfg.get("service_info", "file_inputs"))
for key, val in input_files_dict.items():
exec("self.{} = self.post_data('{}')".format(key, val))

for key, val in literal_inputs_dict.items():
exec("self.{} = '{}'".format(key, val))

3. I request service inputs and I try to match the service parameters with my class variables. I add it to a dictionary of parameters which I then send to the platform when executing the service.

    r2 = requests.get(url = url2, verify=False, allow_redirects=False, cookies=self.session_cookies)
for _input in data_inputs:
value_to_set = eval("self." + _input["id"].lower())
job_config["inputs"][_input["id"]] = [value_to_set]


This current workflow works well for me but I have strong suspicion that it is a very bad practice. I have read that using exec() and eval() is discouraged as there are security issues. However, I cannot think of a better way to achieve this functionality, i.e. to pair values in configuration with service inputs automatically. I want this script to be generic, i.e. usable for any service on the platform.

Question: How could I do this without using the problematic functions? How could using these functions be problematic in this case?

Please note that I removed a lot of code that is not related to the problem I am asking about (e.g. error handling).

• You could use ast.literal_eval but beware that "It is possible to crash the Python interpreter with a sufficiently large/complex string due to stack depth limitations in Python’s AST compiler." – Grajdeanu Alex. Jun 25 at 20:26

You can use getattr, setattr and delattr to retrieve, modify and remove attributes respectively. This avoids most potential messes eval has.
input_files_dict = json.loads(cfg.get("service_info", "file_inputs"))

• @JanPisl Yes. f'{value}' is preferred (as it is shorter) than str.format. But some modern programs still use str.format as they need to support versions of Python that f-strings are not available in. – Peilonrayz Jun 26 at 17:49