I am developing a Django backend for an online course platform. The backend runs the code submitted by the student. Here is a working example for running a student code consisting of three modules:
import importlib
import sys
util_a = """
def foo_a():
print('Yes!')
"""
util_b = """
from util_a import foo_a
def foo_b():
foo_a()
"""
main = """
from util_b import foo_b
foo_b()
"""
def process_module(code, name):
module = importlib.util.module_from_spec(
importlib.util.spec_from_loader(name, loader=None))
compiled_code = compile(code, '<string>', 'exec')
exec(compiled_code, module.__dict__)
sys.modules[name] = module
for code, name in [(util_a, 'util_a'), (util_b, 'util_b'), (main, 'main')]:
process_module(code, name)
The problem is that the util modules have to be specified in the correct order (i.e. [(util_b, 'util_b'), (util_a, 'util_a'), (main, 'main')]
would not work), whereas I want to be able to only specify which module is main, and the rest should happen automatically, just like it would had the modules been real files.
So, how can I modify this code to make it work with util modules specified in any order?
P.S. I have a complicated solution using ast
to get the list of modules imported by each module, and topological sort to execute the modules in the correct order. I am looking for a simpler way.
Here is the complicated solution. The original version was generated using ChatGPT. However, I have improved and re-factored it enough to be comfortable with SO policies. Comments appreciated.