Not all Python scripts are expected to be used by another Python script. The Python code could be written without any function and all the statements might be written on the same level.
In some cases, we need to run the script to do the specific job. How can we run it from a Python script?
The called Python script
I prepared the following python script.
# main_check.py
import sys
def main():
print(f"Hello World! ({sys.argv})--- from main")
def sub():
print(f"Hello World! ({sys.argv}) --- from sub")
if __name__ == "__main__":
main()
sub()
This script is called by another Python file.
Using immport
The python script is easily called by using import.
if __name__ == "__main__":
print("--- import ---")
import main_check
# --- import ---
# Hello World! (['src/exec_another_file.py']) --- from sub
Of course, the main func is not called because the python script checks if it’s called as a main script.
Using exec
The next way is to use exec
function.
import pathlib as path
if __name__ == "__main__":
print("--- exec ---")
filepath = path.Path(__file__).parent.joinpath("main_check.py")
exec(open(filepath).read())
# --- exec ---
# Hello World! (['src/exec_another_file.py'])--- from main
# Hello World! (['src/exec_another_file.py']) --- from sub
We need to pass the file path to the script. path module should be used to get the absolute path to the script.
Once we get the absolute path, we can read the contents. It can be passed to exec function.
How to specify arguments for the called script
The Python script to be called might require some arguments. How can we specify them in this case? exec()
doesn’t have such a property.
A solution is to assign them to sys.argv
print(sys.argv) # ['src/exec_another_file.py']
sys.argv = ["arg1", "arg2"]
exec(open(filepath).read())
# Hello World! (['arg1', 'arg2'])--- from main
# Hello World! (['arg1', 'arg2']) --- from sub
print(sys.argv) # ['arg1', 'arg2']
The arguments are passed correctly but of course, the original arguments are overwritten. The original arguments need to be stored and re-assign in this case.
print(sys.argv) # ['src/exec_another_file.py']
original_argv = sys.argv
sys.argv = ["arg1", "arg2"]
exec(open(filepath).read())
# Hello World! (['arg1', 'arg2'])--- from main
# Hello World! (['arg1', 'arg2']) --- from sub
print(sys.argv) # ['arg1', 'arg2']
sys.argv = original_argv
print(sys.argv) # ['src/exec_another_file.py']
Call a Python script by subprocess
Another way is to use subprocess. We need to know the absolute path to the Python executable.
How to get the absolute path to Python executable in Python
How can we get it in Python script? Use sys.executable
for it.
print(sys.executable)
# /usr/local/bin/python
Then, we can somehow run a python script.
Capture the return code by subprocess.call
The first argument is a list. The first parameter is the path to the python executable. The second parameter is the path to the script that we want to run. Add python options to the second parameter if it’s necessary. After the file path, we can specify (maybe) as many arguments as we want.
res = subprocess.call([sys.executable, filepath, "one", "two"])
# Hello World! (['/workspaces/blogpost-python/src/main_check.py', 'one', 'two'])--- from main
# Hello World! (['/workspaces/blogpost-python/src/main_check.py', 'one', 'two']) --- from sub
print(res) # 0
The specified values are shown in the called python script. subprocess.call
returns a return code of the called python script.
Capture the return code and output by subprocess.run
The output of the called python script can’t be used in the caller python script. Use subprocess.run
if the output needs to be used in the caller script.
res = subprocess.run([sys.executable, filepath, "one", "two"],
capture_output=True, check=False)
print(res.returncode) # 0
print(res.stderr) # b''
print(res.stdout)
# b"Hello World! (['/workspaces/blogpost-python/src/main_check.py', 'one', 'two'])--- from main\n
# Hello World! (['/workspaces/blogpost-python/src/main_check.py', 'one', 'two']) --- from sub\n"
I added a new line for better reading of stdout
. print
is used in the called python script but it is not written to the console. Instead, it is stored to stdout
and the output can be checked in the caller script.
Comments