summaryrefslogtreecommitdiff
path: root/coverage
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2016-07-24 09:39:47 -0400
committerNed Batchelder <ned@nedbatchelder.com>2016-07-24 09:39:47 -0400
commit2f9e2bec60fa1a8f66b34c6c37fdfcf6010fe354 (patch)
tree8689c177a71648d2127f8f236ef5b9869b60ac94 /coverage
parenta003fc65c5a0904894bd16fab351a4459348f70e (diff)
downloadpython-coveragepy-2f9e2bec60fa1a8f66b34c6c37fdfcf6010fe354.tar.gz
Set the rcfile for multiprocessing subprocesses
Diffstat (limited to 'coverage')
-rw-r--r--coverage/config.py3
-rw-r--r--coverage/control.py2
-rw-r--r--coverage/multiproc.py25
3 files changed, 22 insertions, 8 deletions
diff --git a/coverage/config.py b/coverage/config.py
index 23ec232..d6f5af0 100644
--- a/coverage/config.py
+++ b/coverage/config.py
@@ -9,7 +9,7 @@ import re
import sys
from coverage.backward import configparser, iitems, string_class
-from coverage.misc import CoverageException, isolate_module
+from coverage.misc import contract, CoverageException, isolate_module
os = isolate_module(os)
@@ -201,6 +201,7 @@ class CoverageConfig(object):
v = [v]
setattr(self, k, v)
+ @contract(filename=str)
def from_file(self, filename, section_prefix=""):
"""Read configuration from a .rc file.
diff --git a/coverage/control.py b/coverage/control.py
index fed5ab4..d3e6708 100644
--- a/coverage/control.py
+++ b/coverage/control.py
@@ -133,10 +133,10 @@ class Coverage(object):
# True, so make it so.
if config_file == ".coveragerc":
config_file = True
- self.config_file = config_file
specified_file = (config_file is not True)
if not specified_file:
config_file = ".coveragerc"
+ self.config_file = config_file
did_read_rc = self.config.from_file(config_file)
diff --git a/coverage/multiproc.py b/coverage/multiproc.py
index f9341ef..78c680c 100644
--- a/coverage/multiproc.py
+++ b/coverage/multiproc.py
@@ -5,11 +5,18 @@
import multiprocessing
import multiprocessing.process
+import os
import sys
-# An attribute that will be set on modules to indicate that they have been
+from coverage.misc import contract
+
+# An attribute that will be set on the module to indicate that it has been
# monkey-patched.
-PATCHED_MARKER = "_coverage$rcfile"
+PATCHED_MARKER = "_coverage$patched"
+
+# The environment variable that specifies the rcfile for subprocesses.
+COVERAGE_RCFILE_ENV = "_COVERAGE_RCFILE"
+
if sys.version_info >= (3, 4):
OriginalProcess = multiprocessing.process.BaseProcess
@@ -18,13 +25,13 @@ else:
original_bootstrap = OriginalProcess._bootstrap
-
class ProcessWithCoverage(OriginalProcess):
"""A replacement for multiprocess.Process that starts coverage."""
+
def _bootstrap(self):
"""Wrapper around _bootstrap to start coverage."""
- from coverage import Coverage
- rcfile = getattr(multiprocessing, PATCHED_MARKER)
+ from coverage import Coverage # avoid circular import
+ rcfile = os.environ[COVERAGE_RCFILE_ENV]
cov = Coverage(data_suffix=True, config_file=rcfile)
cov.start()
try:
@@ -46,6 +53,7 @@ class Stowaway(object):
patch_multiprocessing(state['rcfile'])
+@contract(rcfile=str)
def patch_multiprocessing(rcfile):
"""Monkey-patch the multiprocessing module.
@@ -55,6 +63,7 @@ def patch_multiprocessing(rcfile):
`rcfile` is the path to the rcfile being used.
"""
+
if hasattr(multiprocessing, PATCHED_MARKER):
return
@@ -63,6 +72,10 @@ def patch_multiprocessing(rcfile):
else:
multiprocessing.Process = ProcessWithCoverage
+ # Set the value in ProcessWithCoverage that will be pickled into the child
+ # process.
+ os.environ[COVERAGE_RCFILE_ENV] = rcfile
+
# When spawning processes rather than forking them, we have no state in the
# new process. We sneak in there with a Stowaway: we stuff one of our own
# objects into the data that gets pickled and sent to the sub-process. When
@@ -83,4 +96,4 @@ def patch_multiprocessing(rcfile):
spawn.get_preparation_data = get_preparation_data_with_stowaway
- setattr(multiprocessing, PATCHED_MARKER, rcfile)
+ setattr(multiprocessing, PATCHED_MARKER, True)