A backport of the Python 3 subprocess module for use on Python 2 with enhanced reliability and thread-safety.
npx @tessl/cli install tessl/pypi-subprocess32@3.5.0A backport of the Python 3 subprocess module for use on Python 2 with enhanced reliability and thread-safety. Provides the full Python 3.2 subprocess functionality plus timeout support from Python 3.3 and the run() API from Python 3.5. Includes a C extension module for reliable process handling in multi-threaded environments.
pip install subprocess32import subprocess32 as subprocessAlternative import pattern for cross-platform compatibility:
import os
import sys
if os.name == 'posix' and sys.version_info[0] < 3:
import subprocess32 as subprocess
else:
import subprocessimport subprocess32 as subprocess
# Simple command execution
result = subprocess.call(['ls', '-l'])
# Command with error checking
try:
subprocess.check_call(['ls', '/nonexistent'])
except subprocess.CalledProcessError as e:
print("Command failed with return code {}".format(e.returncode))
# Capture output
output = subprocess.check_output(['echo', 'Hello World'])
print(output.strip())
# Modern run() API (Python 3.5 style - available in subprocess32)
result = subprocess.run(['echo', 'Hello'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
print("Output: {}".format(result.stdout))
print("Return code: {}".format(result.returncode))
# Advanced process control with Popen
process = subprocess.Popen(['cat'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = process.communicate(input=b'Hello subprocess32')
print(stdout.decode())subprocess32 provides the complete Python 3.2 subprocess API plus several newer features:
Popen, call, check_call, check_output, CalledProcessError, PIPE, STDOUTtimeout parameter, raises TimeoutExpiredrun() function and CompletedProcess classDEVNULL constant for discarding outputSimple functions for common process execution patterns, offering progressively more control and error handling.
def call(*popenargs, **kwargs):
"""
Run command with arguments. Wait for command to complete, then return the return code.
Parameters:
- *popenargs: Command and arguments as sequence or string
- timeout: Maximum time to wait in seconds (raises TimeoutExpired if exceeded)
- **kwargs: Additional arguments passed to Popen constructor
Returns:
int: Process return code (0 for success, non-zero for failure)
"""
def check_call(*popenargs, **kwargs):
"""
Run command with arguments. Wait for command to complete.
If return code is zero, return normally. Otherwise raise CalledProcessError.
Parameters:
- *popenargs: Command and arguments as sequence or string
- timeout: Maximum time to wait in seconds (raises TimeoutExpired if exceeded)
- **kwargs: Additional arguments passed to Popen constructor
Returns:
None (raises CalledProcessError on non-zero exit)
Raises:
CalledProcessError: If command returns non-zero exit code
TimeoutExpired: If timeout is exceeded
"""
def check_output(*popenargs, **kwargs):
"""
Run command with arguments and return its output.
If return code is zero, return stdout. Otherwise raise CalledProcessError.
Parameters:
- *popenargs: Command and arguments as sequence or string
- timeout: Maximum time to wait in seconds (raises TimeoutExpired if exceeded)
- **kwargs: Additional arguments passed to Popen constructor (stdout will be overridden)
Note: The stdout argument is not allowed as it is used internally.
Returns:
bytes: Command's stdout output as byte string
Raises:
CalledProcessError: If command returns non-zero exit code
TimeoutExpired: If timeout is exceeded
"""
def run(*popenargs, **kwargs):
"""
Run command with arguments and return a CompletedProcess instance.
Modern high-level interface for subprocess execution.
Parameters:
- *popenargs: Command and arguments as sequence or string
- input: String or bytes to send to subprocess stdin (cannot be used with stdin argument)
- timeout: Maximum time to wait in seconds (raises TimeoutExpired if exceeded)
- check: If True, raise CalledProcessError on non-zero exit code
- **kwargs: Additional arguments passed to Popen constructor
Note: If input is provided, stdin argument cannot be used as it will be set to PIPE internally.
Returns:
CompletedProcess: Object containing args, returncode, stdout, stderr
Raises:
CalledProcessError: If check=True and command returns non-zero exit code
TimeoutExpired: If timeout is exceeded
"""Advanced process creation and management with full control over streams, environment, and execution.
class Popen(object):
"""
Execute a child program in a new process with flexible stream handling.
Parameters:
- args: Command and arguments as sequence or string
- bufsize: Buffer size for subprocess streams (0=unbuffered, 1=line buffered, >1=buffer size)
- executable: Replacement program to execute instead of args[0]
- stdin: Standard input specification (None, PIPE, DEVNULL, file descriptor, or file object)
- stdout: Standard output specification (None, PIPE, DEVNULL, STDOUT, file descriptor, or file object)
- stderr: Standard error specification (None, PIPE, DEVNULL, STDOUT, file descriptor, or file object)
- preexec_fn: Function to call in child process before exec (POSIX only)
- close_fds: Whether to close file descriptors before exec (default True on POSIX)
- shell: Whether to execute through shell (allows shell features but security risk)
- cwd: Working directory for child process
- env: Environment variables for child process (dict or None for inherit)
- universal_newlines: Whether to open streams in text mode with universal newlines
- startupinfo: Windows-specific startup information (Windows only)
- creationflags: Windows-specific process creation flags (Windows only)
- restore_signals: Whether to restore signals to default handlers before exec (POSIX only, default True)
- start_new_session: Whether to start subprocess in new session (POSIX only, default False)
- pass_fds: Sequence of file descriptors to keep open between parent and child (POSIX only)
Attributes:
- stdin: Standard input stream (if stdin=PIPE)
- stdout: Standard output stream (if stdout=PIPE)
- stderr: Standard error stream (if stderr=PIPE)
- pid: Process ID of child process
- returncode: Return code of process (None if not terminated)
"""
def __init__(self, args, bufsize=0, executable=None, stdin=None, stdout=None,
stderr=None, preexec_fn=None, close_fds=True, shell=False, cwd=None,
env=None, universal_newlines=False, startupinfo=None, creationflags=0,
restore_signals=True, start_new_session=False, pass_fds=()):
pass
def poll(self):
"""
Check if child process has terminated.
Returns:
int or None: Return code if terminated, None if still running
"""
def wait(self, timeout=None):
"""
Wait for child process to terminate.
Parameters:
- timeout: Maximum time to wait in seconds (None for no timeout)
Returns:
int: Process return code
Raises:
TimeoutExpired: If timeout is exceeded
"""
def communicate(self, input=None, timeout=None):
"""
Interact with process: send data to stdin, read data from stdout/stderr.
Parameters:
- input: Data to send to stdin (bytes or string if universal_newlines=True)
- timeout: Maximum time to wait in seconds (None for no timeout)
Returns:
tuple: (stdout_data, stderr_data) as bytes or strings
Raises:
TimeoutExpired: If timeout is exceeded
"""
def send_signal(self, sig):
"""
Send signal to the process.
Parameters:
- sig: Signal number to send
"""
def terminate(self):
"""
Terminate the process with SIGTERM (graceful shutdown).
"""
def kill(self):
"""
Kill the process with SIGKILL (immediate termination).
"""
def __enter__(self):
"""Context manager entry."""
return self
def __exit__(self, type, value, traceback):
"""Context manager exit with automatic cleanup."""
passContainer for process execution results returned by the run() function.
class CompletedProcess(object):
"""
A process that has finished running, returned by run().
Attributes:
- args: The list or str args passed to run()
- returncode: The exit code of the process (negative for signals)
- stdout: The standard output (None if not captured)
- stderr: The standard error (None if not captured)
"""
def __init__(self, args, returncode, stdout=None, stderr=None):
pass
def check_returncode(self):
"""
Raise CalledProcessError if the exit code is non-zero.
Raises:
CalledProcessError: If returncode is non-zero
"""Comprehensive error handling for process execution failures and timeouts.
class SubprocessError(Exception):
"""
Base class for subprocess-related exceptions.
"""
class CalledProcessError(SubprocessError):
"""
Raised when a process run with check_call() or check_output() returns non-zero exit status.
Attributes:
- cmd: Command that was executed
- returncode: Non-zero exit status that caused the error
- output: Output from stdout (if captured) - alias for stdout
- stderr: Output from stderr (if captured)
- stdout: Output from stdout (if captured) - alias for output
"""
def __init__(self, returncode, cmd, output=None, stderr=None):
pass
class TimeoutExpired(SubprocessError):
"""
Raised when the timeout expires while waiting for a child process.
Attributes:
- cmd: Command that was executed
- timeout: Timeout value in seconds that was exceeded
- output: Output from stdout (if captured) - alias for stdout
- stderr: Output from stderr (if captured)
- stdout: Output from stdout (if captured) - alias for output
"""
def __init__(self, cmd, timeout, output=None, stderr=None):
passSpecial values for controlling subprocess stream handling and behavior.
# Stream redirection constants (always available)
PIPE = -1 # Create a pipe to the subprocess
STDOUT = -2 # Redirect stderr to stdout
DEVNULL = -3 # Redirect to os.devnull (discard output)The following constants are only available when running on Windows platforms:
# Windows-specific constants (Windows only)
CREATE_NEW_CONSOLE = 16 # Create new console window
CREATE_NEW_PROCESS_GROUP = 512 # Create new process group
STD_INPUT_HANDLE = -10 # Standard input handle
STD_OUTPUT_HANDLE = -11 # Standard output handle
STD_ERROR_HANDLE = -12 # Standard error handle
SW_HIDE = 0 # Hide window
STARTF_USESTDHANDLES = 256 # Use provided standard handles
STARTF_USESHOWWINDOW = 1 # Use provided window show stateHelper functions for command-line processing and compatibility.
def list2cmdline(seq):
"""
Translate a sequence of arguments into a command line string using
the same rules as the MS C runtime.
Parameters:
- seq: Sequence of command line arguments
Returns:
str: Command line string with proper quoting and escaping
"""import subprocess32 as subprocess
try:
# Command with timeout
result = subprocess.run(['sleep', '10'], timeout=5)
except subprocess.TimeoutExpired as e:
print("Command '{}' timed out after {} seconds".format(e.cmd, e.timeout))
# Timeout with Popen
process = subprocess.Popen(['long_running_command'])
try:
stdout, stderr = process.communicate(timeout=30)
except subprocess.TimeoutExpired:
process.kill()
stdout, stderr = process.communicate()
print("Process was killed due to timeout")import subprocess32 as subprocess
try:
result = subprocess.run(['false'], check=True)
except subprocess.CalledProcessError as e:
print("Command failed with return code {}".format(e.returncode))
if e.stdout:
print("stdout: {}".format(e.stdout))
if e.stderr:
print("stderr: {}".format(e.stderr))import subprocess32 as subprocess
# Complex process with custom environment
env = os.environ.copy()
env['CUSTOM_VAR'] = 'value'
with subprocess.Popen(['command'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=env,
cwd='/tmp') as process:
stdout, stderr = process.communicate(input=b'input data')
if process.returncode != 0:
print("Process failed: {}".format(stderr.decode()))
else:
print("Process succeeded: {}".format(stdout.decode()))subprocess32 includes a C extension module that provides thread-safe process creation, addressing critical concurrency issues in Python 2's original subprocess module. This makes it safe to use in multi-threaded applications where the standard library subprocess module would be unreliable.
subprocess32 is designed as a drop-in replacement:
# Before
import subprocess
# After
import subprocess32 as subprocessAll existing code using the subprocess module should work unchanged with subprocess32, while gaining the benefits of Python 3's improvements and thread-safety enhancements.