Skip to content

Commit

Permalink
Carry static context information into subprocesses
Browse files Browse the repository at this point in the history
  • Loading branch information
s0undt3ch committed Jan 4, 2021
1 parent 7ff93a9 commit e92571b
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 8 deletions.
5 changes: 4 additions & 1 deletion coverage/control.py
Expand Up @@ -434,7 +434,10 @@ def _init_for_start(self):
raise CoverageException( # pragma: only jython
"multiprocessing is not supported on this Python"
)
patch_multiprocessing(rcfile=self.config.config_file)
patch_multiprocessing(
rcfile=self.config.config_file,
static_context=self.config.context or ""
)

dycon = self.config.dynamic_context
if not dycon or dycon == "none":
Expand Down
19 changes: 12 additions & 7 deletions coverage/multiproc.py
Expand Up @@ -32,7 +32,10 @@ def _bootstrap(self, *args, **kwargs): # pylint: disable=signature-diff
"""Wrapper around _bootstrap to start coverage."""
try:
from coverage import Coverage # avoid circular import
cov = Coverage(data_suffix=True)
cov = Coverage(
data_suffix=True,
context=os.environ.get("COVERAGE_STATIC_CONTEXT") or None
)
cov._warn_preimported_source = False
cov.start()
debug = cov._debug
Expand All @@ -55,18 +58,19 @@ def _bootstrap(self, *args, **kwargs): # pylint: disable=signature-diff

class Stowaway(object):
"""An object to pickle, so when it is unpickled, it can apply the monkey-patch."""
def __init__(self, rcfile):
def __init__(self, rcfile, static_context):
self.rcfile = rcfile
self.static_context = static_context

def __getstate__(self):
return {'rcfile': self.rcfile}
return {'rcfile': self.rcfile, "static_context": self.static_context}

def __setstate__(self, state):
patch_multiprocessing(state['rcfile'])
patch_multiprocessing(state['rcfile'], state["static_context"])


@contract(rcfile=str)
def patch_multiprocessing(rcfile):
@contract(rcfile=str, static_context=str)
def patch_multiprocessing(rcfile, static_context):
"""Monkey-patch the multiprocessing module.
This enables coverage measurement of processes started by multiprocessing.
Expand All @@ -87,6 +91,7 @@ def patch_multiprocessing(rcfile):
# Set the value in ProcessWithCoverage that will be pickled into the child
# process.
os.environ["COVERAGE_RCFILE"] = os.path.abspath(rcfile)
os.environ["COVERAGE_STATIC_CONTEXT"] = static_context

# 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
Expand All @@ -103,7 +108,7 @@ def patch_multiprocessing(rcfile):
def get_preparation_data_with_stowaway(name):
"""Get the original preparation data, and also insert our stowaway."""
d = original_get_preparation_data(name)
d['stowaway'] = Stowaway(rcfile)
d['stowaway'] = Stowaway(rcfile, static_context)
return d

spawn.get_preparation_data = get_preparation_data_with_stowaway
Expand Down

0 comments on commit e92571b

Please sign in to comment.