How to call an imported module knowing its name as a string?
Question:
I am writing an application that should test the solution of many students.
I have structure like this
app/
students/
A/
lab1/
solution.py
lab2
solution.py
B/
lab1/
solution.py
C/
test.py
I want to import the solution file in the testing module and run the main method.
I know there is __import__
function that returns a module object, but I don’t know how to call main method.
My code:
import os
def get_student_names():
return os.listdir('students')
def test(name, lab):
if lab not in os.listdir('/'.join(['students',name])):
return f"{lab} not found"
if 'solution.py' not in os.listdir('/'.join(['students',name,lab])):
return "solution file not found"
module = __import__('.'.join(['students',name,lab,'solution']))
# module.name.lab.solution.main()
def main():
student_names = get_student_names()
for student in student_names:
result = test(student, "lab1")
I want to call module.name.lab.solution.main()
but the module
is students
. How to switch to solution
submodule?
Answers:
Your most immediate problem is that you aren’t returning anything from test
so, result
will always be None
. The second and most important problem you have is that you don’t really have any modules. You actually have a bunch of random folders with arbitrary python scripts in them. This means __import__
is going to be quite unfriendly to you.
if we run this line
__import__('students.A.lab1.solution').main()
we get back this error:
AttributeError: module 'students' has no attribute 'main'
students
? We’re supposed to be in solution
! That’s a problem. There is a way to do this without worrying about converting and maintaining your individual folders as actual modules.
First, students must call main
in their solution.
ex:
def main():
print('hello, world')
main()
Secondly, run their script. If the command fails it is going to tell you the script doesn’t exist and move on to the next student.
import os
#change this to however you call python
PY = 'python3'
#lab format strings
LAB1 = '{} "students/{}/lab1/solution.py"'
LAB2 = '{} "students/{}/lab2/solution.py"'
def main(lab:str) -> None:
for student in os.listdir('students'):
os.system(lab.format(PY, student))
main(LAB1)
As highlighted by @KarlKnetchel, the above code has all of the same vulnerabilities as your original concept. This is NOT safe. You should definitely consider running this in a sandbox, if you use it.
I am writing an application that should test the solution of many students.
I have structure like this
app/
students/
A/
lab1/
solution.py
lab2
solution.py
B/
lab1/
solution.py
C/
test.py
I want to import the solution file in the testing module and run the main method.
I know there is __import__
function that returns a module object, but I don’t know how to call main method.
My code:
import os
def get_student_names():
return os.listdir('students')
def test(name, lab):
if lab not in os.listdir('/'.join(['students',name])):
return f"{lab} not found"
if 'solution.py' not in os.listdir('/'.join(['students',name,lab])):
return "solution file not found"
module = __import__('.'.join(['students',name,lab,'solution']))
# module.name.lab.solution.main()
def main():
student_names = get_student_names()
for student in student_names:
result = test(student, "lab1")
I want to call module.name.lab.solution.main()
but the module
is students
. How to switch to solution
submodule?
Your most immediate problem is that you aren’t returning anything from test
so, result
will always be None
. The second and most important problem you have is that you don’t really have any modules. You actually have a bunch of random folders with arbitrary python scripts in them. This means __import__
is going to be quite unfriendly to you.
if we run this line
__import__('students.A.lab1.solution').main()
we get back this error:
AttributeError: module 'students' has no attribute 'main'
students
? We’re supposed to be in solution
! That’s a problem. There is a way to do this without worrying about converting and maintaining your individual folders as actual modules.
First, students must call main
in their solution.
ex:
def main():
print('hello, world')
main()
Secondly, run their script. If the command fails it is going to tell you the script doesn’t exist and move on to the next student.
import os
#change this to however you call python
PY = 'python3'
#lab format strings
LAB1 = '{} "students/{}/lab1/solution.py"'
LAB2 = '{} "students/{}/lab2/solution.py"'
def main(lab:str) -> None:
for student in os.listdir('students'):
os.system(lab.format(PY, student))
main(LAB1)
As highlighted by @KarlKnetchel, the above code has all of the same vulnerabilities as your original concept. This is NOT safe. You should definitely consider running this in a sandbox, if you use it.