I want to safely execute some user defined code. To accomplish this, I want to use RestrictedPython to limit which modules and variables the user has access to. There are a few guidelines to the user-submitted code:
- The code can use the pandas, datetime, math, and random modules. I'm open to expanding this list if it can be done safely. Further, the code will not be allowed to import any new modules
- The code can interact with the global variable d - which will be a dictionary of pandas dataframes
- The code will set the global variable x to some variable, which we must retrieve after running the user's code.
Here is my current version:
from RestrictedPython import compile_restricted
from RestrictedPython import safe_builtins
import pandas as pd
import math
import random
import datetime
d = None
x = None
def MakeDFDict():
data1 = {"A": [1, 2, 3, 4, 5], "B": [2, 4, 6, 8, 10]}
data2 = {"C": [3, 6, 9, 12, 15], "D": [4, 8, 12, 16, 20]}
return {"Dataframe 1": pd.DataFrame(data1),
"Dataframe 2": pd.DataFrame(data2)}
def run_code_safely(code):
global d
d = MakeDFDict()
global x
x = None
globals_dict = {"d": d}
allowed_modules = {
"__builtins__": safe_builtins,
"math": math,
"random": random,
"datetime": datetime,
"pandas": pd
}
restricted_globals = {
"__builtins__": safe_builtins,
"__import__": lambda name, globals=None, locals=None, fromlist=(), level=0: __import__(name),
"getattr": lambda obj, attr: getattr(obj, attr)
}
restricted_globals.update(allowed_modules)
bytecode = RestrictedPython.compile_restricted(code, '<inline code>', 'exec')
try:
exec(bytecode, restricted_globals, globals_dict)
except Exception as e:
return f"Error occurred while running the code:\n{e}"
x = globals_dict['x']
return x
code = """
x = []
for name, df in d.items():
x.append(name, df)
"""
run_code_safely(code)
This gives the following error:
Error occurred while running the code: name '_iter_unpack_sequence_' is not defined
What am I missing here? Is ther any way to make exec yield a more explanatory error message?