coverage-enable-subprocess
This package installs a .pth file that enables the coverage.py process_startup feature in the Python prefix/virtualenv in subsequent runs, facilitating automatic coverage measurement for subprocesses. It is currently stable and actively maintained, with version 1.0 being the latest. The release cadence is as-needed for stability and compatibility with coverage.py.
Common errors
-
No data to combine
cause This often happens when subprocesses are not actually collecting coverage data, or when `coverage combine` is run without any `.coverage` files being generated by the subprocesses. Common causes include missing `COVERAGE_PROCESS_START` env var, incorrect `.coveragerc` path, or improper subprocess termination preventing data write.fixEnsure `COVERAGE_PROCESS_START` points to a valid `.coveragerc` with `parallel = True` and that subprocesses terminate cleanly (using `terminate()` instead of `kill()`). Check if `COV_*` environment variables are correctly passed to subprocesses. -
Subprocess code shows 0% coverage
cause Despite `coverage-enable-subprocess` being installed, `coverage.py` might not be initialized in the subprocess. This typically occurs if `COVERAGE_PROCESS_START` is not set or points to an invalid configuration file, or if the subprocess environment doesn't inherit the necessary `COV_*` variables.fixVerify that `os.environ['COVERAGE_PROCESS_START']` is set to the absolute path of your `.coveragerc` before `subprocess.Popen`. Ensure `env=os.environ.copy()` is passed to `subprocess.Popen` to inherit all environment variables, including `COV_*`. -
Coverage data from multiple subprocesses is incomplete or overwritten
cause When multiple subprocesses run, `coverage.py` needs to write separate data files for each. If `parallel = True` is not set in the `.coveragerc`, subprocesses might attempt to write to the same `.coverage` file, leading to corruption or loss of data.fixAdd `parallel = True` under the `[run]` section of your `.coveragerc` file. After all subprocesses complete, use `coverage combine` to merge the individual `.coverage.<hostname>.<pid>.<timestamp>` files into a single `.coverage` file.
Warnings
- gotcha Coverage data may not be collected from subprocesses if `COV_*` environment variables are not correctly passed to them. When using `subprocess.Popen`, ensure the `env` argument includes all relevant `os.environ` variables, especially those starting with `COV_`.
- gotcha Using `process.kill()` to terminate subprocesses will prevent `coverage.py` from writing out its collected data, resulting in missing or incomplete coverage reports for those processes. Coverage.py relies on a clean shutdown (via `atexit` or `SIGTERM`) to write its data file.
- gotcha When measuring coverage across multiple subprocesses, `coverage.py` requires `parallel = True` in the `[run]` section of your `.coveragerc` file. Without this, subprocesses might overwrite each other's data files, or data might not be collected correctly.
- gotcha The `COVERAGE_PROCESS_START` environment variable *must* point to an existing and accessible `coverage.py` configuration file (e.g., `.coveragerc`). If the file is missing or the path is incorrect, coverage will not be enabled in subprocesses.
Install
-
pip install coverage-enable-subprocess
Imports
- No direct Python imports
This package works by installing a .pth file that automatically invokes `coverage.process_startup()` when Python starts, rather than providing symbols for direct import into user code. Its primary interaction is via environment variables and a `.coveragerc` file.
Quickstart
import os
import subprocess
import sys
# 1. Create a dummy .coveragerc for demonstration
with open('.coveragerc', 'w') as f:
f.write('[run]\n')
f.write('parallel = True\n')
f.write('data_file = .coverage.subprocess\n')
# 2. Set the environment variable to point coverage.py to the config file
os.environ['COVERAGE_PROCESS_START'] = os.path.abspath('.coveragerc')
# 3. Create a simple script to run as a subprocess
script_content = """
import os
import sys
# This line should be covered by the subprocess
def my_subprocess_func():
print("Hello from subprocess!")
if __name__ == '__main__':
my_subprocess_func()
"""
with open('subprocess_target.py', 'w') as f:
f.write(script_content)
print("Running subprocess...")
# 4. Run the script as a subprocess
# Ensure environment variables are passed correctly
subprocess_env = os.environ.copy()
process = subprocess.Popen([sys.executable, 'subprocess_target.py'], env=subprocess_env)
process.wait()
print("Subprocess finished. Check for .coverage.subprocess file.")
# Clean up (optional for quickstart, but good practice)
os.remove('.coveragerc')
os.remove('subprocess_target.py')
# To see the actual coverage report, you would then run:
# coverage combine --data-file=.coverage.subprocess
# coverage report --data-file=.coverage.subprocess