summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.rst7
-rw-r--r--coverage/control.py10
-rw-r--r--tests/test_concurrency.py28
3 files changed, 36 insertions, 9 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index 61c28d19..0c426023 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -24,7 +24,12 @@ want to know what's different in 5.0 since 4.5.x, see :ref:`whatsnew5x`.
Unreleased
----------
-Nothing yet.
+- When using ``coverage run --concurrency=multiprocessing``, all data files
+ should be named with parallel-ready suffixes. 5.0 mistakenly named the main
+ process' file with no suffix when using ``--append``. This is now fixed,
+ closing `issue 880`_.
+
+.. _issue 880: https://github.com/nedbat/coveragepy/issues/880
.. _changes_50:
diff --git a/coverage/control.py b/coverage/control.py
index 1de0e28f..5194b5d6 100644
--- a/coverage/control.py
+++ b/coverage/control.py
@@ -252,6 +252,11 @@ class Coverage(object):
# to.
self._debug = DebugControl(self.config.debug, self._debug_file)
+ if "multiprocessing" in (self.config.concurrency or ()):
+ # Multi-processing uses parallel for the subprocesses, so also use
+ # it for the main process.
+ self.config.parallel = True
+
# _exclude_re is a dict that maps exclusion list names to compiled regexes.
self._exclude_re = {}
@@ -393,16 +398,13 @@ class Coverage(object):
def _init_for_start(self):
"""Initialization for start()"""
# Construct the collector.
- concurrency = self.config.concurrency or []
+ concurrency = self.config.concurrency or ()
if "multiprocessing" in concurrency:
if not patch_multiprocessing:
raise CoverageException( # pragma: only jython
"multiprocessing is not supported on this Python"
)
patch_multiprocessing(rcfile=self.config.config_file)
- # Multi-processing uses parallel for the subprocesses, so also use
- # it for the main process.
- self.config.parallel = True
dycon = self.config.dynamic_context
if not dycon or dycon == "none":
diff --git a/tests/test_concurrency.py b/tests/test_concurrency.py
index a397ea99..5d492a72 100644
--- a/tests/test_concurrency.py
+++ b/tests/test_concurrency.py
@@ -3,6 +3,7 @@
"""Tests for concurrency libraries."""
+import glob
import os
import random
import sys
@@ -360,6 +361,12 @@ MULTI_CODE = """
"""
+def remove_files(*patterns):
+ for pattern in patterns:
+ for fname in glob.glob(pattern):
+ os.remove(fname)
+
+
@flaky(max_runs=30) # Sometimes a test fails due to inherent randomness. Try more times.
class MultiprocessingTest(CoverageTest):
"""Test support of the multiprocessing module."""
@@ -370,7 +377,7 @@ class MultiprocessingTest(CoverageTest):
super(MultiprocessingTest, self).setUp()
def try_multiprocessing_code(
- self, code, expected_out, the_module, concurrency="multiprocessing"
+ self, code, expected_out, the_module, nprocs, concurrency="multiprocessing", args=""
):
"""Run code using multiprocessing, it should produce `expected_out`."""
self.make_file("multi.py", code)
@@ -389,13 +396,18 @@ class MultiprocessingTest(CoverageTest):
if start_method and start_method not in multiprocessing.get_all_start_methods():
continue
- out = self.run_command("coverage run multi.py %s" % (start_method,))
+ remove_files(".coverage", ".coverage.*")
+ cmd = "coverage run {args} multi.py {start_method}".format(
+ args=args, start_method=start_method,
+ )
+ out = self.run_command(cmd)
expected_cant_trace = cant_trace_msg(concurrency, the_module)
if expected_cant_trace is not None:
self.assertEqual(out, expected_cant_trace)
else:
self.assertEqual(out.rstrip(), expected_out)
+ self.assertEqual(len(glob.glob(".coverage.*")), nprocs + 1)
out = self.run_command("coverage combine")
self.assertEqual(out, "")
@@ -410,7 +422,15 @@ class MultiprocessingTest(CoverageTest):
code = (SQUARE_OR_CUBE_WORK + MULTI_CODE).format(NPROCS=nprocs, UPTO=upto)
total = sum(x*x if x%2 else x*x*x for x in range(upto))
expected_out = "{nprocs} pids, total = {total}".format(nprocs=nprocs, total=total)
- self.try_multiprocessing_code(code, expected_out, threading)
+ self.try_multiprocessing_code(code, expected_out, threading, nprocs)
+
+ def test_multiprocessing_append(self):
+ nprocs = 3
+ upto = 30
+ code = (SQUARE_OR_CUBE_WORK + MULTI_CODE).format(NPROCS=nprocs, UPTO=upto)
+ total = sum(x*x if x%2 else x*x*x for x in range(upto))
+ expected_out = "{nprocs} pids, total = {total}".format(nprocs=nprocs, total=total)
+ self.try_multiprocessing_code(code, expected_out, threading, nprocs, args="--append")
def test_multiprocessing_and_gevent(self):
nprocs = 3
@@ -421,7 +441,7 @@ class MultiprocessingTest(CoverageTest):
total = sum(sum(range((x + 1) * 100)) for x in range(upto))
expected_out = "{nprocs} pids, total = {total}".format(nprocs=nprocs, total=total)
self.try_multiprocessing_code(
- code, expected_out, eventlet, concurrency="multiprocessing,eventlet"
+ code, expected_out, eventlet, nprocs, concurrency="multiprocessing,eventlet"
)
def try_multiprocessing_code_with_branching(self, code, expected_out):