An IDE-friendly pytest workflow runner with coverage, a console dashboard and summary log, and optional detailed per-test-file logs.
Project description
pytest_harness
pytest_harness is a one-click pytest workflow runner for IDE-centered development. It handles pytest, coverage, subprocess isolation, summary reporting, and logs so tests are easy to run and interpret.
Why use pytest_harness?
- one-click test execution from an IDE
- no command-line flags, pyproject.toml coverage settings, or log setup required (pytest_harness handles settings)
- all test files run even if one test file crashes
- compact dashboard and runner log for the complete run:
- summary results
- list of files with import/test collection errors
- combined coverage
- (optional) coverage for each source file
- list of paths of created log files
- exit code
- optional per-test-file logs:
- test results
- user-generated print() statements (verifies tests are exercising the code as intended)
- missing (uncovered) source lines
- detailed docstring available with help(pytest_harness)
pytest_harness is a workflow tool, not a pytest plugin.
Quick Start
Create a small runner script in your project's test directory:
-
pytest_harness handles logging. Do not set up logging in your runner script.
-
Recommendation: give your runner script a name that does not start with
test_or end with_test.py. PyCharm may treat those names as pytest test files rather than executable scripts that can be run with right-click.pytest_harness_runner.py, located inside project_root/tests/
from pathlib import Path
from pytest_harness import pytest_harness
PROJECT_ROOT = Path(file).resolve().parent.parent
pytest_harness( test_dir=PROJECT_ROOT / "tests", log_dir=PROJECT_ROOT / "logs", source_dir=PROJECT_ROOT / "src" / "my_package", log_keep=5, )
Create a test file in your project's test directory:
-
Test filenames should match
test_*.py. -
Do not configure pytest_harness or logging inside individual test files.
-
Use print() inside test definitions to verify tests are exercising the code as intended.
-
Use tmp_path when tests create temporary files or directories.
-
Keep tests independent and do not rely on test execution order.
test_calculator.py, located inside project_root/tests/
from my_package.calculator import calculate_discount
def test_discount_calculation():
subtotal = 120 discount_rate = 0.15 result = calculate_discount(subtotal, discount_rate) expected = 18 print(f"subtotal={subtotal}") print(f"discount_rate={discount_rate}") print(f"calculated_discount={result}") print(f"expected_discount={expected}") assert result == expected
In PyCharm, right-click the runner script and run it.
Logs
pytest_harness automatically writes one summary log for the runner. When
individual_logs=True (the default), it also writes one log for each selected
test file.
When running pytest_harness_runner.py with
log_dir=PROJECT_ROOT / "logs"
and test_dir containing
test_config.py
unit/test_paths.py
-> log files:
output directory:
project_root/logs/pytest_runner/run_YYYY_MM_DD__HH_MM_SS/
files in output directory:
pytest_harness_runner.log
test_config.log
unit__test_paths.log
Output from print() statements inside a test file is captured in that test file's individual log.
Example Dashboard
-
Note: Created using
console_wrap_width = 100to better fit this documentlogging started: 2026-07-19 12:25:55 running script : pytest_harness_runner.py pruned run directories: 1 (keep=3) Running 9 test files: ......... done ════════════════════════════════════════════════════════════ TEST SUMMARY ════════════════════════════════════════════════════════════ Test file summary ------------------------------------------------------------ Source files covered: 8 Test files run: 9 Test files passed all tests: 6 Test files not processed, often due to an import error (1): test_import_error.py Test files with no collected tests (1): test_empty.py Test function summary ------------------------------------------------------------ Passed: 103 Failed: 1 Error: 0 XPassed: 0 Skipped: 0 XFailed: 0 Flagged test functions (in 1 test file): test_pytest_harness.py Failed (1): test_12_intentional_fail Coverage ------------------------------------------------------------ Statements: 95% Branches: 93% Total: 95% Source file Executed/ Coverage Statements Source file -------- ---------- ----------- 90% 94/104 record_builder.py 92% 168/183 constants_and_classes.py 97% 101/104 summary_data_builder.py 98% 78/80 arg_resolver.py 98% 48/49 resolve_test_file_paths.py 98% 55/56 pytest_harness.py 99% 70/71 summary_table_builder.py 100% 3/3 __init__.py ─────────────────────────────────────────────────────── logging ended : 2026-07-19 12:25:59 (duration 04 sec) script path : project_root/dev/pytest_harness_validation/pytest_harness_runner.py output directory: project_root/logs/pytest_harness_runner/run_2026_07_19__12_25_55/ files created this logging session in output directory: pytest_harness_runner.log ... test_summary_table_builder.log Process finished with exit code 1
Exit Codes
pytest_harness exits with:
0 the complete selected test run succeeded
1 the complete selected test run did not succeed
The run exits with code 1 when any of the following occurs:
- one or more test functions Failed
- one or more test functions produced Error
- one or more tests XPassed
- one or more selected test files could not be processed
- one or more selected test files collected no tests
Note:
- Skipped and XFailed outcomes do not by themselves cause exit code 1.
- They also do not trigger tests being listed under
Flagged test functions by test fileunlessshow_skipped_and_xfailed=True(default = False)
Arguments:
test_dir
Directory containing pytest test files.
Must be a pathlib.Path, must exist, and must be a directory.
log_dir
Directory where pytest_harness writes run logs.
Must be a pathlib.Path. If the directory does not exist, pytest_harness
creates it after all arguments have been validated.
source_dir
Source directory containing code files measured for coverage.
Must be a pathlib.Path, must exist, and must be a directory.
include_list
Optional list of test files or test directories to run.
Entries may be strings or pathlib.Path objects.
Default: None (discover all test files in test_dir).
exclude_list
Optional list of test files or test directories to exclude. Exclusions are applied after normal discovery or include-list selection.
Default: None (no test files excluded)
individual_logs
Optional. If True, writes a detailed log for each selected test file.
Default: True
coverage_warning_threshold
Optional total-coverage warning threshold from 0 through 100.
Default: 85.0 (use 0 or None to disable)
show_source_file_coverage
Optional. If True, displays the source-file coverage table.
Default: True
show_skipped_and_xfailed
Optional. If True, Skipped and XFailed outcomes are included in the flagged-test section along with Failed, Error, and XPassed outcomes.
Default: False
log_keep
Optional number of recent pytest_harness run directories to keep.
Only run directories containing the auto-generated .logduo_marker file are
eligible for pruning.
Default: None (no run directories pruned)
console_wrap_width
Optional. Console wrapping width used by Logduo. Must be a positive integer >= 80.
Default: 150
debug_pytest_harness
Optional. If True, prints additional pytest_harness diagnostic information, including the exact selected test files and official combined Coverage.py line counts.
Default: False
Examples
A basic example project is available in:
examples/basic_project/
More advanced usage and edge-case examples are available in:
developer_resources/pytest_harness_validation/
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pytest_harness-0.1.4.tar.gz.
File metadata
- Download URL: pytest_harness-0.1.4.tar.gz
- Upload date:
- Size: 21.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f7c0063efb3743b1ce4eb383bf84d57999abe33b7fd6a3d5b92f9641b9a8bc40
|
|
| MD5 |
3e261af70021254e93c83479791f0284
|
|
| BLAKE2b-256 |
41b3ef2d5cca4bc6b8a4ef9b3cdd047aaee23f7e1db18d3151fc45e2c6929ac7
|
File details
Details for the file pytest_harness-0.1.4-py3-none-any.whl.
File metadata
- Download URL: pytest_harness-0.1.4-py3-none-any.whl
- Upload date:
- Size: 21.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5bc56a5349e5399e8e5483e778b8bc20582a4221b6de20fe45b46a6f3e99ee25
|
|
| MD5 |
2db308f534fc852ec72cdfe0d4d81cf4
|
|
| BLAKE2b-256 |
8108161afd2a23722debdcb41c63276b095a9fbea6dfd9cebc0b44241bd4d966
|