Any instance of a computer program that is being executed is referred to as a process. Thus, when you open your favorite application, open the command line interface or execute a Python script, you are literally initiating a process.
Processes can themselves initiate other processes. When this happens, the newly started process is referred to as a subprocess or a child process. The original process that initiated the creation of the child process is known as the "parent process." . This relationship leads to a hierarchical structure where the child process can also start other processes and so on.
In this article, we will explore the process of initiating external programs or applications from within a Python program.
The subprocess module
The subprocess
module in the standard library provides the necessary tools for initiating external processes from within a Python program. It makes it possible to run commands programmatically like you would from the command line interface.
To use the functions defined in the subprocess
module, we first need to import the module in our program, as in:
import subprocess
The most basic tool defined in the module is the subprocess.run()
function. Before we look deeper on how the function works, let us first look at a simple example:
Running the above program is just a programmatic way of running the python --version
command from the commandline/shell.
The subprocess.run()
function has the following syntax:
subprocess.run(*popenargs, input=None, capture_output=False, timeout=None, check=False, **kwargs)
popenargs |
An iterable such as a list containing the commands to be executed as you would type them in the commandline. |
input |
Data to be sent to the process's standard input. |
capture_output |
If True , the standard output and standard error of the executed process will be captured and returned. |
check |
If True , a CalledProcessError exception will be raised if the process exits with a non-zero return code |
**kwargs |
Additional keyword arguments that can be passed to modify the behavior of the function. |
The subprocess
after being executed returns three important values:
-
returncode:
- An integer representing the exit code of the process. A value of 0 usually indicates successful execution, while non-zero values typically signify an error or an abnormal termination.
-
stdout:
- This attribute contains the standard output of the process as a byte sequence. If you use
capture_output=True
in thesubprocess.run()
call, the captured standard output will be available in this attribute. You can settext = True
to interpret the captured standard output as a standard string rather than a byte sequence
- This attribute contains the standard output of the process as a byte sequence. If you use
-
stderr:
- This attribute contains the standard error message raised by the
subprocess
, if any. Similar tostdout
, it is populated only whencapture_output=True
.
- This attribute contains the standard error message raised by the
stdout: pip 23.3.2 from C:\Users\John\AppData\Local\Programs\Python\Python311\Lib\site-packages\pip (python 3.11)
returncode: 0
stderr:
Run shell commands as a string
The shell
argument in the subprocess.run()
function determines whether the command should be run in a shell. When set to True
, the command is run through the system shell (e.g., /bin/sh
on Unix-like systems, or cmd.exe
on Windows).
The shell argument allows commands to be run as a string, similar to how you would run them directly on the shell.
python: C:\Users\John\AppData\Local\Programs\Python\Python311\python.exe
pip: C:\Users\John\AppData\Local\Programs\Python\Python311\Scripts\pip.exe
In the above example, we called the subprocess.run()
function with the where
command which checks the absolute path to the executable of a program given as the argument.
Raising Errors
By default, errors raised by a subprocess
are not propagated to the calling program. However we can set the check
parameter to True
in the subprocess.run()
function to make it raise a CalledProcessError
if the subprocess returns a non-zero exit code, indicating an error.
Sending input values when calling a subprocess
Input values can be passed to the called subprocess
as additional parameters to the popenargs
argument. For example, consider if we want to call Python as a subprocess
with a script which expects arguments. We can pass the arguments, then access them from the called subprocess
using the sys.argv
list.
['foo.py', '10', '20']
10 + 20 = 30
More advanced examples
Create a virtual environment
CompletedProcess(args='python -m venv venv', returncode=0)
If you execute the above snippet, a new virtual environment with the name virtualenv
will be created in the working directory.
Run pip programmatically
We can run pip as a subprocess
to manage modules and packages programmatically. This is especially useful for automating installations and other package management tasks.
Collecting flask
Obtaining dependency information for flask from https://files.pythonhosted.org/packages/bd/0e/63738e88e981ae57c23bad6c499898314a1110a4141f77d7bd929b552fb4/flask-3.0.1-py3-none-any.whl.metadata.......
.......
Downloading MarkupSafe-2.1.4-cp311-cp311-win_amd64.whl (17 kB)
Installing collected packages: MarkupSafe, itsdangerous, colorama, blinker, Werkzeug, Jinja2, click, flask
Successfully installed Jinja2-3.1.3 MarkupSafe-2.1.4 Werkzeug-3.0.1 blinker-1.7.0 click-8.1.7 colorama-0.4.6 flask-3.0.1 itsdangerous-2.1.2
In the above example, we have run pip as a subprocess
to install the flask
package programmatically. This is the equivalent of running the pip install flask
command from the commandline.
package Version
------------ -------
blinker 1.7.0
click 8.1.7
colorama 0.4.6
Flask 3.0.1
itsdangerous 2.1.2
Jinja2 3.1.3
MarkupSafe 2.1.4
pip 23.2.1
setuptools 65.5.0
Werkzeug 3.0.1