pytest-cov
pytest-cov copied to clipboard
Issues when using pytest-cov for project with sklearn
My repo contains 3 Python projects in a "projects" dir, and I'm running pytest --cov=packageA projects/packageA/tests (for each of the 3 projects). The 2nd project in the test sequence (so the 2nd pytest --cov run, out of 3) causes some lingering process-specific .coverage data files, which seems to impact the 3rd project's pytest run.
I've documented the issue with steps to reproduce in this repo (some details there about why this issue is here and not with coverage itself): https://github.com/mdscruggs/pytest-coverage-sklearn-issue
Happy to answer questions and assist.
> coverage debug config data sys
-- config ----------------------------------------------------
attempted_config_files: .coveragerc
setup.cfg
tox.ini
config_files: -none-
_include: None
_omit: None
branch: False
concurrency: None
cover_pylib: False
data_file: .coverage
debug: -none-
disable_warnings: -none-
note: None
parallel: False
plugins: -none-
source: None
run_include: None
run_omit: None
timid: False
exclude_list: #\s*(pragma|PRAGMA)[:\s]?\s*(no|NO)\s*(cover|COVER)
fail_under: 0.0
ignore_errors: False
report_include: None
report_omit: None
partial_always_list: while (True|1|False|0):
if (True|1|False|0):
partial_list: #\s*(pragma|PRAGMA)[:\s]?\s*(no|NO)\s*(branch|BRANCH)
precision: 0
show_missing: False
skip_covered: False
extra_css: None
html_dir: htmlcov
html_title: Coverage report
xml_output: coverage.xml
xml_package_depth: 99
paths: {}
plugin_options: {}
ds: None
-- data ------------------------------------------------------
path: /Users/user/repos/coverage-sklearn/.coverage
has_arcs: False
2 files:
/Users/user/repos/coverage-sklearn/mycode.py: 2 lines
/Users/user/repos/coverage-sklearn/othercode.py: 1 lines
-- sys -------------------------------------------------------
version: 4.5.3
coverage: /Users/user/repos/coverage-sklearn/venv/lib/python3.6/site-packages/coverage/__init__.py
cover_paths: /Users/user/repos/coverage-sklearn/venv/lib/python3.6/site-packages/coverage
pylib_paths: /Users/user/anaconda3/lib/python3.6
tracer: CTracer
plugins.file_tracers: -none-
plugins.configurers: -none-
config_files: .coveragerc
setup.cfg
tox.ini
configs_read: -none-
data_path: /Users/user/repos/coverage-sklearn/.coverage
python: 3.6.5 |Anaconda custom (64-bit)| (default, Apr 26 2018, 08:42:37) [GCC 4.2.1 Compatible Clang 4.0.1 (tags/RELEASE_401/final)]
platform: Darwin-17.7.0-x86_64-i386-64bit
implementation: CPython
executable: /Users/user/repos/coverage-sklearn/venv/bin/python3
cwd: /Users/user/repos/coverage-sklearn
path:
/Users/user/anaconda3/lib/python36.zip
/Users/user/anaconda3/lib/python3.6
/Users/user/anaconda3/lib/python3.6/lib-dynload
/Users/user/repos/coverage-sklearn/venv/lib/python3.6/site-packages
environment: PYSPARK_DRIVER_PYTHON_OPTS = -m jupyter notebook
command_line: /Users/user/repos/coverage-sklearn/venv/bin/coverage debug config data sys
source_match: -none-
source_pkgs_match: -none-
include_match: -none-
omit_match: -none-
cover_match: /Users/user/repos/coverage-sklearn/venv/lib/python3.6/site-packages/coverage
pylib_match: /Users/user/anaconda3/lib/python3.6
@mdscruggs just to check: have you tried the master of pytest-cov? Cause the master has quite some changes around subprocess handling ...
I just tried per your suggestion @ionelmc and the behavior + results appears the same.
So it appears that the lingering process starts with this:
execve("/tmp/pytest-coverage-sklearn-issue/venv/bin/python3", ["/tmp/pytest-coverage-sklearn-issue/venv/bin/python3", "-Wignore:A true SSLContext object is not available", "-c", "from multiprocessing.semaphore_tracker import main;main(8)"]
Obviously coveragepy alone won't track this process thus the assessment that pytest-cov does cleanup that coveragepy does is wrong. Coveragepy doesn't even know about that process.
~~Anyway, the situation is a bit tricky - pytest-cov has api for extra cleanup handler from a signal (pytest_cov.embed.cleanup_on_signal) however it cannot be used cause there's no place to put that code. We could have an env var to enable the handler I guess ...~~ - actually I doubt anyone tries to shutdown/sigterm that semaphore_tracker ...
An alternative solution is to make sure the semaphore_tracker is shut down before the test is done.
You can see the difference by measuring coverage on multiprocessing.semaphore_tracker.
pytest-cov could specifically handle cleanup for this semaphore_tracker but then again, maybe a more generic solution would be more useful. What if pytest-cov would wait for all the subprocesses to exit? That could get test suites stuck tho ...
@schlamar or @blueyed please share your opinion. These are the options:
- Implement specific handling for
multiprocessing.semaphore_tracker. Will probably involve gross monkeypatching. - Implement generic subprocess waiting. Can get tests stuck when users forget to shutdown subprocesses.