pax_global_header00006660000000000000000000000064126523521540014517gustar00rootroot0000000000000052 comment=4b3d73d6e5a8e7b2baf61283857d9206c60cccb6 pytest-cov-2.2.1/000077500000000000000000000000001265235215400136365ustar00rootroot00000000000000pytest-cov-2.2.1/.bumpversion.cfg000066400000000000000000000002551265235215400167500ustar00rootroot00000000000000[bumpversion] current_version = 2.2.1 commit = True tag = True [bumpversion:file:setup.py] [bumpversion:file:docs/conf.py] [bumpversion:file:src/pytest_cov/__init__.py] pytest-cov-2.2.1/.cookiecutterrc000066400000000000000000000017321265235215400166670ustar00rootroot00000000000000# Generated by cookiepatcher, a small shim around cookiecutter (pip install cookiepatcher) cookiecutter: appveyor: 'yes' bin_name: ' ' c_extension_cython: 'no' c_extension_optional: 'no' c_extension_support: 'no' codacy: 'yes' codeclimate: 'yes' codecov: 'no' command_line_interface: 'no' coveralls: 'no' distribution_name: pytest-cov email: contact@ionelmc.ro full_name: Ionel Cristian Mărieș github_username: pytest-dev landscape: 'yes' package_name: pytest_cov project_name: pytest-cov project_short_description: This plugin produces coverage reports. It supports centralised testing and distributed testing in release_date: today repo_name: pytest-cov requiresio: 'yes' scrutinizer: 'yes' sphinx_theme: sphinx-py3doc-enhanced-theme test_matrix_configurator: 'no' test_runner: pytest travis: 'yes' version: 2.2.0 website: http://blog.ionelmc.ro year: now pytest-cov-2.2.1/.coveragerc000066400000000000000000000002071265235215400157560ustar00rootroot00000000000000[paths] source = src [run] branch = True source = src parallel = true [report] show_missing = true precision = 2 omit = *migrations* pytest-cov-2.2.1/.editorconfig000066400000000000000000000003271265235215400163150ustar00rootroot00000000000000# see http://editorconfig.org root = true [*] end_of_line = lf trim_trailing_whitespace = true insert_final_newline = true indent_style = space indent_size = 4 charset = utf-8 [*.{bat,cmd,ps1}] end_of_line = crlf pytest-cov-2.2.1/.gitignore000066400000000000000000000010401265235215400156210ustar00rootroot00000000000000*.py[cod] # C extensions *.so # Packages *.egg *.egg-info dist build eggs .eggs parts bin var sdist develop-eggs .installed.cfg lib lib64 venv*/ pyvenv*/ # Installer logs pip-log.txt # Unit test / coverage reports .coverage .tox .coverage.* nosetests.xml coverage.xml htmlcov # Translations *.mo # Mr Developer .mr.developer.cfg .project .pydevproject .idea *.iml *.komodoproject # Complexity output/*.html output/*/index.html # Sphinx docs/_build .DS_Store *~ .*.sw[po] .build .ve .env .cache .pytest .bootstrap .appveyor.token *.bak pytest-cov-2.2.1/.travis.yml000066400000000000000000000026731265235215400157570ustar00rootroot00000000000000language: python python: '3.5' sudo: false env: global: - LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so - SEGFAULT_SIGNALS=all matrix: - TOXENV=check - TOXENV=py26-27-37 - TOXENV=py26-27-40 - TOXENV=py26-27-41 - TOXENV=py26-28-37 - TOXENV=py26-28-40 - TOXENV=py26-28-41 - TOXENV=py27-27-37 - TOXENV=py27-27-40 - TOXENV=py27-27-41 - TOXENV=py27-28-37 - TOXENV=py27-28-40 - TOXENV=py27-28-41 - TOXENV=py33-27-37 - TOXENV=py33-27-40 - TOXENV=py33-27-41 - TOXENV=py33-28-37 - TOXENV=py33-28-40 - TOXENV=py33-28-41 - TOXENV=py34-27-37 - TOXENV=py34-27-40 - TOXENV=py34-27-41 - TOXENV=py34-28-37 - TOXENV=py34-28-40 - TOXENV=py34-28-41 - TOXENV=py35-27-37 - TOXENV=py35-27-40 - TOXENV=py35-27-41 - TOXENV=py35-28-37 - TOXENV=py35-28-40 - TOXENV=py35-28-41 - TOXENV=pypy-27-37 - TOXENV=pypy-27-40 - TOXENV=pypy-27-41 - TOXENV=pypy-28-37 - TOXENV=pypy-28-40 - TOXENV=pypy-28-41 before_install: - python --version - uname -a - lsb_release -a install: - pip install tox - virtualenv --version - easy_install --version - pip --version - tox --version script: - tox -v after_failure: - more .tox/log/* | cat - more .tox/*/log/* | cat before_cache: - rm -rf $HOME/.cache/pip/log cache: directories: - $HOME/.cache/pip notifications: email: on_success: never on_failure: always pytest-cov-2.2.1/AUTHORS.rst000066400000000000000000000007631265235215400155230ustar00rootroot00000000000000Authors ======= * Marc Schlaich - http://www.schlamar.org/ * Rick van Hattem - http://wol.ph/ * Buck Evan - https://github.com/bukzor * Eric Larson - http://larsoner.com/ * Marc Abramowitz - http://marc-abramowitz.com/ * Thomas Kluyver - https://github.com/takluyver * Guillaume Ayoub - http://www.yabz.fr/ * Federico Ceratto - http://firelet.net/ * Josh Kalderimis - http://blog.cookiestack.com/ * Ionel Cristian Mărieș - http://blog.ionelmc.ro * Christian Ledermann - https://github.com/cleder pytest-cov-2.2.1/CHANGELOG.rst000066400000000000000000000033071265235215400156620ustar00rootroot00000000000000Changelog ========= 2.2.1 (2016-01-28) ------------------ * Fixed incorrect merging of coverage data when xdist was used and coverage was ``>= 4.0``. 2.2.0 (2015-10-04) ------------------ * Added support for changing working directory in tests. Previously changing working directory would disable coverage measurements in suprocesses. * Fixed broken handling for ``--cov-report=annotate``. 2.1.0 (2015-08-23) ------------------ * Added support for `coverage 4.0b2`. * Added the ``--cov-append`` command line options. Contributed by Christian Ledermann in `PR#80 `_. 2.0.0 (2015-07-28) ------------------ * Added ``--cov-fail-under``, akin to the new ``fail_under`` option in `coverage-4.0` (automatically activated if there's a ``[report] fail_under = ...`` in ``.coveragerc``). * Changed ``--cov-report=term`` to automatically upgrade to ``--cov-report=term-missing`` if there's ``[run] show_missing = True`` in ``.coveragerc``. * Changed ``--cov`` so it can be used with no path argument (in wich case the source settings from ``.coveragerc`` will be used instead). * Fixed `.pth` installation to work in all cases (install, easy_install, wheels, develop etc). * Fixed `.pth` uninstallation to work for wheel installs. * Support for coverage 4.0. * Data file suffixing changed to use coverage's ``data_suffix=True`` option (instead of the custom suffixing). * Avoid warning about missing coverage data (just like ``coverage.control.process_startup``). * Fixed a race condition when running with xdist (all the workers tried to combine the files). It's possible that this issue is not present in `pytest-cov 1.8.X`. 1.8.2 (2014-11-06) ------------------ * N/A pytest-cov-2.2.1/CONTRIBUTING.rst000066400000000000000000000052261265235215400163040ustar00rootroot00000000000000============ Contributing ============ Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given. Bug reports =========== When `reporting a bug `_ please include: * Your operating system name and version. * Any details about your local setup that might be helpful in troubleshooting. * Detailed steps to reproduce the bug. Documentation improvements ========================== pytest-cov could always use more documentation, whether as part of the official pytest-cov docs, in docstrings, or even on the web in blog posts, articles, and such. Feature requests and feedback ============================= The best way to send feedback is to file an issue at https://github.com/pytest-dev/pytest-cov/issues. If you are proposing a feature: * Explain in detail how it would work. * Keep the scope as narrow as possible, to make it easier to implement. * Remember that this is a volunteer-driven project, and that code contributions are welcome :) Development =========== To set up `pytest-cov` for local development: 1. `Fork pytest-cov on GitHub `_. 2. Clone your fork locally:: git clone git@github.com:your_name_here/pytest-cov.git 3. Create a branch for local development:: git checkout -b name-of-your-bugfix-or-feature Now you can make your changes locally. 4. When you're done making changes, run all the checks, doc builder and spell checker with `tox `_ one command:: tox 5. Commit your changes and push your branch to GitHub:: git add . git commit -m "Your detailed description of your changes." git push origin name-of-your-bugfix-or-feature 6. Submit a pull request through the GitHub website. Pull Request Guidelines ----------------------- If you need some code review or feedback while you're developing the code just make the pull request. For merging, you should: 1. Include passing tests (run ``tox``) [1]_. 2. Update documentation when there's new API, functionality etc. 3. Add a note to ``CHANGELOG.rst`` about the changes. 4. Add yourself to ``AUTHORS.rst``. .. [1] If you don't have all the necessary python versions available locally you can rely on Travis - it will `run the tests `_ for each change you add in the pull request. It will be slower though ... Tips ---- To run a subset of tests:: tox -e envname -- py.test -k test_myfeature To run all the test environments in *parallel* (you need to ``pip install detox``):: detox pytest-cov-2.2.1/LICENSE000066400000000000000000000020571265235215400146470ustar00rootroot00000000000000The MIT License Copyright (c) 2010 Meme Dough Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pytest-cov-2.2.1/MANIFEST.in000066400000000000000000000005651265235215400154020ustar00rootroot00000000000000graft docs graft example graft src graft ci graft tests include .bumpversion.cfg include .coveragerc include .cookiecutterrc include .editorconfig include .isort.cfg include .pylintrc include AUTHORS.rst include CHANGELOG.rst include CONTRIBUTING.rst include LICENSE include README.rst include tox.ini .travis.yml appveyor.yml global-exclude *.py[cod] __pycache__ *.so pytest-cov-2.2.1/README.rst000066400000000000000000000250401265235215400153260ustar00rootroot00000000000000======== Overview ======== .. start-badges .. list-table:: :stub-columns: 1 * - docs - |docs| * - tests - | |travis| |appveyor| |requires| * - package - |version| |downloads| |wheel| |supported-versions| |supported-implementations| .. |docs| image:: https://readthedocs.org/projects/pytest-cov/badge/?style=flat :target: https://readthedocs.org/projects/pytest-cov :alt: Documentation Status .. |travis| image:: https://travis-ci.org/pytest-dev/pytest-cov.svg?branch=master :alt: Travis-CI Build Status :target: https://travis-ci.org/pytest-dev/pytest-cov .. |appveyor| image:: https://ci.appveyor.com/api/projects/status/github/pytest-dev/pytest-cov?branch=master&svg=true :alt: AppVeyor Build Status :target: https://ci.appveyor.com/project/pytestbot/pytest-cov .. |requires| image:: https://requires.io/github/pytest-dev/pytest-cov/requirements.svg?branch=master :alt: Requirements Status :target: https://requires.io/github/pytest-dev/pytest-cov/requirements/?branch=master .. |version| image:: https://img.shields.io/pypi/v/pytest-cov.svg?style=flat :alt: PyPI Package latest release :target: https://pypi.python.org/pypi/pytest-cov .. |downloads| image:: https://img.shields.io/pypi/dm/pytest-cov.svg?style=flat :alt: PyPI Package monthly downloads :target: https://pypi.python.org/pypi/pytest-cov .. |wheel| image:: https://img.shields.io/pypi/wheel/pytest-cov.svg?style=flat :alt: PyPI Wheel :target: https://pypi.python.org/pypi/pytest-cov .. |supported-versions| image:: https://img.shields.io/pypi/pyversions/pytest-cov.svg?style=flat :alt: Supported versions :target: https://pypi.python.org/pypi/pytest-cov .. |supported-implementations| image:: https://img.shields.io/pypi/implementation/pytest-cov.svg?style=flat :alt: Supported implementations :target: https://pypi.python.org/pypi/pytest-cov .. end-badges This plugin produces coverage reports. It supports centralised testing and distributed testing in both load and each modes. It also supports coverage of subprocesses. All features offered by the coverage package should be available, either through pytest-cov or through coverage's config file. * Free software: MIT license Installation ============ Install with pip:: pip install pytest-cov For distributed testing support install pytest-xdist:: pip install pytest-xdist Upgrade ======= `pytest-cov 2.0` is using a new ``.pth`` file (``pytest-cov.pth``). You may want to manually remove the older ``init_cov_core.pth`` from site-packages as it's not automatically removed. Uninstallation ============== Uninstall with pip:: pip uninstall pytest-cov Under certain scenarios a stray ``.pth`` file may be left around in site-packages. * `pytest-cov 2.0` may leave a ``pytest-cov.pth`` if you installed without wheels (``easy_install``, ``setup.py install`` etc). * `pytest-cov 1.8 or older` will leave a ``init_cov_core.pth``. Usage ===== Centralised Testing ------------------- Centralised testing will report on the combined coverage of the main process and all of it's subprocesses. Running centralised testing:: py.test --cov=myproj tests/ Shows a terminal report:: -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- Name Stmts Miss Cover ---------------------------------------- myproj/__init__ 2 0 100% myproj/myproj 257 13 94% myproj/feature4286 94 7 92% ---------------------------------------- TOTAL 353 20 94% Distributed Testing: Load ------------------------- Distributed testing with dist mode set to load will report on the combined coverage of all slaves. The slaves may be spread out over any number of hosts and each slave may be located anywhere on the file system. Each slave will have it's subprocesses measured. Running distributed testing with dist mode set to load:: py.test --cov=myproj -n 2 tests/ Shows a terminal report:: -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- Name Stmts Miss Cover ---------------------------------------- myproj/__init__ 2 0 100% myproj/myproj 257 13 94% myproj/feature4286 94 7 92% ---------------------------------------- TOTAL 353 20 94% Again but spread over different hosts and different directories:: py.test --cov=myproj --dist load --tx ssh=memedough@host1//chdir=testenv1 --tx ssh=memedough@host2//chdir=/tmp/testenv2//python=/tmp/env1/bin/python --rsyncdir myproj --rsyncdir tests --rsync examples tests/ Shows a terminal report:: -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- Name Stmts Miss Cover ---------------------------------------- myproj/__init__ 2 0 100% myproj/myproj 257 13 94% myproj/feature4286 94 7 92% ---------------------------------------- TOTAL 353 20 94% Distributed Testing: Each ------------------------- Distributed testing with dist mode set to each will report on the combined coverage of all slaves. Since each slave is running all tests this allows generating a combined coverage report for multiple environments. Running distributed testing with dist mode set to each:: py.test --cov=myproj --dist each --tx popen//chdir=/tmp/testenv3//python=/usr/local/python27/bin/python --tx ssh=memedough@host2//chdir=/tmp/testenv4//python=/tmp/env2/bin/python --rsyncdir myproj --rsyncdir tests --rsync examples tests/ Shows a terminal report:: ---------------------------------------- coverage ---------------------------------------- platform linux2, python 2.6.5-final-0 platform linux2, python 2.7.0-final-0 Name Stmts Miss Cover ---------------------------------------- myproj/__init__ 2 0 100% myproj/myproj 257 13 94% myproj/feature4286 94 7 92% ---------------------------------------- TOTAL 353 20 94% Reporting ========= It is possible to generate any combination of the reports for a single test run. The available reports are terminal (with or without missing line numbers shown), HTML, XML and annotated source code. The terminal report without line numbers (default):: py.test --cov-report term --cov=myproj tests/ -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- Name Stmts Miss Cover ---------------------------------------- myproj/__init__ 2 0 100% myproj/myproj 257 13 94% myproj/feature4286 94 7 92% ---------------------------------------- TOTAL 353 20 94% The terminal report with line numbers:: py.test --cov-report term-missing --cov=myproj tests/ -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- Name Stmts Miss Cover Missing -------------------------------------------------- myproj/__init__ 2 0 100% myproj/myproj 257 13 94% 24-26, 99, 149, 233-236, 297-298, 369-370 myproj/feature4286 94 7 92% 183-188, 197 -------------------------------------------------- TOTAL 353 20 94% These three report options output to files without showing anything on the terminal:: py.test --cov-report html --cov-report xml --cov-report annotate --cov=myproj tests/ The final report option can also suppress printing to the terminal:: py.test --cov-report= --cov=myproj tests/ This mode can be especially useful on continuous integration servers, where a coverage file is needed for subsequent processing, but no local report needs to be viewed. For example, tests run on Travis-CI could produce a .coverage file for use with Coveralls. Coverage Data File ================== The data file is erased at the beginning of testing to ensure clean data for each test run. If you need to combine the coverage of several test runs you can use the ``--cov-append`` option to append this coverage data to coverage data from previous test runs. The data file is left at the end of testing so that it is possible to use normal coverage tools to examine it. Coverage Config File ==================== This plugin provides a clean minimal set of command line options that are added to pytest. For further control of coverage use a coverage config file. For example if tests are contained within the directory tree being measured the tests may be excluded if desired by using a .coveragerc file with the omit option set:: py.test --cov-config .coveragerc --cov=myproj myproj/tests/ Where the .coveragerc file contains file globs:: [run] omit = tests/* For full details refer to the `coverage config file`_ documentation. .. _`coverage config file`: http://nedbatchelder.com/code/coverage/config.html Note that this plugin controls some options and setting the option in the config file will have no effect. These include specifying source to be measured (source option) and all data file handling (data_file and parallel options). Limitations =========== For distributed testing the slaves must have the pytest-cov package installed. This is needed since the plugin must be registered through setuptools for pytest to start the plugin on the slave. For subprocess measurement environment variables must make it from the main process to the subprocess. The python used by the subprocess must have pytest-cov installed. The subprocess must do normal site initialisation so that the environment variables can be detected and coverage started. Acknowledgements ================ Whilst this plugin has been built fresh from the ground up it has been influenced by the work done on pytest-coverage (Ross Lawley, James Mills, Holger Krekel) and nose-cover (Jason Pellerin) which are other coverage plugins. Ned Batchelder for coverage and its ability to combine the coverage results of parallel runs. Holger Krekel for pytest with its distributed testing support. Jason Pellerin for nose. Michael Foord for unittest2. No doubt others have contributed to these tools as well. pytest-cov-2.2.1/appveyor.yml000066400000000000000000000154771265235215400162440ustar00rootroot00000000000000version: '{branch}-{build}' build: off cache: - '%LOCALAPPDATA%\pip\Cache' environment: global: WITH_COMPILER: 'cmd /E:ON /V:ON /C .\ci\appveyor-with-compiler.cmd' matrix: - TOXENV: check PYTHON_HOME: C:\Python27 PYTHON_VERSION: '2.7' PYTHON_ARCH: '32' - TOXENV: 'py27-27-37' TOXPYTHON: C:\Python27\python.exe PYTHON_HOME: C:\Python27 PYTHON_VERSION: '2.7' PYTHON_ARCH: '32' - TOXENV: 'py27-27-37' TOXPYTHON: C:\Python27-x64\python.exe WINDOWS_SDK_VERSION: v7.0 PYTHON_HOME: C:\Python27-x64 PYTHON_VERSION: '2.7' PYTHON_ARCH: '64' - TOXENV: 'py27-27-40' TOXPYTHON: C:\Python27\python.exe PYTHON_HOME: C:\Python27 PYTHON_VERSION: '2.7' PYTHON_ARCH: '32' - TOXENV: 'py27-27-40' TOXPYTHON: C:\Python27-x64\python.exe WINDOWS_SDK_VERSION: v7.0 PYTHON_HOME: C:\Python27-x64 PYTHON_VERSION: '2.7' PYTHON_ARCH: '64' - TOXENV: 'py27-27-41' TOXPYTHON: C:\Python27\python.exe PYTHON_HOME: C:\Python27 PYTHON_VERSION: '2.7' PYTHON_ARCH: '32' - TOXENV: 'py27-27-41' TOXPYTHON: C:\Python27-x64\python.exe WINDOWS_SDK_VERSION: v7.0 PYTHON_HOME: C:\Python27-x64 PYTHON_VERSION: '2.7' PYTHON_ARCH: '64' - TOXENV: 'py27-28-37' TOXPYTHON: C:\Python27\python.exe PYTHON_HOME: C:\Python27 PYTHON_VERSION: '2.7' PYTHON_ARCH: '32' - TOXENV: 'py27-28-37' TOXPYTHON: C:\Python27-x64\python.exe WINDOWS_SDK_VERSION: v7.0 PYTHON_HOME: C:\Python27-x64 PYTHON_VERSION: '2.7' PYTHON_ARCH: '64' - TOXENV: 'py27-28-40' TOXPYTHON: C:\Python27\python.exe PYTHON_HOME: C:\Python27 PYTHON_VERSION: '2.7' PYTHON_ARCH: '32' - TOXENV: 'py27-28-40' TOXPYTHON: C:\Python27-x64\python.exe WINDOWS_SDK_VERSION: v7.0 PYTHON_HOME: C:\Python27-x64 PYTHON_VERSION: '2.7' PYTHON_ARCH: '64' - TOXENV: 'py27-28-41' TOXPYTHON: C:\Python27\python.exe PYTHON_HOME: C:\Python27 PYTHON_VERSION: '2.7' PYTHON_ARCH: '32' - TOXENV: 'py27-28-41' TOXPYTHON: C:\Python27-x64\python.exe WINDOWS_SDK_VERSION: v7.0 PYTHON_HOME: C:\Python27-x64 PYTHON_VERSION: '2.7' PYTHON_ARCH: '64' - TOXENV: 'py34-27-37' TOXPYTHON: C:\Python34\python.exe PYTHON_HOME: C:\Python34 PYTHON_VERSION: '3.4' PYTHON_ARCH: '32' - TOXENV: 'py34-27-37' TOXPYTHON: C:\Python34-x64\python.exe WINDOWS_SDK_VERSION: v7.1 PYTHON_HOME: C:\Python34-x64 PYTHON_VERSION: '3.4' PYTHON_ARCH: '64' - TOXENV: 'py34-27-40' TOXPYTHON: C:\Python34\python.exe PYTHON_HOME: C:\Python34 PYTHON_VERSION: '3.4' PYTHON_ARCH: '32' - TOXENV: 'py34-27-40' TOXPYTHON: C:\Python34-x64\python.exe WINDOWS_SDK_VERSION: v7.1 PYTHON_HOME: C:\Python34-x64 PYTHON_VERSION: '3.4' PYTHON_ARCH: '64' - TOXENV: 'py34-27-41' TOXPYTHON: C:\Python34\python.exe PYTHON_HOME: C:\Python34 PYTHON_VERSION: '3.4' PYTHON_ARCH: '32' - TOXENV: 'py34-27-41' TOXPYTHON: C:\Python34-x64\python.exe WINDOWS_SDK_VERSION: v7.1 PYTHON_HOME: C:\Python34-x64 PYTHON_VERSION: '3.4' PYTHON_ARCH: '64' - TOXENV: 'py34-28-37' TOXPYTHON: C:\Python34\python.exe PYTHON_HOME: C:\Python34 PYTHON_VERSION: '3.4' PYTHON_ARCH: '32' - TOXENV: 'py34-28-37' TOXPYTHON: C:\Python34-x64\python.exe WINDOWS_SDK_VERSION: v7.1 PYTHON_HOME: C:\Python34-x64 PYTHON_VERSION: '3.4' PYTHON_ARCH: '64' - TOXENV: 'py34-28-40' TOXPYTHON: C:\Python34\python.exe PYTHON_HOME: C:\Python34 PYTHON_VERSION: '3.4' PYTHON_ARCH: '32' - TOXENV: 'py34-28-40' TOXPYTHON: C:\Python34-x64\python.exe WINDOWS_SDK_VERSION: v7.1 PYTHON_HOME: C:\Python34-x64 PYTHON_VERSION: '3.4' PYTHON_ARCH: '64' - TOXENV: 'py34-28-41' TOXPYTHON: C:\Python34\python.exe PYTHON_HOME: C:\Python34 PYTHON_VERSION: '3.4' PYTHON_ARCH: '32' - TOXENV: 'py34-28-41' TOXPYTHON: C:\Python34-x64\python.exe WINDOWS_SDK_VERSION: v7.1 PYTHON_HOME: C:\Python34-x64 PYTHON_VERSION: '3.4' PYTHON_ARCH: '64' - TOXENV: 'py35-27-37' TOXPYTHON: C:\Python35\python.exe PYTHON_HOME: C:\Python35 PYTHON_VERSION: '3.5' PYTHON_ARCH: '32' - TOXENV: 'py35-27-37' TOXPYTHON: C:\Python35-x64\python.exe PYTHON_HOME: C:\Python35-x64 PYTHON_VERSION: '3.5' PYTHON_ARCH: '64' - TOXENV: 'py35-27-40' TOXPYTHON: C:\Python35\python.exe PYTHON_HOME: C:\Python35 PYTHON_VERSION: '3.5' PYTHON_ARCH: '32' - TOXENV: 'py35-27-40' TOXPYTHON: C:\Python35-x64\python.exe PYTHON_HOME: C:\Python35-x64 PYTHON_VERSION: '3.5' PYTHON_ARCH: '64' - TOXENV: 'py35-27-41' TOXPYTHON: C:\Python35\python.exe PYTHON_HOME: C:\Python35 PYTHON_VERSION: '3.5' PYTHON_ARCH: '32' - TOXENV: 'py35-27-41' TOXPYTHON: C:\Python35-x64\python.exe PYTHON_HOME: C:\Python35-x64 PYTHON_VERSION: '3.5' PYTHON_ARCH: '64' - TOXENV: 'py35-28-37' TOXPYTHON: C:\Python35\python.exe PYTHON_HOME: C:\Python35 PYTHON_VERSION: '3.5' PYTHON_ARCH: '32' - TOXENV: 'py35-28-37' TOXPYTHON: C:\Python35-x64\python.exe PYTHON_HOME: C:\Python35-x64 PYTHON_VERSION: '3.5' PYTHON_ARCH: '64' - TOXENV: 'py35-28-40' TOXPYTHON: C:\Python35\python.exe PYTHON_HOME: C:\Python35 PYTHON_VERSION: '3.5' PYTHON_ARCH: '32' - TOXENV: 'py35-28-40' TOXPYTHON: C:\Python35-x64\python.exe PYTHON_HOME: C:\Python35-x64 PYTHON_VERSION: '3.5' PYTHON_ARCH: '64' - TOXENV: 'py35-28-41' TOXPYTHON: C:\Python35\python.exe PYTHON_HOME: C:\Python35 PYTHON_VERSION: '3.5' PYTHON_ARCH: '32' - TOXENV: 'py35-28-41' TOXPYTHON: C:\Python35-x64\python.exe PYTHON_HOME: C:\Python35-x64 PYTHON_VERSION: '3.5' PYTHON_ARCH: '64' init: - ps: echo $env:TOXENV - ps: ls C:\Python* install: - python -u ci\appveyor-bootstrap.py - '%PYTHON_HOME%\Scripts\virtualenv --version' - '%PYTHON_HOME%\Scripts\easy_install --version' - '%PYTHON_HOME%\Scripts\pip --version' - '%PYTHON_HOME%\Scripts\tox --version' test_script: - '%WITH_COMPILER% %PYTHON_HOME%\Scripts\tox' on_failure: - ps: dir "env:" - ps: get-content .tox\*\log\* artifacts: - path: dist\* ### To enable remote debugging uncomment this (also, see: http://www.appveyor.com/docs/how-to/rdp-to-build-worker): # on_finish: # - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) pytest-cov-2.2.1/ci/000077500000000000000000000000001265235215400142315ustar00rootroot00000000000000pytest-cov-2.2.1/ci/appveyor-bootstrap.py000066400000000000000000000105341265235215400204660ustar00rootroot00000000000000""" AppVeyor will at least have few Pythons around so there's no point of implementing a bootstrapper in PowerShell. This is a port of https://github.com/pypa/python-packaging-user-guide/blob/master/source/code/install.ps1 with various fixes and improvements that just weren't feasible to implement in PowerShell. """ from __future__ import print_function from os import environ from os.path import exists from subprocess import check_call try: from urllib.request import urlretrieve except ImportError: from urllib import urlretrieve BASE_URL = "https://www.python.org/ftp/python/" GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py" GET_PIP_PATH = "C:\get-pip.py" URLS = { ("2.6", "64"): BASE_URL + "2.6.6/python-2.6.6.amd64.msi", ("2.6", "32"): BASE_URL + "2.6.6/python-2.6.6.msi", ("2.7", "64"): BASE_URL + "2.7.10/python-2.7.10.amd64.msi", ("2.7", "32"): BASE_URL + "2.7.10/python-2.7.10.msi", # NOTE: no .msi installer for 3.3.6 ("3.3", "64"): BASE_URL + "3.3.3/python-3.3.3.amd64.msi", ("3.3", "32"): BASE_URL + "3.3.3/python-3.3.3.msi", ("3.4", "64"): BASE_URL + "3.4.3/python-3.4.3.amd64.msi", ("3.4", "32"): BASE_URL + "3.4.3/python-3.4.3.msi", ("3.5", "64"): BASE_URL + "3.5.0/python-3.5.0-amd64.exe", ("3.5", "32"): BASE_URL + "3.5.0/python-3.5.0.exe", } INSTALL_CMD = { # Commands are allowed to fail only if they are not the last command. Eg: uninstall (/x) allowed to fail. "2.6": [["msiexec.exe", "/L*+!", "install.log", "/qn", "/x", "{path}"], ["msiexec.exe", "/L*+!", "install.log", "/qn", "/i", "{path}", "TARGETDIR={home}"]], "2.7": [["msiexec.exe", "/L*+!", "install.log", "/qn", "/x", "{path}"], ["msiexec.exe", "/L*+!", "install.log", "/qn", "/i", "{path}", "TARGETDIR={home}"]], "3.3": [["msiexec.exe", "/L*+!", "install.log", "/qn", "/x", "{path}"], ["msiexec.exe", "/L*+!", "install.log", "/qn", "/i", "{path}", "TARGETDIR={home}"]], "3.4": [["msiexec.exe", "/L*+!", "install.log", "/qn", "/x", "{path}"], ["msiexec.exe", "/L*+!", "install.log", "/qn", "/i", "{path}", "TARGETDIR={home}"]], "3.5": [["{path}", "/quiet", "TargetDir={home}"]], } def download_file(url, path): print("Downloading: {} (into {})".format(url, path)) progress = [0, 0] def report(count, size, total): progress[0] = count * size if progress[0] - progress[1] > 1000000: progress[1] = progress[0] print("Downloaded {:,}/{:,} ...".format(progress[1], total)) dest, _ = urlretrieve(url, path, reporthook=report) return dest def install_python(version, arch, home): print("Installing Python", version, "for", arch, "bit architecture to", home) if exists(home): return path = download_python(version, arch) print("Installing", path, "to", home) success = False for cmd in INSTALL_CMD[version]: cmd = [part.format(home=home, path=path) for part in cmd] print("Running:", " ".join(cmd)) try: check_call(cmd) except Exception as exc: print("Failed command", cmd, "with:", exc) if exists("install.log"): with open("install.log") as fh: print(fh.read()) else: success = True if success: print("Installation complete!") else: print("Installation failed") def download_python(version, arch): for _ in range(3): try: return download_file(URLS[version, arch], "installer.exe") except Exception as exc: print("Failed to download:", exc) print("Retrying ...") def install_pip(home): pip_path = home + "/Scripts/pip.exe" python_path = home + "/python.exe" if exists(pip_path): print("pip already installed.") else: print("Installing pip...") download_file(GET_PIP_URL, GET_PIP_PATH) print("Executing:", python_path, GET_PIP_PATH) check_call([python_path, GET_PIP_PATH]) def install_packages(home, *packages): cmd = [home + "/Scripts/pip.exe", "install"] cmd.extend(packages) check_call(cmd) if __name__ == "__main__": install_python(environ['PYTHON_VERSION'], environ['PYTHON_ARCH'], environ['PYTHON_HOME']) install_pip(environ['PYTHON_HOME']) install_packages(environ['PYTHON_HOME'], "setuptools>=18.0.1", "wheel", "tox", "virtualenv>=13.1.0") pytest-cov-2.2.1/ci/appveyor-with-compiler.cmd000066400000000000000000000030761265235215400213520ustar00rootroot00000000000000:: To build extensions for 64 bit Python 3, we need to configure environment :: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of: :: MS Windows SDK for Windows 7 and .NET Framework 4 (SDK v7.1) :: :: To build extensions for 64 bit Python 2, we need to configure environment :: variables to use the MSVC 2008 C++ compilers from GRMSDKX_EN_DVD.iso of: :: MS Windows SDK for Windows 7 and .NET Framework 3.5 (SDK v7.0) :: :: 32 bit builds do not require specific environment configurations. :: :: Note: this script needs to be run with the /E:ON and /V:ON flags for the :: cmd interpreter, at least for (SDK v7.0) :: :: More details at: :: https://github.com/cython/cython/wiki/64BitCythonExtensionsOnWindows :: http://stackoverflow.com/a/13751649/163740 :: :: Author: Olivier Grisel :: License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/ SET COMMAND_TO_RUN=%* SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows SET WIN_WDK="c:\Program Files (x86)\Windows Kits\10\Include\wdf" ECHO SDK: %WINDOWS_SDK_VERSION% ARCH: %PYTHON_ARCH% IF "%PYTHON_VERSION%"=="3.5" ( IF EXIST %WIN_WDK% ( REM See: https://connect.microsoft.com/VisualStudio/feedback/details/1610302/ REN %WIN_WDK% 0wdf ) GOTO main ) IF "%PYTHON_ARCH%"=="32" ( GOTO main ) SET DISTUTILS_USE_SDK=1 SET MSSdk=1 "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WINDOWS_SDK_VERSION% CALL "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release :main ECHO Executing: %COMMAND_TO_RUN% CALL %COMMAND_TO_RUN% || EXIT 1 pytest-cov-2.2.1/ci/bootstrap.py000077500000000000000000000035161265235215400166300ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import absolute_import, print_function, unicode_literals import os import sys from os.path import exists from os.path import join from os.path import dirname from os.path import abspath if __name__ == "__main__": base_path = dirname(dirname(abspath(__file__))) print("Project path: {0}".format(base_path)) env_path = join(base_path, ".tox", "bootstrap") if sys.platform == "win32": bin_path = join(env_path, "Scripts") else: bin_path = join(env_path, "bin") if not exists(env_path): import subprocess print("Making bootstrap env in: {0} ...".format(env_path)) try: subprocess.check_call(["virtualenv", env_path]) except Exception: subprocess.check_call([sys.executable, "-m", "virtualenv", env_path]) print("Installing `jinja2` into bootstrap environment ...") subprocess.check_call([join(bin_path, "pip"), "install", "jinja2"]) activate = join(bin_path, "activate_this.py") exec(compile(open(activate, "rb").read(), activate, "exec"), dict(__file__=activate)) import jinja2 import subprocess jinja = jinja2.Environment( loader=jinja2.FileSystemLoader(join(base_path, "ci", "templates")), trim_blocks=True, lstrip_blocks=True, keep_trailing_newline=True ) tox_environments = [line.strip() for line in subprocess.check_output(['tox', '--listenvs']).splitlines()] tox_environments = [line for line in tox_environments if line not in ['clean', 'report', 'docs', 'check']] for name in os.listdir(join("ci", "templates")): with open(join(base_path, name), "w") as fh: fh.write(jinja.get_template(name).render(tox_environments=tox_environments)) print("Wrote {}".format(name)) print("DONE.") pytest-cov-2.2.1/ci/templates/000077500000000000000000000000001265235215400162275ustar00rootroot00000000000000pytest-cov-2.2.1/ci/templates/.travis.yml000066400000000000000000000013261265235215400203420ustar00rootroot00000000000000language: python python: '3.5' sudo: false env: global: - LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so - SEGFAULT_SIGNALS=all matrix: - TOXENV=check {% for env in tox_environments %}{{ '' }} - TOXENV={{ env }}{% if 'cover' in env %},coveralls{% endif -%} {% endfor %} before_install: - python --version - uname -a - lsb_release -a install: - pip install tox - virtualenv --version - easy_install --version - pip --version - tox --version script: - tox -v after_failure: - more .tox/log/* | cat - more .tox/*/log/* | cat before_cache: - rm -rf $HOME/.cache/pip/log cache: directories: - $HOME/.cache/pip notifications: email: on_success: never on_failure: always pytest-cov-2.2.1/ci/templates/appveyor.yml000066400000000000000000000033311265235215400206170ustar00rootroot00000000000000version: '{branch}-{build}' build: off cache: - '%LOCALAPPDATA%\pip\Cache' environment: global: WITH_COMPILER: 'cmd /E:ON /V:ON /C .\ci\appveyor-with-compiler.cmd' matrix: - TOXENV: check PYTHON_HOME: C:\Python27 PYTHON_VERSION: '2.7' PYTHON_ARCH: '32' {% for env in tox_environments %}{% if env.startswith(('py27', 'py34', 'py35')) %} - TOXENV: '{{ env }}{% if 'cover' in env %},codecov{% endif %}' TOXPYTHON: C:\Python{{ env[2:4] }}\python.exe PYTHON_HOME: C:\Python{{ env[2:4] }} PYTHON_VERSION: '{{ env[2] }}.{{ env[3] }}' PYTHON_ARCH: '32' - TOXENV: '{{ env }}{% if 'cover' in env %},codecov{% endif %}' TOXPYTHON: C:\Python{{ env[2:4] }}-x64\python.exe {%- if env.startswith(('py2', 'py33', 'py34')) %} WINDOWS_SDK_VERSION: v7.{{ '1' if env.startswith('py3') else '0' }} {%- endif %} PYTHON_HOME: C:\Python{{ env[2:4] }}-x64 PYTHON_VERSION: '{{ env[2] }}.{{ env[3] }}' PYTHON_ARCH: '64' {% endif %}{% endfor %} init: - ps: echo $env:TOXENV - ps: ls C:\Python* install: - python -u ci\appveyor-bootstrap.py - '%PYTHON_HOME%\Scripts\virtualenv --version' - '%PYTHON_HOME%\Scripts\easy_install --version' - '%PYTHON_HOME%\Scripts\pip --version' - '%PYTHON_HOME%\Scripts\tox --version' test_script: - '%WITH_COMPILER% %PYTHON_HOME%\Scripts\tox' on_failure: - ps: dir "env:" - ps: get-content .tox\*\log\* artifacts: - path: dist\* ### To enable remote debugging uncomment this (also, see: http://www.appveyor.com/docs/how-to/rdp-to-build-worker): # on_finish: # - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) pytest-cov-2.2.1/docs/000077500000000000000000000000001265235215400145665ustar00rootroot00000000000000pytest-cov-2.2.1/docs/authors.rst000066400000000000000000000000341265235215400170020ustar00rootroot00000000000000.. include:: ../AUTHORS.rst pytest-cov-2.2.1/docs/changelog.rst000066400000000000000000000000361265235215400172460ustar00rootroot00000000000000.. include:: ../CHANGELOG.rst pytest-cov-2.2.1/docs/conf.py000066400000000000000000000025471265235215400160750ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import unicode_literals import os extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.autosummary', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode', 'sphinx.ext.napoleon', 'sphinx.ext.extlinks', ] if os.getenv('SPELLCHECK'): extensions += 'sphinxcontrib.spelling', spelling_show_suggestions = True spelling_lang = 'en_US' source_suffix = '.rst' master_doc = 'index' project = 'pytest-cov' year = '2016' author = 'pytest-cov contributors' copyright = '{0}, {1}'.format(year, author) version = release = '2.2.1' pygments_style = 'trac' templates_path = ['.'] extlinks = { 'issue': ('https://github.com/pytest-dev/pytest-cov/issues/%s', '#'), 'pr': ('https://github.com/pytest-dev/pytest-cov/pull/%s', 'PR #'), } import sphinx_py3doc_enhanced_theme html_theme = "sphinx_py3doc_enhanced_theme" html_theme_path = [sphinx_py3doc_enhanced_theme.get_html_theme_path()] html_theme_options = { 'githuburl': 'https://github.com/pytest-dev/pytest-cov/' } html_use_smartypants = True html_last_updated_fmt = '%b %d, %Y' html_split_index = True html_sidebars = { '**': ['searchbox.html', 'globaltoc.html', 'sourcelink.html'], } html_short_title = '%s-%s' % (project, version) napoleon_use_ivar = True napoleon_use_rtype = False napoleon_use_param = False pytest-cov-2.2.1/docs/contributing.rst000066400000000000000000000000411265235215400200220ustar00rootroot00000000000000.. include:: ../CONTRIBUTING.rst pytest-cov-2.2.1/docs/index.rst000066400000000000000000000004441265235215400164310ustar00rootroot00000000000000Welcome to pytest-cov's documentation! ====================================== Contents: .. toctree:: :maxdepth: 2 readme installation contributing releasing authors changelog Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` pytest-cov-2.2.1/docs/installation.rst000066400000000000000000000001321265235215400200150ustar00rootroot00000000000000============ Installation ============ At the command line:: pip install pytest-cov pytest-cov-2.2.1/docs/readme.rst000066400000000000000000000000671265235215400165600ustar00rootroot00000000000000######## Overview ######## .. include:: ../README.rst pytest-cov-2.2.1/docs/releasing.rst000066400000000000000000000025461265235215400173000ustar00rootroot00000000000000========= Releasing ========= The process for releasing should follow these steps: #. Test that docs build and render properly by running ``tox -e docs,spell``. If there are bogus spelling issues add the words in ``spelling_wordlist.txt``. #. Update ``CHANGELOG.rst`` and ``AUTHORS.rst`` to be up to date. #. Bump the version by running ``bumpversion [ major | minor | patch ]``. This will automatically add a tag. Alternativelly, you can manually edit the files and run ``git tag v1.2.3`` yourself. #. Push changes and tags with:: git push git push --tags #. Wait for `AppVeyor `_ and `Travis `_ to give the green builds. #. Check that the docs on `ReadTheDocs `_ are built. #. Make sure you have a clean checkout, run ``git status`` to verify. #. Manually clean temporary files (that are ignored and won't show up in ``git status``):: rm -rf dist build src/*.egg-info These files need to be removed to force distutils/setuptools to rebuild everything and recreate the egg-info metadata. #. Build the dists:: python3.4 setup.py clean --all sdist bdist_wheel #. Verify that the resulting archives (found in ``dist/``) are good. #. Upload the sdist and wheel with twine:: twine upload dist/* pytest-cov-2.2.1/docs/requirements.txt000066400000000000000000000000561265235215400200530ustar00rootroot00000000000000sphinx>=1.3 sphinx-py3doc-enhanced-theme -e . pytest-cov-2.2.1/docs/spelling_wordlist.txt000066400000000000000000000001551265235215400210740ustar00rootroot00000000000000builtin builtins classmethod staticmethod classmethods staticmethods args kwargs callstack Changelog Indices pytest-cov-2.2.1/example/000077500000000000000000000000001265235215400152715ustar00rootroot00000000000000pytest-cov-2.2.1/example/.coveragerc000066400000000000000000000000241265235215400174060ustar00rootroot00000000000000[run] source = mylibpytest-cov-2.2.1/example/mylib/000077500000000000000000000000001265235215400164055ustar00rootroot00000000000000pytest-cov-2.2.1/example/mylib/__init__.py000066400000000000000000000002151265235215400205140ustar00rootroot00000000000000 import sys PY3 = sys.version_info[0] == 3 if PY3: def add(a, b): return a + b else: def add(a, b): return b + a pytest-cov-2.2.1/example/setup.py000066400000000000000000000001251265235215400170010ustar00rootroot00000000000000 from setuptools import setup, find_packages setup( packages=find_packages() ) pytest-cov-2.2.1/example/tests/000077500000000000000000000000001265235215400164335ustar00rootroot00000000000000pytest-cov-2.2.1/example/tests/test_mylib.py000066400000000000000000000001441265235215400211570ustar00rootroot00000000000000 import mylib def test_add(): assert mylib.add(1, 1) == 2 assert not mylib.add(0, 1) == 2 pytest-cov-2.2.1/example/tox.ini000066400000000000000000000007141265235215400166060ustar00rootroot00000000000000[tox] envlist = cov-init,py27,py34,cov-report [testenv] usedevelop=True setenv = COVERAGE_FILE = .coverage.{envname} commands = py.test --cov --cov-report= {posargs} deps = ../cov-core pytest ../pytest-cov [testenv:cov-init] setenv = COVERAGE_FILE = .coverage deps = coverage commands = coverage erase [testenv:cov-report] setenv = COVERAGE_FILE = .coverage deps = coverage commands = coverage combine coverage report pytest-cov-2.2.1/setup.cfg000066400000000000000000000012741265235215400154630ustar00rootroot00000000000000[bdist_wheel] universal = 1 [aliases] release = register clean --all sdist bdist_wheel [flake8] max-line-length = 140 exclude = tests/*,*/migrations/*,*/south_migrations/* [pytest] norecursedirs = .git .tox .env dist build south_migrations migrations example python_files = test_*.py *_test.py tests.py addopts = -rxEfsw --strict --ignore=docs/conf.py --ignore=setup.py --ignore=src --ignore=ci --ignore=.eggs --doctest-modules --doctest-glob=\*.rst --tb=short -p pytester [isort] force_single_line=True line_length=120 known_first_party=pytest_cov default_section=THIRDPARTY forced_separate=test_pytest_cov pytest-cov-2.2.1/setup.py000066400000000000000000000102761265235215400153560ustar00rootroot00000000000000#!/usr/bin/env python # -*- encoding: utf-8 -*- from __future__ import absolute_import, print_function import io from itertools import chain import re from glob import glob from os.path import basename from os.path import dirname from os.path import join from os.path import splitext from distutils.command.build import build from setuptools import Command from setuptools import find_packages from setuptools import setup from setuptools.command.develop import develop from setuptools.command.install_lib import install_lib from setuptools.command.easy_install import easy_install def read(*names, **kwargs): return io.open( join(dirname(__file__), *names), encoding=kwargs.get('encoding', 'utf8') ).read() class BuildWithPTH(build): def run(self): build.run(self) path = join(dirname(__file__), 'src', 'pytest-cov.pth') dest = join(self.build_lib, basename(path)) self.copy_file(path, dest) class EasyInstallWithPTH(easy_install): def run(self): easy_install.run(self) path = join(dirname(__file__), 'src', 'pytest-cov.pth') dest = join(self.install_dir, basename(path)) self.copy_file(path, dest) class InstallLibWithPTH(install_lib): def run(self): install_lib.run(self) path = join(dirname(__file__), 'src', 'pytest-cov.pth') dest = join(self.install_dir, basename(path)) self.copy_file(path, dest) self.outputs = [dest] def get_outputs(self): return chain(install_lib.get_outputs(self), self.outputs) class DevelopWithPTH(develop): def run(self): develop.run(self) path = join(dirname(__file__), 'src', 'pytest-cov.pth') dest = join(self.install_dir, basename(path)) self.copy_file(path, dest) class GeneratePTH(Command): user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): with open(join(dirname(__file__), 'src', 'pytest-cov.pth'), 'w') as fh: with open(join(dirname(__file__), 'src', 'pytest-cov.embed')) as sh: fh.write( 'import os, sys;' 'exec(%r)' % sh.read().replace(' ', ' ') ) setup( name='pytest-cov', version='2.2.1', license='MIT', description='Pytest plugin for measuring coverage.', long_description='%s\n%s' % (read('README.rst'), re.sub(':[a-z]+:`~?(.*?)`', r'``\1``', read('CHANGELOG.rst'))), author='Marc Schlaich', author_email='marc.schlaich@gmail.com', url='https://github.com/pytest-dev/pytest-cov', packages=find_packages('src'), package_dir={'': 'src'}, py_modules=[splitext(basename(path))[0] for path in glob('src/*.py')], include_package_data=True, zip_safe=False, classifiers=[ # complete classifier list: http://pypi.python.org/pypi?%3Aaction=list_classifiers 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Operating System :: Unix', 'Operating System :: POSIX', 'Operating System :: Microsoft :: Windows', 'Programming Language :: Python', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Utilities', 'Topic :: Software Development :: Testing' ], keywords=[ 'cover', 'coverage', 'pytest', 'py.test', 'distributed', 'parallel', ], install_requires=[ 'pytest>=2.6.0', 'coverage>=3.7.1' ], extras_require={ }, entry_points={ 'pytest11': [ 'pytest_cov = pytest_cov.plugin', ], 'console_scripts': [ ] }, cmdclass={ 'build': BuildWithPTH, 'easy_install': EasyInstallWithPTH, 'install_lib': InstallLibWithPTH, 'develop': DevelopWithPTH, 'genpth': GeneratePTH, }, ) pytest-cov-2.2.1/src/000077500000000000000000000000001265235215400144255ustar00rootroot00000000000000pytest-cov-2.2.1/src/pytest-cov.embed000066400000000000000000000005221265235215400175370ustar00rootroot00000000000000if 'COV_CORE_SOURCE' in os.environ: try: from pytest_cov.embed import init init() except ImportError: sys.stderr.write( "Failed to setup coverage." "Sources: {[COV_CORE_SOURCE]!r}" "Config: {[COV_CORE_CONFIG]!r}" "Exception: {!r}\n".format(os.environ, exc)) pytest-cov-2.2.1/src/pytest-cov.pth000066400000000000000000000004731265235215400172630ustar00rootroot00000000000000import os, sys;exec('if \'COV_CORE_SOURCE\' in os.environ:\n try:\n from pytest_cov.embed import init\n init()\n except ImportError:\n sys.stderr.write(\n "Failed to setup coverage."\n "Sources: {[COV_CORE_SOURCE]!r}"\n "Config: {[COV_CORE_CONFIG]!r}"\n "Exception: {!r}\\n".format(os.environ, exc))\n') pytest-cov-2.2.1/src/pytest_cov/000077500000000000000000000000001265235215400166245ustar00rootroot00000000000000pytest-cov-2.2.1/src/pytest_cov/__init__.py000066400000000000000000000000261265235215400207330ustar00rootroot00000000000000__version__ = "2.2.1" pytest-cov-2.2.1/src/pytest_cov/embed.py000066400000000000000000000037151265235215400202600ustar00rootroot00000000000000"""Activate coverage at python startup if appropriate. The python site initialisation will ensure that anything we import will be removed and not visible at the end of python startup. However we minimise all work by putting these init actions in this separate module and only importing what is needed when needed. For normal python startup when coverage should not be activated the pth file checks a single env var and does not import or call the init fn here. For python startup when an ancestor process has set the env indicating that code coverage is being collected we activate coverage based on info passed via env vars. """ import os def multiprocessing_start(obj): cov = init() if cov: multiprocessing.util.Finalize(None, multiprocessing_finish, args=(cov,), exitpriority=1000) def multiprocessing_finish(cov): cov.stop() cov.save() try: import multiprocessing.util except ImportError: pass else: multiprocessing.util.register_after_fork(multiprocessing_start, multiprocessing_start) def init(): # Only continue if ancestor process has set everything needed in # the env. cov_source = os.environ.get('COV_CORE_SOURCE') cov_config = os.environ.get('COV_CORE_CONFIG') cov_datafile = os.environ.get('COV_CORE_DATAFILE') if cov_datafile: # Import what we need to activate coverage. import coverage # Determine all source roots. if not cov_source: cov_source = None else: cov_source = cov_source.split(os.pathsep) if not cov_config: cov_config = True # Activate coverage for this process. cov = coverage.coverage( source=cov_source, data_suffix=True, config_file=cov_config, auto_data=True, data_file=cov_datafile ) cov.load() cov.start() cov._warn_no_data = False cov._warn_unimported_source = False return cov pytest-cov-2.2.1/src/pytest_cov/engine.py000066400000000000000000000252561265235215400204550ustar00rootroot00000000000000"""Coverage controllers for use by pytest-cov and nose-cov.""" import os import random import socket import sys try: from StringIO import StringIO except ImportError: from io import StringIO import coverage from coverage.data import CoverageData class CovController(object): """Base class for different plugin implementations.""" def __init__(self, cov_source, cov_report, cov_config, cov_append, config=None, nodeid=None): """Get some common config used by multiple derived classes.""" self.cov_source = cov_source self.cov_report = cov_report self.cov_config = cov_config self.cov_append = cov_append self.config = config self.nodeid = nodeid self.cov = None self.node_descs = set() self.failed_slaves = [] self.topdir = os.getcwd() def set_env(self): """Put info about coverage into the env so that subprocesses can activate coverage.""" if self.cov_source is None: os.environ['COV_CORE_SOURCE'] = '' else: os.environ['COV_CORE_SOURCE'] = os.pathsep.join( os.path.abspath(p) for p in self.cov_source) config_file = os.path.abspath(self.cov_config) if os.path.exists(config_file): os.environ['COV_CORE_CONFIG'] = config_file else: os.environ['COV_CORE_CONFIG'] = '' os.environ['COV_CORE_DATAFILE'] = os.path.abspath('.coverage') @staticmethod def unset_env(): """Remove coverage info from env.""" os.environ.pop('COV_CORE_SOURCE', None) os.environ.pop('COV_CORE_CONFIG', None) os.environ.pop('COV_CORE_DATAFILE', None) @staticmethod def get_node_desc(platform, version_info): """Return a description of this node.""" return 'platform %s, python %s' % (platform, '%s.%s.%s-%s-%s' % version_info[:5]) @staticmethod def sep(stream, s, txt): if hasattr(stream, 'sep'): stream.sep(s, txt) else: sep_total = max((70 - 2 - len(txt)), 2) sep_len = sep_total // 2 sep_extra = sep_total % 2 out = '%s %s %s\n' % (s * sep_len, txt, s * (sep_len + sep_extra)) stream.write(out) def summary(self, stream): """Produce coverage reports.""" total = 0 if not self.cov_report: with open(os.devnull, 'w') as null: total = self.cov.report(show_missing=True, ignore_errors=True, file=null) return total # Output coverage section header. if len(self.node_descs) == 1: self.sep(stream, '-', 'coverage: %s' % ''.join(self.node_descs)) else: self.sep(stream, '-', 'coverage') for node_desc in sorted(self.node_descs): self.sep(stream, ' ', '%s' % node_desc) # Produce terminal report if wanted. if 'term' in self.cov_report or 'term-missing' in self.cov_report: show_missing = ('term-missing' in self.cov_report) or None total = self.cov.report(show_missing=show_missing, ignore_errors=True, file=stream) # Produce annotated source code report if wanted. if 'annotate' in self.cov_report: self.cov.annotate(ignore_errors=True) # We need to call Coverage.report here, just to get the total # Coverage.annotate don't return any total and we need it for --cov-fail-under. total = self.cov.report(ignore_errors=True, file=StringIO()) stream.write('Coverage annotated source written next to source\n') # Produce html report if wanted. if 'html' in self.cov_report: total = self.cov.html_report(ignore_errors=True) stream.write('Coverage HTML written to dir %s\n' % self.cov.config.html_dir) # Produce xml report if wanted. if 'xml' in self.cov_report: total = self.cov.xml_report(ignore_errors=True) stream.write('Coverage XML written to file %s\n' % self.cov.config.xml_output) # Report on any failed slaves. if self.failed_slaves: self.sep(stream, '-', 'coverage: failed slaves') stream.write('The following slaves failed to return coverage data, ' 'ensure that pytest-cov is installed on these slaves.\n') for node in self.failed_slaves: stream.write('%s\n' % node.gateway.id) return total class Central(CovController): """Implementation for centralised operation.""" def start(self): """Erase any previous coverage data and start coverage.""" self.cov = coverage.coverage(source=self.cov_source, config_file=self.cov_config) if self.cov_append: self.cov.load() else: self.cov.erase() self.cov.start() self.set_env() def finish(self): """Stop coverage, save data to file and set the list of coverage objects to report on.""" self.unset_env() self.cov.stop() self.cov.combine() self.cov.save() node_desc = self.get_node_desc(sys.platform, sys.version_info) self.node_descs.add(node_desc) class DistMaster(CovController): """Implementation for distributed master.""" def start(self): """Ensure coverage rc file rsynced if appropriate.""" if self.cov_config and os.path.exists(self.cov_config): self.config.option.rsyncdir.append(self.cov_config) self.cov = coverage.coverage(source=self.cov_source, config_file=self.cov_config) if self.cov_append: self.cov.load() else: self.cov.erase() self.cov.start() self.cov.config.paths['source'] = [self.topdir] def configure_node(self, node): """Slaves need to know if they are collocated and what files have moved.""" node.slaveinput['cov_master_host'] = socket.gethostname() node.slaveinput['cov_master_topdir'] = self.topdir node.slaveinput['cov_master_rsync_roots'] = [str(root) for root in node.nodemanager.roots] def testnodedown(self, node, error): """Collect data file name from slave.""" # If slave doesn't return any data then it is likely that this # plugin didn't get activated on the slave side. if not (hasattr(node, 'slaveoutput') and 'cov_slave_node_id' in node.slaveoutput): self.failed_slaves.append(node) return # If slave is not collocated then we must save the data file # that it returns to us. if 'cov_slave_data' in node.slaveoutput: data_suffix = '%s.%s.%06d.%s' % ( socket.gethostname(), os.getpid(), random.randint(0, 999999), node.slaveoutput['cov_slave_node_id'] ) cov = coverage.coverage(source=self.cov_source, data_suffix=data_suffix, config_file=self.cov_config) cov.start() if hasattr(self.cov.data, 'read_fileobj'): # for coverage 4.0 data = CoverageData() data.read_fileobj(StringIO(node.slaveoutput['cov_slave_data'])) cov.data.update(data) else: cov.data.lines, cov.data.arcs = node.slaveoutput['cov_slave_data'] cov.stop() cov.save() path = node.slaveoutput['cov_slave_path'] self.cov.config.paths['source'].append(path) # Record the slave types that contribute to the data file. rinfo = node.gateway._rinfo() node_desc = self.get_node_desc(rinfo.platform, rinfo.version_info) self.node_descs.add(node_desc) def finish(self): """Combines coverage data and sets the list of coverage objects to report on.""" # Combine all the suffix files into the data file. self.cov.stop() self.cov.combine() self.cov.save() class DistSlave(CovController): """Implementation for distributed slaves.""" def start(self): """Determine what data file and suffix to contribute to and start coverage.""" # Determine whether we are collocated with master. self.is_collocated = (socket.gethostname() == self.config.slaveinput['cov_master_host'] and self.topdir == self.config.slaveinput['cov_master_topdir']) # If we are not collocated then rewrite master paths to slave paths. if not self.is_collocated: master_topdir = self.config.slaveinput['cov_master_topdir'] slave_topdir = self.topdir self.cov_source = [source.replace(master_topdir, slave_topdir) for source in self.cov_source] self.cov_config = self.cov_config.replace(master_topdir, slave_topdir) # Erase any previous data and start coverage. self.cov = coverage.coverage(source=self.cov_source, data_suffix=True, config_file=self.cov_config) if self.cov_append: self.cov.load() else: self.cov.erase() self.cov.start() self.set_env() def finish(self): """Stop coverage and send relevant info back to the master.""" self.unset_env() self.cov.stop() if self.is_collocated: # We don't combine data if we're collocated - we can get # race conditions in the .combine() call (it's not atomic) # The data is going to be combined in the master. self.cov.save() # If we are collocated then just inform the master of our # data file to indicate that we have finished. self.config.slaveoutput['cov_slave_node_id'] = self.nodeid else: self.cov.combine() self.cov.save() # If we are not collocated then add the current path # and coverage data to the output so we can combine # it on the master node. # Send all the data to the master over the channel. self.config.slaveoutput['cov_slave_path'] = self.topdir self.config.slaveoutput['cov_slave_node_id'] = self.nodeid if hasattr(self.cov.data, 'write_fileobj'): # for coverage 4.0 buff = StringIO() self.cov.data.write_fileobj(buff) self.config.slaveoutput['cov_slave_data'] = buff.getvalue() else: self.config.slaveoutput['cov_slave_data'] = self.cov.data.lines, self.cov.data.arcs def summary(self, stream): """Only the master reports so do nothing.""" pass pytest-cov-2.2.1/src/pytest_cov/plugin.py000066400000000000000000000164451265235215400205060ustar00rootroot00000000000000"""Coverage plugin for pytest.""" import os import pytest from coverage.misc import CoverageException from . import embed from . import engine class CoverageError(Exception): """Indicates that our coverage is too low""" def pytest_addoption(parser): """Add options to control coverage.""" group = parser.getgroup( 'cov', 'coverage reporting with distributed testing support') group.addoption('--cov', action='append', default=[], metavar='path', nargs='?', const=True, dest='cov_source', help='measure coverage for filesystem path ' '(multi-allowed)') group.addoption('--cov-report', action='append', default=[], metavar='type', choices=['term', 'term-missing', 'annotate', 'html', 'xml', ''], help='type of report to generate: term, term-missing, ' 'annotate, html, xml (multi-allowed)') group.addoption('--cov-config', action='store', default='.coveragerc', metavar='path', help='config file for coverage, default: .coveragerc') group.addoption('--no-cov-on-fail', action='store_true', default=False, help='do not report coverage if test run fails, ' 'default: False') group.addoption('--cov-fail-under', action='store', metavar='MIN', type='int', help='Fail if the total coverage is less than MIN.') group.addoption('--cov-append', action='store_true', default=False, help='do not delete coverage but append to current, ' 'default: False') @pytest.mark.tryfirst def pytest_load_initial_conftests(early_config, parser, args): ns = parser.parse_known_args(args) ns.cov = bool(ns.cov_source) if ns.cov_source == [True]: ns.cov_source = None if not ns.cov_report: ns.cov_report = ['term'] elif ns.cov_report == ['']: ns.cov_report = [] if ns.cov: plugin = CovPlugin(ns, early_config.pluginmanager) early_config.pluginmanager.register(plugin, '_cov') def pytest_configure(config): """Activate coverage plugin if appropriate.""" if config.getvalue('cov_source'): if not config.pluginmanager.hasplugin('_cov'): if not config.option.cov_report: config.option.cov_report = ['term'] plugin = CovPlugin(config.option, config.pluginmanager, start=False) config.pluginmanager.register(plugin, '_cov') class CovPlugin(object): """Use coverage package to produce code coverage reports. Delegates all work to a particular implementation based on whether this test process is centralised, a distributed master or a distributed slave. """ def __init__(self, options, pluginmanager, start=True): """Creates a coverage pytest plugin. We read the rc file that coverage uses to get the data file name. This is needed since we give coverage through it's API the data file name. """ # Our implementation is unknown at this time. self.pid = None self.cov = None self.cov_controller = None self.failed = False self._started = False self.options = options is_dist = (getattr(options, 'numprocesses', False) or getattr(options, 'distload', False) or getattr(options, 'dist', 'no') != 'no') if is_dist and start: self.start(engine.DistMaster) elif start: self.start(engine.Central) # slave is started in pytest hook def start(self, controller_cls, config=None, nodeid=None): if config is None: # fake config option for engine class Config(object): option = self.options config = Config() self.cov_controller = controller_cls( self.options.cov_source, self.options.cov_report, self.options.cov_config, self.options.cov_append, config, nodeid ) self.cov_controller.start() self._started = True cov_config = self.cov_controller.cov.config if self.options.cov_fail_under is None and hasattr(cov_config, 'fail_under'): self.options.cov_fail_under = cov_config.fail_under def pytest_sessionstart(self, session): """At session start determine our implementation and delegate to it.""" self.pid = os.getpid() is_slave = hasattr(session.config, 'slaveinput') if is_slave: nodeid = session.config.slaveinput.get('slaveid', getattr(session, 'nodeid')) self.start(engine.DistSlave, session.config, nodeid) elif not self._started: self.start(engine.Central) def pytest_configure_node(self, node): """Delegate to our implementation. Mark this hook as optional in case xdist is not installed. """ self.cov_controller.configure_node(node) pytest_configure_node.optionalhook = True def pytest_testnodedown(self, node, error): """Delegate to our implementation. Mark this hook as optional in case xdist is not installed. """ self.cov_controller.testnodedown(node, error) pytest_testnodedown.optionalhook = True def pytest_sessionfinish(self, session, exitstatus): """Delegate to our implementation.""" self.failed = exitstatus != 0 if self.cov_controller is not None: self.cov_controller.finish() def pytest_terminal_summary(self, terminalreporter): """Delegate to our implementation.""" if self.cov_controller is None: return if not (self.failed and self.options.no_cov_on_fail): try: total = self.cov_controller.summary(terminalreporter.writer) except CoverageException as exc: terminalreporter.writer.write('Failed to generate report: %s\n' % exc) total = 0 assert total is not None, 'Test coverage should never be `None`' cov_fail_under = self.options.cov_fail_under if cov_fail_under is not None and total < cov_fail_under: raise CoverageError(('Required test coverage of %d%% not ' 'reached. Total coverage: %.2f%%') % (self.options.cov_fail_under, total)) def pytest_runtest_setup(self, item): if os.getpid() != self.pid: # test is run in another process than session, run # coverage manually self.cov = embed.init() def pytest_runtest_teardown(self, item): if self.cov is not None: embed.multiprocessing_finish(self.cov) self.cov = None def pytest_funcarg__cov(request): """A pytest funcarg that provides access to the underlying coverage object. """ # Check with hasplugin to avoid getplugin exception in older pytest. if request.config.pluginmanager.hasplugin('_cov'): plugin = request.config.pluginmanager.getplugin('_cov') if plugin.cov_controller: return plugin.cov_controller.cov return None pytest-cov-2.2.1/tests/000077500000000000000000000000001265235215400150005ustar00rootroot00000000000000pytest-cov-2.2.1/tests/conftest.py000066400000000000000000000001111265235215400171700ustar00rootroot00000000000000def pytest_configure(config): config.option.runpytest = 'subprocess' pytest-cov-2.2.1/tests/helper.py000066400000000000000000000000471265235215400166320ustar00rootroot00000000000000def do_stuff(): a = 1 return a pytest-cov-2.2.1/tests/test_pytest_cov.py000066400000000000000000000611271265235215400206170ustar00rootroot00000000000000import glob import os import subprocess import sys from distutils.version import StrictVersion import coverage import py import pytest import virtualenv from process_tests import TestProcess from process_tests import dump_on_error from process_tests import wait_for_strings import pytest_cov.plugin coverage, StrictVersion # required for skipif mark on test_cov_min_from_coveragerc SCRIPT = ''' import sys, helper def pytest_generate_tests(metafunc): for i in range(10): metafunc.addcall() def test_foo(): x = True helper.do_stuff() # get some coverage in some other completely different location if sys.version_info[0] > 5: assert False ''' SCRIPT2 = ''' # def test_bar(): x = True assert x ''' COVERAGERC_SOURCE = '''\ [run] source = . ''' SCRIPT_CHILD = ''' import sys idx = int(sys.argv[1]) if idx == 0: foo = "a" # previously there was a "pass" here but Python 3.5 optimizes it away. if idx == 1: foo = "b" # previously there was a "pass" here but Python 3.5 optimizes it away. ''' SCRIPT_PARENT = ''' import subprocess import sys def pytest_generate_tests(metafunc): for i in range(2): metafunc.addcall(funcargs=dict(idx=i)) def test_foo(idx): out, err = subprocess.Popen( [sys.executable, 'child_script.py', str(idx)], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() # there is a issue in coverage.py with multiline statements at # end of file: https://bitbucket.org/ned/coveragepy/issue/293 pass ''' SCRIPT_PARENT_CHANGE_CWD = ''' import subprocess import sys import os def pytest_generate_tests(metafunc): for i in range(2): metafunc.addcall(funcargs=dict(idx=i)) def test_foo(idx): os.mkdir("foobar") os.chdir("foobar") subprocess.check_call([ sys.executable, os.path.join(os.path.dirname(__file__), 'child_script.py'), str(idx) ]) # there is a issue in coverage.py with multiline statements at # end of file: https://bitbucket.org/ned/coveragepy/issue/293 pass ''' SCRIPT_FUNCARG = ''' import coverage def test_foo(cov): assert isinstance(cov, coverage.coverage) ''' SCRIPT_FUNCARG_NOT_ACTIVE = ''' def test_foo(cov): assert cov is None ''' MULTIPROCESSING_SCRIPT = ''' import multiprocessing def target_fn(): a = True return a def test_run_target(): p = multiprocessing.Process(target=target_fn) p.start() p.join() ''' SCRIPT_FAIL = ''' def test_fail(): assert False ''' SCRIPT_RESULT = '9 * 89%' SCRIPT2_RESULT = '3 * 100%' CHILD_SCRIPT_RESULT = '[56] * 100%' PARENT_SCRIPT_RESULT = '8 * 100%' xdist = pytest.mark.parametrize('opts', ['', '-n 1'], ids=['nodist', 'xdist']) def test_central(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--cov-report=term-missing', script) result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', 'test_central* %s *' % SCRIPT_RESULT, '*10 passed*' ]) assert result.ret == 0 def test_annotate(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--cov-report=annotate', script) result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', 'Coverage annotated source written next to source', '*10 passed*', ]) assert result.ret == 0 def test_cov_min_100(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--cov-report=term-missing', '--cov-fail-under=100', script) assert result.ret != 0 def test_cov_min_50(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--cov-report=term-missing', '--cov-fail-under=50', script) assert result.ret == 0 def test_cov_min_no_report(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--cov-report=', '--cov-fail-under=50', script) assert result.ret == 0 def test_central_nonspecific(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', '--cov', '--cov-report=term-missing', script) result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', 'test_central_nonspecific* %s *' % SCRIPT_RESULT, '*10 passed*' ]) # multi-module coverage report assert any(line.startswith('TOTAL ') for line in result.stdout.lines[-4:]) assert result.ret == 0 @pytest.mark.skipif('StrictVersion(coverage.__version__) <= StrictVersion("3.8")') def test_cov_min_from_coveragerc(testdir): script = testdir.makepyfile(SCRIPT) testdir.tmpdir.join('.coveragerc').write(""" [report] fail_under = 100 """) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--cov-report=term-missing', script) assert result.ret != 0 def test_central_coveragerc(testdir): script = testdir.makepyfile(SCRIPT) testdir.tmpdir.join('.coveragerc').write(COVERAGERC_SOURCE) result = testdir.runpytest('-v', '--cov', '--cov-report=term-missing', script) result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', 'test_central_coveragerc* %s *' % SCRIPT_RESULT, '*10 passed*', ]) # single-module coverage report assert all(not line.startswith('TOTAL ') for line in result.stdout.lines[-4:]) assert result.ret == 0 def test_show_missing_coveragerc(testdir): script = testdir.makepyfile(SCRIPT) testdir.tmpdir.join('.coveragerc').write(""" [run] source = . [report] show_missing = true """) result = testdir.runpytest('-v', '--cov', '--cov-report=term', script) result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', 'Name * Stmts * Miss * Cover * Missing', 'test_show_missing_coveragerc* %s * 11' % SCRIPT_RESULT, '*10 passed*', ]) # single-module coverage report assert all(not line.startswith('TOTAL ') for line in result.stdout.lines[-4:]) assert result.ret == 0 def test_no_cov_on_fail(testdir): script = testdir.makepyfile(SCRIPT_FAIL) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--cov-report=term-missing', '--no-cov-on-fail', script) assert 'coverage: platform' not in result.stdout.str() result.stdout.fnmatch_lines(['*1 failed*']) def test_dist_combine_racecondition(testdir): script = testdir.makepyfile(""" import pytest @pytest.mark.parametrize("foo", range(1000)) def test_foo(foo): """ + "\n".join(""" if foo == %s: assert True """ % i for i in range(1000))) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--cov-report=term-missing', '-n', '5', script) result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', 'test_dist_combine_racecondition* 2002 * 0 * 100%*', '*1000 passed*' ]) for line in result.stdout.lines: assert 'The following slaves failed to return coverage data' not in line assert result.ret == 0 def test_dist_collocated(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--cov-report=term-missing', '--dist=load', '--tx=2*popen', '--max-slave-restart=0', script) result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', 'test_dist_collocated* %s *' % SCRIPT_RESULT, '*10 passed*' ]) assert result.ret == 0 def test_dist_not_collocated(testdir): script = testdir.makepyfile(SCRIPT) dir1 = testdir.mkdir('dir1') dir2 = testdir.mkdir('dir2') result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--cov-report=term-missing', '--dist=load', '--tx=popen//chdir=%s' % dir1, '--tx=popen//chdir=%s' % dir2, '--rsyncdir=%s' % script.basename, '--max-slave-restart=0', '-s', script) result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', 'test_dist_not_collocated* %s *' % SCRIPT_RESULT, '*10 passed*' ]) assert result.ret == 0 def test_central_subprocess(testdir): scripts = testdir.makepyfile(parent_script=SCRIPT_PARENT, child_script=SCRIPT_CHILD) parent_script = scripts.dirpath().join('parent_script.py') result = testdir.runpytest('-v', '--cov=%s' % scripts.dirpath(), '--cov-report=term-missing', parent_script) result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', 'child_script* %s*' % CHILD_SCRIPT_RESULT, 'parent_script* %s*' % PARENT_SCRIPT_RESULT, ]) assert result.ret == 0 def test_central_subprocess_change_cwd(testdir): scripts = testdir.makepyfile(parent_script=SCRIPT_PARENT_CHANGE_CWD, child_script=SCRIPT_CHILD) parent_script = scripts.dirpath().join('parent_script.py') testdir.makefile('', coveragerc=""" [run] branch = true parallel = true """) result = testdir.runpytest('-v', '-s', '--cov=%s' % scripts.dirpath(), '--cov-config=coveragerc', '--cov-report=term-missing', parent_script) result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', 'child_script* %s*' % CHILD_SCRIPT_RESULT, 'parent_script* 100%*', ]) assert result.ret == 0 def test_central_subprocess_no_subscript(testdir): script = testdir.makepyfile(""" import subprocess, sys def test_foo(): subprocess.check_call([sys.executable, '-c', 'print("Hello World")']) """) testdir.makefile('', coveragerc=""" [run] branch = true parallel = true omit = */__init__.py """) result = testdir.runpytest('-v', '--cov-config=coveragerc', '--cov=%s' % script.dirpath(), script) result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', 'test_central_subprocess_no_subscript* * 3 * 0 * 100%*', ]) assert result.ret == 0 def test_dist_subprocess_collocated(testdir): scripts = testdir.makepyfile(parent_script=SCRIPT_PARENT, child_script=SCRIPT_CHILD) parent_script = scripts.dirpath().join('parent_script.py') result = testdir.runpytest('-v', '--cov=%s' % scripts.dirpath(), '--cov-report=term-missing', '--dist=load', '--tx=2*popen', '--max-slave-restart=0', parent_script) result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', 'child_script* %s*' % CHILD_SCRIPT_RESULT, 'parent_script* %s*' % PARENT_SCRIPT_RESULT, ]) assert result.ret == 0 def test_dist_subprocess_not_collocated(testdir, tmpdir): scripts = testdir.makepyfile(parent_script=SCRIPT_PARENT, child_script=SCRIPT_CHILD) parent_script = scripts.dirpath().join('parent_script.py') child_script = scripts.dirpath().join('child_script.py') dir1 = tmpdir.mkdir('dir1') dir2 = tmpdir.mkdir('dir2') result = testdir.runpytest('-v', '--cov=%s' % scripts.dirpath(), '--cov-report=term-missing', '--dist=load', '--tx=popen//chdir=%s' % dir1, '--tx=popen//chdir=%s' % dir2, '--rsyncdir=%s' % child_script, '--rsyncdir=%s' % parent_script, '--max-slave-restart=0', parent_script) result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', 'child_script* %s*' % CHILD_SCRIPT_RESULT, 'parent_script* %s*' % PARENT_SCRIPT_RESULT, ]) assert result.ret == 0 def test_empty_report(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', '--cov=non_existent_module', '--cov-report=term-missing', script) result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', '*10 passed*' ]) assert result.ret == 0 matching_lines = [line for line in result.outlines if '%' in line] assert not matching_lines def test_dist_missing_data(testdir): venv_path = os.path.join(str(testdir.tmpdir), 'venv') virtualenv.create_environment(venv_path) if sys.platform == 'win32': exe = os.path.join(venv_path, 'Scripts', 'python.exe') else: exe = os.path.join(venv_path, 'bin', 'python') subprocess.check_call([ exe, '-mpip' if sys.version_info >= (2, 7) else '-mpip.__main__', 'install', 'py==%s' % py.__version__, 'pytest==%s' % pytest.__version__ ]) script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--cov-report=term-missing', '--dist=load', '--tx=popen//python=%s' % exe, '--max-slave-restart=0', script) result.stdout.fnmatch_lines([ '*- coverage: failed slaves -*' ]) assert result.ret == 0 def test_funcarg(testdir): script = testdir.makepyfile(SCRIPT_FUNCARG) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--cov-report=term-missing', script) result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', 'test_funcarg* 3 * 100%*', '*1 passed*' ]) assert result.ret == 0 def test_funcarg_not_active(testdir): script = testdir.makepyfile(SCRIPT_FUNCARG_NOT_ACTIVE) result = testdir.runpytest('-v', script) result.stdout.fnmatch_lines([ '*1 passed*' ]) assert result.ret == 0 def test_multiprocessing_subprocess(testdir): py.test.importorskip('multiprocessing.util') script = testdir.makepyfile(MULTIPROCESSING_SCRIPT) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--cov-report=term-missing', script) result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', 'test_multiprocessing_subprocess* 8 * 100%*', '*1 passed*' ]) assert result.ret == 0 MODULE = ''' def func(): return 1 ''' CONFTEST = ''' import mod mod.func() ''' BASIC_TEST = ''' def test_basic(): x = True assert x ''' CONF_RESULT = 'mod* 2 * 100%*' def test_cover_conftest(testdir): testdir.makepyfile(mod=MODULE) testdir.makeconftest(CONFTEST) script = testdir.makepyfile(BASIC_TEST) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--cov-report=term-missing', script) assert result.ret == 0 result.stdout.fnmatch_lines([CONF_RESULT]) def test_cover_looponfail(testdir, monkeypatch): testdir.makepyfile(mod=MODULE) testdir.makeconftest(CONFTEST) script = testdir.makepyfile(BASIC_TEST) monkeypatch.setattr(testdir, 'run', lambda *args: TestProcess(*map(str, args))) with testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--looponfail', script) as process: with dump_on_error(process.read): wait_for_strings( process.read, 30, # 30 seconds 'Stmts Miss Cover' ) def test_cover_conftest_dist(testdir): testdir.makepyfile(mod=MODULE) testdir.makeconftest(CONFTEST) script = testdir.makepyfile(BASIC_TEST) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--cov-report=term-missing', '--dist=load', '--tx=2*popen', '--max-slave-restart=0', script) assert result.ret == 0 result.stdout.fnmatch_lines([CONF_RESULT]) COVERAGERC = ''' [report] # Regexes for lines to exclude from consideration exclude_lines = raise NotImplementedError ''' EXCLUDED_TEST = ''' def func(): raise NotImplementedError def test_basic(): x = True assert x ''' EXCLUDED_RESULT = '4 * 100%*' def test_coveragerc(testdir): testdir.makefile('', coveragerc=COVERAGERC) script = testdir.makepyfile(EXCLUDED_TEST) result = testdir.runpytest('-v', '--cov-config=coveragerc', '--cov=%s' % script.dirpath(), '--cov-report=term-missing', script) assert result.ret == 0 result.stdout.fnmatch_lines(['test_coveragerc* %s' % EXCLUDED_RESULT]) def test_coveragerc_dist(testdir): testdir.makefile('', coveragerc=COVERAGERC) script = testdir.makepyfile(EXCLUDED_TEST) result = testdir.runpytest('-v', '--cov-config=coveragerc', '--cov=%s' % script.dirpath(), '--cov-report=term-missing', '-n', '2', '--max-slave-restart=0', script) assert result.ret == 0 result.stdout.fnmatch_lines( ['test_coveragerc_dist* %s' % EXCLUDED_RESULT]) CLEAR_ENVIRON_TEST = ''' import os def test_basic(): os.environ.clear() ''' def test_clear_environ(testdir): script = testdir.makepyfile(CLEAR_ENVIRON_TEST) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--cov-report=term-missing', script) assert result.ret == 0 SCRIPT_SIMPLE = ''' def test_foo(): assert 1 == 1 x = True assert x ''' SCRIPT_SIMPLE_RESULT = '4 * 100%' @pytest.mark.skipif('sys.platform == "win32"') def test_dist_boxed(testdir): script = testdir.makepyfile(SCRIPT_SIMPLE) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--boxed', script) result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', 'test_dist_boxed* %s*' % SCRIPT_SIMPLE_RESULT, '*1 passed*' ]) assert result.ret == 0 def test_not_started_plugin_does_not_fail(testdir): plugin = pytest_cov.plugin.CovPlugin(None, None, start=False) plugin.pytest_sessionfinish(None, None) plugin.pytest_terminal_summary(None) def test_default_output_setting(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), script) result.stdout.fnmatch_lines([ '*coverage*' ]) assert result.ret == 0 def test_disabled_output(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--cov-report=', script) assert 'coverage' not in result.stdout.str() assert result.ret == 0 def test_coverage_file(testdir): script = testdir.makepyfile(SCRIPT) data_file_name = 'covdata' os.environ['COVERAGE_FILE'] = data_file_name try: result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), script) assert result.ret == 0 data_file = testdir.tmpdir.join(data_file_name) assert data_file.check() finally: os.environ.pop('COVERAGE_FILE') def test_external_data_file(testdir): script = testdir.makepyfile(SCRIPT) testdir.tmpdir.join('.coveragerc').write(""" [run] data_file = %s """ % testdir.tmpdir.join('some/special/place/coverage-data').ensure()) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), script) assert result.ret == 0 assert glob.glob(str(testdir.tmpdir.join('some/special/place/coverage-data*'))) def test_external_data_file_xdist(testdir): script = testdir.makepyfile(SCRIPT) testdir.tmpdir.join('.coveragerc').write(""" [run] parallel = true data_file = %s """ % testdir.tmpdir.join('some/special/place/coverage-data').ensure()) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '-n', '1', '--max-slave-restart=0', script) assert result.ret == 0 assert glob.glob(str(testdir.tmpdir.join('some/special/place/coverage-data*'))) def test_external_data_file_negative(testdir): script = testdir.makepyfile(SCRIPT) testdir.tmpdir.join('.coveragerc').write("") result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), script) assert result.ret == 0 assert glob.glob(str(testdir.tmpdir.join('.coverage*'))) @xdist def test_append_coverage(testdir, opts): script = testdir.makepyfile(test_1=SCRIPT) testdir.tmpdir.join('.coveragerc').write("") result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), script, *opts.split()) result.stdout.fnmatch_lines([ 'test_1* %s*' % SCRIPT_RESULT, ]) script2 = testdir.makepyfile(test_2=SCRIPT2) result = testdir.runpytest('-v', '--cov-append', '--cov=%s' % script2.dirpath(), script2, *opts.split()) result.stdout.fnmatch_lines([ 'test_1* %s*' % SCRIPT_RESULT, 'test_2* %s*' % SCRIPT2_RESULT, ]) @xdist def test_do_not_append_coverage(testdir, opts): script = testdir.makepyfile(test_1=SCRIPT) testdir.tmpdir.join('.coveragerc').write("") result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), script, *opts.split()) result.stdout.fnmatch_lines([ 'test_1* %s*' % SCRIPT_RESULT, ]) script2 = testdir.makepyfile(test_2=SCRIPT2) result = testdir.runpytest('-v', '--cov=%s' % script2.dirpath(), script2, *opts.split()) result.stdout.fnmatch_lines([ 'test_1* 0%', 'test_2* %s*' % SCRIPT2_RESULT, ]) pytest-cov-2.2.1/tox.ini000066400000000000000000000030061265235215400151500ustar00rootroot00000000000000; a generative tox configuration, see: https://testrun.org/tox/latest/config.html#generative-envlist [tox] envlist = check, {py26,py27,py33,py34,py35,pypy}-{27,28}-{37,40,41}, docs [testenv] basepython = pypy: pypy py26: {env:TOXPYTHON:python2.6} {py27,docs}: {env:TOXPYTHON:python2.7} py33: {env:TOXPYTHON:python3.3} py34: {env:TOXPYTHON:python3.4} py35: {env:TOXPYTHON:python3.5} {clean,check,report,extension-coveralls,coveralls,spell}: python3.4 setenv = PYTHONPATH={toxinidir}/tests PYTHONUNBUFFERED=yes passenv = * deps = 27: pytest==2.7.3 28: pytest==2.8.5 pytest-capturelog 37: coverage==3.7.1 40: coverage==4.0.3 41: coverage==4.1b2 virtualenv pytest-xdist==1.13.1 27: pytest-cache==1.0.0 process-tests==1.2.0 pip_pre = true commands = {posargs:py.test -vv} [testenv:spell] setenv = SPELLCHECK=1 commands = sphinx-build -b spelling docs dist/docs skip_install = true usedevelop = false deps = -r{toxinidir}/docs/requirements.txt sphinxcontrib-spelling pyenchant [testenv:docs] deps = -r{toxinidir}/docs/requirements.txt commands = sphinx-build {posargs:-E} -b html docs dist/docs sphinx-build -b linkcheck docs dist/docs [testenv:check] deps = docutils check-manifest flake8 readme-renderer pygments skip_install = true usedevelop = false commands = python setup.py check --strict --metadata --restructuredtext check-manifest {toxinidir} flake8 src tests setup.py