Commits

Meme Dough  committed 15aeada Merge

Merge completed work on command line options, subprocesses.

  • Participants
  • Parent commits a15a73e, 4e564a3
  • Tags RELEASE_1_0

Comments (0)

Files changed (5)

File MANIFEST.in

File contents unchanged.
 pytest-cov
 ==========
 
-This plugin produces coverage reports using the coverage package.  It
-supports centralised testing and distributed testing in both load and
-each modes.
+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 this plugin or through coverage's own config file.
+All features offered by the coverage package should be available, either through pytest-cov or
+through coverage's config file.
 
 
 Installation
 ------------
 
-The `pytest-cov pypi`_ package may be installed / uninstalled with pip::
+The `pytest-cov`_ package may be installed with pip or easy_install::
 
     pip install pytest-cov
+    easy_install pytest-cov
+
+.. _`pytest-cov`: http://pypi.python.org/pypi/pytest-cov/
+
+
+Uninstallation
+--------------
+
+Uninstalling packages is supported by pip::
+
     pip uninstall pytest-cov
 
-Alternatively easy_install can be used::
+However easy_install does not provide an uninstall facility.
 
-    easy_install pytest-cov
+.. IMPORTANT::
 
-.. _`pytest-cov pypi`: http://pypi.python.org/pypi/pytest-cov/
+    Ensure that you manually delete the init_cov_core.pth file in your site-packages directory.
+
+    This file starts coverage collection of subprocesses if appropriate during site initialisation
+    at python startup.
 
 
 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   Exec  Cover   Missing
-    --------------------------------------------------
-    myproj/__init__          2      2   100%
-    myproj/myproj          257    244    94%   24-26, 99, 149, 233-236, 297-298, 369-370
-    myproj/feature4286      94     87    92%   183-188, 197
-    --------------------------------------------------
-    TOTAL                  353    333    94%
+    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
-~~~~~~~~~~~~~~~~~~~
+Distributed Testing: Load
+~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Distributed testing with dist mode set to 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/
 
-The results from the slaves will be combined like so::
+Shows a terminal report::
 
     -------------------- coverage: platform linux2, python 2.6.4-final-0 ---------------------
-    Name                 Stmts   Exec  Cover   Missing
-    --------------------------------------------------
-    myproj/__init__          2      2   100%
-    myproj/myproj          257    244    94%   24-26, 99, 149, 233-236, 297-298, 369-370
-    myproj/feature4286      94     87    92%   183-188, 197
-    --------------------------------------------------
-    TOTAL                  353    333    94%
+    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 in each mode::
+Again but spread over different hosts and different directories::
 
-    py.test --cov myproj --dist=each
-            --tx=popen//python=/usr/local/python265/bin/python
-            --tx=popen//python=/usr/local/python27b1/bin/python
+    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/
 
-Will produce a report for each slave::
+Shows a terminal report::
 
-    -------------------- coverage: platform linux2, python 2.6.5-final-0 ---------------------
-    Name                 Stmts   Exec  Cover   Missing
-    --------------------------------------------------
-    myproj/__init__          2      2   100%
-    myproj/myproj          257    244    94%   24-26, 99, 149, 233-236, 297-298, 369-370
-    myproj/feature4286      94     87    92%   183-188, 197
-    --------------------------------------------------
-    TOTAL                  353    333    94%
-    --------------------- coverage: platform linux2, python 2.7.0-beta-1 ---------------------
-    Name                 Stmts   Exec  Cover   Missing
-    --------------------------------------------------
-    myproj/__init__          2      2   100%
-    myproj/myproj          257    244    94%   24-26, 99, 149, 233-236, 297-298, 369-370
-    myproj/feature4286      94     87    92%   183-188, 197
-    --------------------------------------------------
-    TOTAL                  353    333    94%
+    -------------------- 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 in each mode can also produce a single combined
-report.  This is useful to get coverage information spanning things
-such as all python versions::
+Distributed Testing: Each
+~~~~~~~~~~~~~~~~~~~~~~~~~
 
-    py.test --cov myproj --cov-combine-each --dist=each
-            --tx=popen//python=/usr/local/python265/bin/python
-            --tx=popen//python=/usr/local/python27b1/bin/python
+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/
 
-Which looks like::
+Shows a terminal report::
 
     ---------------------------------------- coverage ----------------------------------------
                               platform linux2, python 2.6.5-final-0
-                               platform linux2, python 2.7.0-beta-1
-    Name                 Stmts   Exec  Cover   Missing
-    --------------------------------------------------
-    myproj/__init__          2      2   100%
-    myproj/myproj          257    244    94%   24-26, 99, 149, 233-236, 297-298, 369-370
-    myproj/feature4286      94     87    92%   183-188, 197
-    --------------------------------------------------
-    TOTAL                  353    333    94%
+                              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
 ---------
 
-By default a terminal report is output.  This report can be disabled
-if desired, such as when results are going to a continuous integration
-system and the terminal output won't be seen.
+It is possible to generate any combination of the reports for a single test run.
 
-In addition and without rerunning tests it is possible to generate
-annotated source code, a html report and an xml report.
+The available reports are terminal (with or without missing line numbers shown), HTML, XML and
+annotated source code.
 
-The directories for annotated source code and html reports can be
-specified as can the file name for the xml report.
+The terminal report without line numbers (default)::
 
-Since testing often takes a non trivial amount of time at the end of
-testing any / all of the reports may be generated.
+    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%
+
+
+The remaining three reports output to files without showing anything on the terminal (useful for
+when the output is going to a continuous integration server)::
+
+    py.test --cov-report html --cov-report xml --cov-report annotate --cov myproj tests/
 
 
 Coverage Data File
 ------------------
 
-During testing there may be many data files with coverage data.  These
-will have unique suffixes and will be combined at the end of testing.
+The data file is erased at the beginning of testing to ensure clean data for each test run.
 
-Upon completion, for --dist=load (and also for --dist=each when the
---cov-combine-each option is used) there will only be one data file.
-
-For --dist=each there may be many data files where each one will have
-the platform / python version info appended to the name.
-
-These data files are left at the end of testing so that it is possible
-to use normal coverage tools to examine them.
-
-At the beginning of testing any data files that are about to be used
-will first be erased so ensure the data is clean for each test run.
-
-It is possible to set the name of the data file.  If needed the
-platform / python version will be appended automatically to this name.
-
-
-Coverage Config File
---------------------
-
-Coverage by default will read its own config file.  An alternative
-file name may be specified or reading config can be disabled entirely.
-
-Care has been taken to ensure that the coverage env vars and config
-file options work the same under this plugin as they do under coverage
-itself.
-
-Since options may be specified in different ways the order of
-precedence between pytest-cov and coverage from highest to lowest is:
-
-1. pytest command line
-2. pytest env var
-3. pytest conftest
-4. coverage env var
-5. coverage config file
-6. coverage default
+The data file is left at the end of testing so that it is possible to use normal coverage tools to
+examine it.
 
 
 Limitations
 -----------
 
-For distributed testing the slaves must have the pytest-cov package
-installed.  This is needed since the plugin must be registered through
-setuptools / distribute for pytest to start the plugin on the slave.
+For distributed testing the slaves must have the pytest-cov package installed.  This is needed since
+the plugin must be registered through setuptools / distribute 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
 
 Holger Krekel for pytest with its distributed testing support.
 
-Ned Batchelder for coverage and its ability to combine the coverage
-results of parallel runs.
+Ned Batchelder for coverage and its ability to combine the coverage results of parallel runs.
 
-Whilst this plugin has been built fresh from the ground up to support
-distributed testing 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 for
-pytest and nose respectively.
+Whilst this plugin has been built fresh from the ground up to support distributed testing 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 for pytest and nose respectively.
 
 No doubt others have contributed to these tools as well.

File pytest_cov.py

 """produce code coverage reports using the 'coverage' package, including support for distributed testing.
 
-This plugin produces coverage reports using the coverage package.  It
-supports centralised testing and distributed testing in both load and
-each modes.
+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 this plugin or through coverage's own config file.
+All features offered by the coverage package should be available, either through pytest-cov or
+through coverage's config file.
 
 
 Installation
 ------------
 
-The `pytest-cov pypi`_ package may be installed / uninstalled with pip::
+The `pytest-cov`_ package may be installed with pip or easy_install::
 
     pip install pytest-cov
+    easy_install pytest-cov
+
+.. _`pytest-cov`: http://pypi.python.org/pypi/pytest-cov/
+
+
+Uninstallation
+--------------
+
+Uninstalling packages is supported by pip::
+
     pip uninstall pytest-cov
 
-Alternatively easy_install can be used::
+However easy_install does not provide an uninstall facility.
 
-    easy_install pytest-cov
+.. IMPORTANT::
 
-.. _`pytest-cov pypi`: http://pypi.python.org/pypi/pytest-cov/
+    Ensure that you manually delete the init_cov_core.pth file in your site-packages directory.
+
+    This file starts coverage collection of subprocesses if appropriate during site initialisation
+    at python startup.
 
 
 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   Exec  Cover   Missing
-    --------------------------------------------------
-    myproj/__init__          2      2   100%
-    myproj/myproj          257    244    94%   24-26, 99, 149, 233-236, 297-298, 369-370
-    myproj/feature4286      94     87    92%   183-188, 197
-    --------------------------------------------------
-    TOTAL                  353    333    94%
+    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
-~~~~~~~~~~~~~~~~~~~
+Distributed Testing: Load
+~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Distributed testing with dist mode set to 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/
 
-The results from the slaves will be combined like so::
+Shows a terminal report::
 
     -------------------- coverage: platform linux2, python 2.6.4-final-0 ---------------------
-    Name                 Stmts   Exec  Cover   Missing
-    --------------------------------------------------
-    myproj/__init__          2      2   100%
-    myproj/myproj          257    244    94%   24-26, 99, 149, 233-236, 297-298, 369-370
-    myproj/feature4286      94     87    92%   183-188, 197
-    --------------------------------------------------
-    TOTAL                  353    333    94%
+    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 in each mode::
+Again but spread over different hosts and different directories::
 
-    py.test --cov myproj --dist=each
-            --tx=popen//python=/usr/local/python265/bin/python
-            --tx=popen//python=/usr/local/python27b1/bin/python
+    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/
 
-Will produce a report for each slave::
+Shows a terminal report::
 
-    -------------------- coverage: platform linux2, python 2.6.5-final-0 ---------------------
-    Name                 Stmts   Exec  Cover   Missing
-    --------------------------------------------------
-    myproj/__init__          2      2   100%
-    myproj/myproj          257    244    94%   24-26, 99, 149, 233-236, 297-298, 369-370
-    myproj/feature4286      94     87    92%   183-188, 197
-    --------------------------------------------------
-    TOTAL                  353    333    94%
-    --------------------- coverage: platform linux2, python 2.7.0-beta-1 ---------------------
-    Name                 Stmts   Exec  Cover   Missing
-    --------------------------------------------------
-    myproj/__init__          2      2   100%
-    myproj/myproj          257    244    94%   24-26, 99, 149, 233-236, 297-298, 369-370
-    myproj/feature4286      94     87    92%   183-188, 197
-    --------------------------------------------------
-    TOTAL                  353    333    94%
+    -------------------- 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 in each mode can also produce a single combined
-report.  This is useful to get coverage information spanning things
-such as all python versions::
+Distributed Testing: Each
+~~~~~~~~~~~~~~~~~~~~~~~~~
 
-    py.test --cov myproj --cov-combine-each --dist=each
-            --tx=popen//python=/usr/local/python265/bin/python
-            --tx=popen//python=/usr/local/python27b1/bin/python
+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/
 
-Which looks like::
+Shows a terminal report::
 
     ---------------------------------------- coverage ----------------------------------------
                               platform linux2, python 2.6.5-final-0
-                               platform linux2, python 2.7.0-beta-1
-    Name                 Stmts   Exec  Cover   Missing
-    --------------------------------------------------
-    myproj/__init__          2      2   100%
-    myproj/myproj          257    244    94%   24-26, 99, 149, 233-236, 297-298, 369-370
-    myproj/feature4286      94     87    92%   183-188, 197
-    --------------------------------------------------
-    TOTAL                  353    333    94%
+                              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
 ---------
 
-By default a terminal report is output.  This report can be disabled
-if desired, such as when results are going to a continuous integration
-system and the terminal output won't be seen.
+It is possible to generate any combination of the reports for a single test run.
 
-In addition and without rerunning tests it is possible to generate
-annotated source code, a html report and an xml report.
+The available reports are terminal (with or without missing line numbers shown), HTML, XML and
+annotated source code.
 
-The directories for annotated source code and html reports can be
-specified as can the file name for the xml report.
+The terminal report without line numbers (default)::
 
-Since testing often takes a non trivial amount of time at the end of
-testing any / all of the reports may be generated.
+    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%
+
+
+The remaining three reports output to files without showing anything on the terminal (useful for
+when the output is going to a continuous integration server)::
+
+    py.test --cov-report html --cov-report xml --cov-report annotate --cov myproj tests/
 
 
 Coverage Data File
 ------------------
 
-During testing there may be many data files with coverage data.  These
-will have unique suffixes and will be combined at the end of testing.
+The data file is erased at the beginning of testing to ensure clean data for each test run.
 
-Upon completion, for --dist=load (and also for --dist=each when the
---cov-combine-each option is used) there will only be one data file.
-
-For --dist=each there may be many data files where each one will have
-the platform / python version info appended to the name.
-
-These data files are left at the end of testing so that it is possible
-to use normal coverage tools to examine them.
-
-At the beginning of testing any data files that are about to be used
-will first be erased so ensure the data is clean for each test run.
-
-It is possible to set the name of the data file.  If needed the
-platform / python version will be appended automatically to this name.
-
-
-Coverage Config File
---------------------
-
-Coverage by default will read its own config file.  An alternative
-file name may be specified or reading config can be disabled entirely.
-
-Care has been taken to ensure that the coverage env vars and config
-file options work the same under this plugin as they do under coverage
-itself.
-
-Since options may be specified in different ways the order of
-precedence between pytest-cov and coverage from highest to lowest is:
-
-1. pytest command line
-2. pytest env var
-3. pytest conftest
-4. coverage env var
-5. coverage config file
-6. coverage default
+The data file is left at the end of testing so that it is possible to use normal coverage tools to
+examine it.
 
 
 Limitations
 -----------
 
-For distributed testing the slaves must have the pytest-cov package
-installed.  This is needed since the plugin must be registered through
-setuptools / distribute for pytest to start the plugin on the slave.
+For distributed testing the slaves must have the pytest-cov package installed.  This is needed since
+the plugin must be registered through setuptools / distribute 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
 
 Holger Krekel for pytest with its distributed testing support.
 
-Ned Batchelder for coverage and its ability to combine the coverage
-results of parallel runs.
+Ned Batchelder for coverage and its ability to combine the coverage results of parallel runs.
 
-Whilst this plugin has been built fresh from the ground up to support
-distributed testing 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 for
-pytest and nose respectively.
+Whilst this plugin has been built fresh from the ground up to support distributed testing 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 for pytest and nose respectively.
 
 No doubt others have contributed to these tools as well.
 """
 
-import coverage
-import socket
-import sys
-import os
-
-try:
-    import configparser
-except ImportError:
-    import ConfigParser as configparser
-
-try:
-    from functools import reduce
-except ImportError:
-    pass
+import cov_core
 
 def pytest_addoption(parser):
     """Add options to control coverage."""
 
     group = parser.getgroup('coverage reporting with distributed testing support')
-    group.addoption('--cov-on', action='store_true', default=False,
-                    dest='cov_on',
-                    help='enable coverage, only needed if not specifying any --cov options')
-    group.addoption('--cov', action='append', default=[], metavar='package',
-                    dest='cov_packages',
-                    help='collect coverage for the specified package (multi-allowed)')
-    group.addoption('--cov-no-terminal', action='store_false', default=True,
-                    dest='cov_terminal',
-                    help='disable printing a report on the terminal')
-    group.addoption('--cov-annotate', action='store_true', default=False,
-                    dest='cov_annotate',
-                    help='generate an annotated source code report')
-    group.addoption('--cov-html', action='store_true', default=False,
-                    dest='cov_html',
-                    help='generate a html report')
-    group.addoption('--cov-xml', action='store_true', default=False,
-                    dest='cov_xml',
-                    help='generate an xml report')
-    group.addoption('--cov-annotate-dir', action='store', default='coverage_annotate', metavar='dir',
-                    dest='cov_annotate_dir',
-                    help='directory for the annotate report, default: %default')
-    group.addoption('--cov-html-dir', action='store', default=None, metavar='dir',
-                    dest='cov_html_dir',
-                    help='directory for the html report, default: coverage_html')
-    group.addoption('--cov-xml-file', action='store', default=None, metavar='path',
-                    dest='cov_xml_file',
-                    help='file for the xml report, default: coverage.xml')
-    group.addoption('--cov-data-file', action='store', default=None, metavar='path',
-                    dest='cov_data_file',
-                    help='file containing coverage data, default: .coverage')
-    group.addoption('--cov-combine-each', action='store_true', default=False,
-                    dest='cov_combine_each',
-                    help='for dist=each mode produce a single combined report')
-    group.addoption('--cov-branch', action='store_true', default=None,
-                    dest='cov_branch',
-                    help='enable branch coverage')
-    group.addoption('--cov-pylib', action='store_true', default=None,
-                    dest='cov_pylib',
-                    help='enable python library coverage')
-    group.addoption('--cov-timid', action='store_true', default=None,
-                    dest='cov_timid',
-                    help='enable slower and simpler tracing')
-    group.addoption('--cov-no-missing-lines', action='store_false', default=True,
-                    dest='cov_show_missing',
-                    help='disable showing missing lines, only relevant to the terminal report')
-    group.addoption('--cov-no-missing-files', action='store_true', default=None,
-                    dest='cov_ignore_errors',
-                    help='disable showing message about missing source files')
-    group.addoption('--cov-omit', action='store', default=None, metavar='prefix1,prefix2,...',
-                    dest='cov_omit_prefixes',
-                    help='ignore files with these prefixes')
-    group.addoption('--cov-no-config', action='store_false', default=True,
+    group.addoption('--cov', action='append', default=[], metavar='path',
+                    dest='cov_source',
+                    help='measure coverage for path (multi-allowed)')
+    group.addoption('--cov-report', action='append', default=[], metavar='type',
+                    choices=['term', 'term-missing', 'annotate', 'html', 'xml'],
+                    dest='cov_report',
+                    help='type of report to generate: term, term-missing, annotate, html, xml (multi-allowed)')
+    group.addoption('--cov-config', action='store', default='.coveragerc', metavar='path',
                     dest='cov_config',
-                    help='disable coverage reading its config file')
-    group.addoption('--cov-config-file', action='store', default='.coveragerc', metavar='path',
-                    dest='cov_config_file',
-                    help='config file for coverage, default: %default')
+                    help='config file for coverage, default: .coveragerc')
 
 
 def pytest_configure(config):
     """Activate coverage plugin if appropriate."""
 
-    if config.getvalue('cov_on') or config.getvalue('cov_packages'):
+    if config.getvalue('cov_source'):
         config.pluginmanager.register(CovPlugin(config), '_cov')
 
 
     def __init__(self, config):
         """Creates a coverage pytest plugin.
 
-        We read the rc file that coverage uses so that everything in
-        the rc file will be honoured.  Specifically we tell coverage
-        through it's API the data file name, html dir name and xml
-        file name.  So we need to know what these are in the rc file
-        or env vars.
-
-        Doing this ensures that users can rely on the coverage rc file
-        and env vars to work the same under this plugin as they do
-        under coverage itself.
+        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.cov_controller = None
 
-        # For data file, html dir and xml file consider coverage rc
-        # file, coverage env vars and our own options in priority
-        # order.
-        parser = configparser.RawConfigParser()
-        parser.read(config.getvalue('cov_config_file'))
-        for default, section, item, env_var, option in (
-            ('coverage_html', 'html', 'directory', None           , 'cov_html_dir' ),
-            ('coverage.xml' , 'xml' , 'output'   , None           , 'cov_xml_file' ),
-            ('.coverage'    , 'run' , 'data_file', 'COVERAGE_FILE', 'cov_data_file')):
-
-            # Lowest priority is coverage hard coded default.
-            result = default
-
-            # Override with coverage rc file.
-            if parser.has_option(section, item):
-                result = parser.get(section, item)
-
-            # Override with coverage env var.
-            if env_var:
-                result = os.environ.get(env_var, result)
-
-            # Override with pytest cmd line, env var or conftest file.
-            value = config.getvalue(option)
-            if value:
-                result = value
-
-            # Set config option for consistency and for transport to slaves.
-            setattr(config.option, option, result)
-
-    def pytest_funcarg__cov(self, request):
-        return self.cov_controller.cov
-
     def pytest_sessionstart(self, session):
         """At session start determine our implementation and delegate to it."""
 
-        self.cov_controller = CovController.create_from_session(session)
-        self.cov_controller.sessionstart(session)
+        cov_source = session.config.getvalue('cov_source')
+        cov_report = session.config.getvalue('cov_report') or ['term']
+        cov_config = session.config.getvalue('cov_config')
+
+        name_to_cls = dict(Session=cov_core.Central,
+                           DSession=cov_core.DistMaster,
+                           SlaveSession=cov_core.DistSlave)
+        session_name = session.__class__.__name__
+        controller_cls = name_to_cls.get(session_name, cov_core.Central)
+        self.cov_controller = controller_cls(cov_source,
+                                             cov_report,
+                                             cov_config,
+                                             session.config,
+                                             getattr(session, 'nodeid', None))
+
+        self.cov_controller.start()
 
     def pytest_configure_node(self, node):
         """Delegate to our implementation."""
     def pytest_sessionfinish(self, session, exitstatus):
         """Delegate to our implementation."""
 
-        self.cov_controller.sessionfinish(session, exitstatus)
+        self.cov_controller.finish()
 
     def pytest_terminal_summary(self, terminalreporter):
         """Delegate to our implementation."""
 
-        self.cov_controller.terminal_summary(terminalreporter)
+        self.cov_controller.summary(terminalreporter._tw)
 
+    def pytest_funcarg__cov(self, request):
+        """A pytest funcarg that provide access to the underlying coverage object."""
 
-class CovController(object):
-    """Base class for different plugin implementations."""
-
-    @staticmethod
-    def create_from_session(session):
-        """Create the appropriate implementation based on the type of session."""
-
-        name_to_cls = dict(Session=Central,
-                           DSession=DistMaster,
-                           SlaveSession=DistSlave)
-        session_name = session.__class__.__name__
-        controller_cls = name_to_cls.get(session_name, Central)
-        return controller_cls(session.config)
-
-    def __init__(self, config):
-        """Get some common config used by multiple derived classes."""
-
-        self.config = config
-        self.covs = []
-        self.failed_slaves = []
-
-        self.cov_data_file = config.getvalue('cov_data_file')
-        self.cov_branch = config.getvalue('cov_branch')
-        self.cov_pylib = config.getvalue('cov_pylib')
-        self.cov_timid = config.getvalue('cov_timid')
-        if self.config.getvalue('cov_config'):
-            self.cov_config_file = os.path.realpath(self.config.getvalue('cov_config_file'))
-        else:
-            self.cov_config_file = False
-
-    def terminal_summary(self, terminalreporter):
-        """Produce coverage reports."""
-
-        # Get terminal writer and config values.
-        config = terminalreporter.config
-        terminalwriter = terminalreporter._tw
-
-        cov_packages = config.getvalue('cov_packages')
-        cov_terminal = config.getvalue('cov_terminal')
-        cov_annotate = config.getvalue('cov_annotate')
-        cov_html = config.getvalue('cov_html')
-        cov_xml = config.getvalue('cov_xml')
-        cov_annotate_dir = config.getvalue('cov_annotate_dir')
-        cov_html_dir = config.getvalue('cov_html_dir')
-        cov_xml_file = config.getvalue('cov_xml_file')
-        cov_show_missing = config.getvalue('cov_show_missing')
-        cov_ignore_errors = config.getvalue('cov_ignore_errors')
-        cov_omit_prefixes = config.getvalue('cov_omit_prefixes')
-        if cov_omit_prefixes:
-            cov_omit_prefixes = cov_omit_prefixes.split(',')
-
-        # Determine the modules or files to limit reports on.
-        morfs = list(set(module.__file__
-                         for name, module in sys.modules.items()
-                         for package in cov_packages
-                         if hasattr(module, '__file__') and
-                         os.path.splitext(module.__file__)[1] in ('.py', '.pyc', '.pyo') and
-                         name.startswith(package)))
-
-        # Produce a report for each coverage object.
-        for cov, node_descs in self.covs:
-
-            # Produce terminal report if wanted.
-            if cov_terminal:
-                if len(node_descs) == 1:
-                    terminalwriter.sep('-', 'coverage: %s' % ''.join(node_descs))
-                else:
-                    terminalwriter.sep('-', 'coverage')
-                    for node_desc in sorted(node_descs):
-                        terminalwriter.sep(' ', '%s' % node_desc)
-                cov.report(morfs, cov_show_missing, cov_ignore_errors, terminalwriter, cov_omit_prefixes)
-
-            # Only determine a suffix if we have more reports to do.
-            if cov_annotate or cov_html or cov_xml:
-
-                # Determine suffix if needed for following reports.
-                suffix = None
-                if len(self.covs) > 1:
-                    suffix = '_'.join(node_descs)
-                    replacements = [(' ', '_'), (',', ''), ('.', ''), ('-', '')]
-                    suffix = reduce(lambda suffix, oldnew: suffix.replace(oldnew[0], oldnew[1]), replacements, suffix)
-
-                # Produce annotated source code report if wanted.
-                if cov_annotate:
-                    if suffix:
-                        dir = '%s_%s' % (cov_annotate_dir, suffix)
-                    else:
-                        dir = cov_annotate_dir
-                    cov.annotate(morfs, dir, cov_ignore_errors, cov_omit_prefixes)
-
-                # Produce html report if wanted.
-                if cov_html:
-                    if suffix:
-                        dir = '%s_%s' % (cov_html_dir, suffix)
-                    else:
-                        dir = cov_html_dir
-                    cov.html_report(morfs, dir, cov_ignore_errors, cov_omit_prefixes)
-
-                # Produce xml report if wanted.
-                if cov_xml:
-                    if suffix:
-                        root, ext = os.path.splitext(cov_xml_file)
-                        xml_file = '%s_%s%s' % (root, suffix, ext)
-                    else:
-                        xml_file = cov_xml_file
-                    cov.xml_report(morfs, xml_file, cov_ignore_errors, cov_omit_prefixes)
-
-        # Report on any failed slaves.
-        if self.failed_slaves:
-            terminalwriter.sep('-', 'coverage: failed slaves')
-            terminalwriter.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:
-                terminalwriter.write('%s\n' % node.gateway.id)
-
-
-class Central(CovController):
-    """Implementation for centralised operation."""
-
-    def sessionstart(self, session):
-        """Erase any previous coverage data and start coverage."""
-
-        self.cov = coverage.coverage(data_file=self.cov_data_file,
-                                     branch=self.cov_branch,
-                                     cover_pylib=self.cov_pylib,
-                                     timid=self.cov_timid,
-                                     config_file=self.cov_config_file)
-        self.cov.erase()
-        self.cov.start()
-
-    def sessionfinish(self, session, exitstatus):
-        """Stop coverage, save data to file and set the list of coverage objects to report on."""
-
-        self.cov.stop()
-        self.cov.save()
-        node_desc = get_node_desc(sys.platform, sys.version_info)
-        self.covs = [(self.cov, [node_desc])]
-
-    def terminal_summary(self, terminalreporter):
-        """Produce coverage reports."""
-
-        CovController.terminal_summary(self, terminalreporter)
-
-
-class DistMaster(CovController):
-    """Implementation for distributed master."""
-
-    def sessionstart(self, session):
-        """Ensure coverage rc file rsynced if appropriate."""
-
-        self.data_files = {}
-        if self.cov_config_file and os.path.exists(self.cov_config_file):
-            self.config.option.rsyncdir.append(self.cov_config_file)
-
-    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.config.topdir
-        node.slaveinput['cov_master_rsync_roots'] = node.nodemanager.roots
-
-    def testnodedown(self, node, error):
-        """Collect data file name from slave.  Also save data to file if slave not collocated."""
-
-        # 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_data_file' 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_suffix' in node.slaveoutput:
-            cov = coverage.coverage(data_file=node.slaveoutput['cov_slave_data_file'],
-                                    data_suffix=node.slaveoutput['cov_slave_data_suffix'],
-                                    branch=self.cov_branch,
-                                    cover_pylib=self.cov_pylib,
-                                    timid=self.cov_timid,
-                                    config_file=self.cov_config_file)
-            cov.start()
-            cov.stop()
-            cov.data.lines = node.slaveoutput['cov_slave_lines']
-            cov.data.arcs = node.slaveoutput['cov_slave_arcs']
-            cov.save()
-
-        # For each data file record the set of slave types that contribute.
-        rinfo = node.gateway._rinfo()
-        node_desc = get_node_desc(rinfo.platform, rinfo.version_info)
-        node_descs = self.data_files.setdefault(node.slaveoutput['cov_slave_data_file'], set())
-        node_descs.add(node_desc)
-
-    def sessionfinish(self, session, exitstatus):
-        """Combines coverage data and sets the list of coverage objects to report on."""
-
-        # Fn that combines all appropriate suffix files into a data file.
-        def combine(data_file):
-            cov = coverage.coverage(data_file=data_file,
-                                    branch=self.cov_branch,
-                                    cover_pylib=self.cov_pylib,
-                                    timid=self.cov_timid,
-                                    config_file=self.cov_config_file)
-            cov.erase()
-            cov.combine()
-            cov.save()
-            return cov
-
-        # For each data file combine all its suffix files and record
-        # the contributing node types.
-        self.covs = [(combine(data_file), node_descs) for data_file, node_descs in sorted(self.data_files.items())]
-
-    def terminal_summary(self, terminalreporter):
-        """Produce coverage reports."""
-
-        CovController.terminal_summary(self, terminalreporter)
-
-
-class DistSlave(CovController):
-    """Implementation for distributed slaves."""
-
-    def sessionstart(self, session):
-        """Determine what data file and suffix to contribute to and start coverage."""
-
-        # Determine whether we are collocated with master.
-        self.is_collocated = bool(socket.gethostname() == session.config.slaveinput['cov_master_host'] and
-                                  session.config.topdir == session.config.slaveinput['cov_master_topdir'])
-
-        # Determine what data file to contribute to.
-        if session.config.option.dist == 'each' and not session.config.getvalue('cov_combine_each'):
-            # Contribute to data file specific to this node type,
-            # typically --dist=each and we are the only contributing
-            # slave.
-            node_desc = 'platform_%s_python_%s' % (sys.platform, '%s%s%s%s%s' % sys.version_info[:5])
-            self.data_file = '%s_%s' % (session.config.getvalue('cov_data_file'), node_desc)
-        else:
-            # Contribute to data file which typically is --dist=load
-            # and has all slaves contributing to it.
-            self.data_file = session.config.getvalue('cov_data_file')
-
-        # Our suffix makes us unique from all other slaves, master
-        # will combine our data later.
-        self.data_suffix = session.nodeid
-
-        # Erase any previous data and start coverage.
-        self.cov = coverage.coverage(data_file=self.data_file,
-                                     data_suffix=self.data_suffix,
-                                     branch=self.cov_branch,
-                                     cover_pylib=self.cov_pylib,
-                                     timid=self.cov_timid,
-                                     config_file=self.cov_config_file)
-        self.cov.erase()
-        self.cov.start()
-
-    def sessionfinish(self, session, exitstatus):
-        """Stop coverage and send relevant info back to the master."""
-
-        self.cov.stop()
-
-        if self.is_collocated:
-            # If we are collocated then save the file ourselves and
-            # inform the master of the data file we are contributing
-            # to.
-            self.cov.save()
-            session.config.slaveoutput['cov_slave_data_file'] = self.data_file
-        else:
-            # If we are not collocated then rewrite the filenames from
-            # the slave location to the master location.
-            slave_topdir = session.config.topdir
-            path_rewrites = [(str(slave_topdir.join(rsync_root.basename)), str(rsync_root))
-                             for rsync_root in session.config.slaveinput['cov_master_rsync_roots']]
-            path_rewrites.append((str(session.config.topdir), str(session.config.slaveinput['cov_master_topdir'])))
-
-            def rewrite_path(filename):
-                return reduce(lambda filename, slavemaster: filename.replace(slavemaster[0], slavemaster[1]),
-                              path_rewrites,
-                              filename)
-            lines = dict((rewrite_path(filename), data) for filename, data in self.cov.data.lines.items())
-            arcs = dict((rewrite_path(filename), data) for filename, data in self.cov.data.arcs.items())
-
-            # Send all the data to the master over the channel.
-            session.config.slaveoutput['cov_slave_data_file'] = self.data_file
-            session.config.slaveoutput['cov_slave_data_suffix'] = self.data_suffix
-            session.config.slaveoutput['cov_slave_lines'] = lines
-            session.config.slaveoutput['cov_slave_arcs'] = arcs
-
-    def terminal_summary(self, terminalreporter):
-        """Only the master reports so do nothing."""
-
-        pass
-
-
-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])
+        return self.cov_controller.cov if self.cov_controller else None
 import setuptools
 
 setuptools.setup(name='pytest-cov',
-                 version='0.15',
+                 version='1.0',
                  description='py.test plugin for coverage reporting with support for both centralised and distributed testing',
                  long_description=open('README.txt').read().strip(),
                  author='Meme Dough',
                  author_email='memedough@gmail.com',
                  url='http://bitbucket.org/memedough/pytest-cov/overview',
                  py_modules=['pytest_cov'],
-                 install_requires=['py>=1.3.0',
-                                   'pytest-xdist>=1.2',
-                                   'coverage>=3.3.1'],
+                 install_requires=['py>=1.3.3',
+                                   'pytest-xdist>=1.4',
+                                   'cov-core>=1.0'],
                  entry_points={'pytest11': ['pytest_cov = pytest_cov']},
                  license='MIT License',
                  zip_safe=False,

File test_pytest_cov.py

 
 - For py 3.0 coverage seems to give incorrect results, it reports all
   covered except the one line which it should have actualy covered.
+  Issue reported upstream, also only problem with pass statement and
+  is find with simple assignment statement.
 """
 
 import py
 import sys
+import os
 
 pytest_plugins = 'pytester', 'cov'
 
 def test_foo():
     version = sys.version_info[:2]
     if version == (2, 4):
-        pass
+        a = True
     if version == (2, 5):
-        pass
+        a = True
     if version == (2, 6):
-        pass
+        a = True
     if version == (2, 7):
-        pass
+        a = True
     if version == (3, 0):
-        pass
+        a = True
     if version == (3, 1):
-        pass
+        a = True
 '''
 
-SCRIPT_CMATH = '''
-import cmath
+SCRIPT_CHILD = '''
+import sys
 
-def test_foo():
+idx = int(sys.argv[1])
+
+if idx == 0:
+    pass
+if idx == 1:
     pass
 '''
 
-@py.test.mark.xfail('sys.version_info[:2] == (3, 0)')
+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()
+'''
+
+
 def test_central(testdir):
     script = testdir.makepyfile(SCRIPT)
+
     result = testdir.runpytest(script,
-                               '--cov=%s' % script.purebasename)
+                               '--cov=%s' % script.dirpath(),
+                               '--cov-report=term-missing')
+
     result.stdout.fnmatch_lines([
             '*- coverage: platform *, python * -*',
-            'test_central * 18 * 13 * 72% *',
+            'test_central * 18 * 72%*',
             '*10 passed*'
             ])
     assert result.ret == 0
 
-def test_module_selection(testdir):
-    script = testdir.makepyfile(SCRIPT_CMATH)
+
+def test_dist_collocated(testdir):
+    script = testdir.makepyfile(SCRIPT)
+
     result = testdir.runpytest(script,
-                               '--cov=cmath',
-                               '--cov=%s' % script.purebasename)
+                               '--cov=%s' % script.dirpath(),
+                               '--cov-report=term-missing',
+                               '--dist=load',
+                               '--tx=2*popen')
+
     result.stdout.fnmatch_lines([
             '*- coverage: platform *, python * -*',
-            'test_module_selection * 3 * 3 * 100% *',
-            '*1 passed*'
-            ])
-    assert result.ret == 0
-    matching_lines = [line for line in result.outlines if 'TokenError' in line]
-    assert not matching_lines
-
-@py.test.mark.xfail('sys.version_info[:2] == (3, 0)')
-def test_dist_load_collocated(testdir):
-    script = testdir.makepyfile(SCRIPT)
-    result = testdir.runpytest(script,
-                               '--cov=%s' % script.purebasename,
-                               '--dist=load',
-                               '--tx=2*popen')
-    result.stdout.fnmatch_lines([
-            '*- coverage: platform *, python * -*',
-            'test_dist_load_collocated * 18 * 13 * 72% *',
+            'test_dist_collocated * 18 * 72%*',
             '*10 passed*'
             ])
     assert result.ret == 0
 
-@py.test.mark.xfail('sys.version_info[:2] == (3, 0)')
-def test_dist_load_not_collocated(testdir):
+
+def test_dist_not_collocated(testdir):
     script = testdir.makepyfile(SCRIPT)
     dir1 = testdir.mkdir('dir1')
     dir2 = testdir.mkdir('dir2')
+
     result = testdir.runpytest(script,
-                               '--cov=%s' % script.purebasename,
+                               '--cov=%s' % script.dirpath(),
+                               '--cov-report=term-missing',
                                '--dist=load',
                                '--tx=popen//chdir=%s' % dir1,
                                '--tx=popen//chdir=%s' % dir2,
                                '--rsyncdir=%s' % script.basename)
+
     result.stdout.fnmatch_lines([
             '*- coverage: platform *, python * -*',
-            'test_dist_load_not_collocated * 18 * 13 * 72% *',
+            'test_dist_not_collocated * 18 * 72%*',
             '*10 passed*'
             ])
     assert result.ret == 0
 
-@py.test.mark.skipif('sys.version_info[:2] >= (3, 0)')
-def test_dist_each_many_reports_py2(testdir):
-    script = testdir.makepyfile(SCRIPT)
-    result = testdir.runpytest(script,
-                               '--cov=%s' % script.purebasename,
-                               '--dist=each',
-                               '--tx=popen//python=/usr/local/python246/bin/python',
-                               '--tx=popen//python=/usr/local/python255/bin/python',
-                               '--tx=popen//python=/usr/local/python265/bin/python',
-                               '--tx=popen//python=/usr/local/python27b1/bin/python')
+
+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(parent_script,
+                               '--cov=%s' % scripts.dirpath(),
+                               '--cov-report=term-missing')
+
     result.stdout.fnmatch_lines([
-           '*- coverage: platform *, python 2.4.6-final-0 -*',
-           'test_dist_each_many_reports_py2 * 18 * 13 * 72% *',
-           '*- coverage: platform *, python 2.5.5-final-0 -*',
-           'test_dist_each_many_reports_py2 * 18 * 13 * 72% *',
-            '*- coverage: platform *, python 2.6.5-final-0 -*',
-           'test_dist_each_many_reports_py2 * 18 * 13 * 72% *',
-            '*- coverage: platform *, python 2.7.0-beta-1 -*',
-           'test_dist_each_many_reports_py2 * 18 * 13 * 72% *',
-            '*40 passed*'
+            '*- coverage: platform *, python * -*',
+            'child_script * 6 * 100%*',
+            'parent_script * 7 * 100%*',
             ])
     assert result.ret == 0
 
-@py.test.mark.skipif('sys.version_info[:2] < (3, 0)')
-@py.test.mark.xfail('sys.version_info[:2] == (3, 1)')
-def test_dist_each_many_reports_py3(testdir):
-    script = testdir.makepyfile(SCRIPT)
-    result = testdir.runpytest(script,
-                               '--cov=%s' % script.purebasename,
-                               '--dist=each',
-                               '--tx=popen//python=/usr/local/python301/bin/python3.0',
-                               '--tx=popen//python=/usr/local/python312/bin/python3.1')
+
+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(parent_script,
+                               '--cov=%s' % scripts.dirpath(),
+                               '--cov-report=term-missing',
+                               '--dist=load',
+                               '--tx=2*popen')
+
     result.stdout.fnmatch_lines([
-            # coverage under python 3.0 seems to produce incorrect
-            # results but ignore for this test as we want to see
-            # multiple reports regardless of results.
-            '*- coverage: platform *, python 3.0.1-final-0 -*',
-            'test_dist_each_many_reports_py3 * 18 * 17 * 94% *',
-            '*- coverage: platform *, python 3.1.2-final-0 -*',
-            'test_dist_each_many_reports_py3 * 18 * 13 * 72% *',
-            '*20 passed*'
+            '*- coverage: platform *, python * -*',
+            'child_script * 6 * 100%*',
+            'parent_script * 7 * 100%*',
             ])
     assert result.ret == 0
 
-@py.test.mark.skipif('sys.version_info[:2] >= (3, 0)')
-def test_dist_each_one_report_py2(testdir):
-    script = testdir.makepyfile(SCRIPT)
-    result = testdir.runpytest(script,
-                               '--cov=%s' % script.purebasename,
-                               '--cov-combine-each',
-                               '--dist=each',
-                               '--tx=popen//python=/usr/local/python246/bin/python',
-                               '--tx=popen//python=/usr/local/python255/bin/python',
-                               '--tx=popen//python=/usr/local/python265/bin/python',
-                               '--tx=popen//python=/usr/local/python27b1/bin/python')
+
+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(parent_script,
+                               '--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)
+
     result.stdout.fnmatch_lines([
-            '*- coverage -*',
-            '* platform *, python 2.4.6-final-0 *',
-            '* platform *, python 2.5.5-final-0 *',
-            '* platform *, python 2.6.5-final-0 *',
-            '* platform *, python 2.7.0-beta-1 *',
-            'test_dist_each_one_report_py2 * 18 * 16 * 88% *',
-            '*40 passed*'
+            '*- coverage: platform *, python * -*',
+            'child_script * 6 * 100%*',
+            'parent_script * 7 * 100%*',
             ])
     assert result.ret == 0
 
-@py.test.mark.skipif('sys.version_info[:2] < (3, 0)')
-@py.test.mark.xfail('sys.version_info[:2] == (3, 1)')
-def test_dist_each_one_report_py3(testdir):
-    script = testdir.makepyfile(SCRIPT)
-    result = testdir.runpytest(script,
-                               '--cov=%s' % script.purebasename,
-                               '--cov-combine-each',
-                               '--dist=each',
-                               '--tx=popen//python=/usr/local/python301/bin/python3.0',
-                               '--tx=popen//python=/usr/local/python312/bin/python3.1')
-    result.stdout.fnmatch_lines([
-            # coverage under python 3.0 seems to produce incorrect
-            # results but ignore for this test as we want to see
-            # multiple reports regardless of results.
-            '*- coverage -*',
-            '* platform *, python 3.0.1-final-0 *',
-            '* platform *, python 3.1.2-final-0 *',
-            'test_dist_each_one_report_py3 * 18 * 17 * 94% *',
-            '*20 passed*'
-            ])
-    assert result.ret == 0
 
 @py.test.mark.skipif('sys.version_info[:2] >= (3, 0)')
 def test_dist_missing_data(testdir):
+    if not os.path.exists('/usr/local/python255-empty/bin/python'):
+        py.test.skip('this test needs python without pytest-cov installed in /usr/local/python255-empty/bin/python')
+
     script = testdir.makepyfile(SCRIPT)
+
     result = testdir.runpytest(script,
-                               '--cov=%s' % script.purebasename,
+                               '--cov=%s' % script.dirpath(),
+                               '--cov-report=term-missing',
                                '--dist=load',
-                               '--tx=popen//python=/usr/local/env255empty/bin/python')
+                               '--tx=popen//python=/usr/local/python255-empty/bin/python')
+
     result.stdout.fnmatch_lines([
             '*- coverage: failed slaves -*'
             ])