diff options
Diffstat (limited to 'coverage')
-rw-r--r-- | coverage/config.py | 3 | ||||
-rw-r--r-- | coverage/control.py | 2 | ||||
-rw-r--r-- | coverage/multiproc.py | 25 |
3 files changed, 22 insertions, 8 deletions
diff --git a/coverage/config.py b/coverage/config.py index 23ec2328..d6f5af0a 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 fed5ab45..d3e67085 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 f9341ef8..78c680c7 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) |