Python How to run another Python script with arguments

eye-catch Python

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?

Sponsored links

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.

Sponsored links

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

Copied title and URL