eric6/DebugClients/Python/coverage/multiproc.py

changeset 7427
362cd1b6f81a
parent 7275
9a25fe1fab84
child 7702
f8b97639deb5
equal deleted inserted replaced
7426:dc171b1d8261 7427:362cd1b6f81a
1 # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 1 # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2 # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt 2 # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
3 3
4 """Monkey-patching to add multiprocessing support for coverage.py""" 4 """Monkey-patching to add multiprocessing support for coverage.py"""
5 5
6 import multiprocessing 6 import multiprocessing
7 import multiprocessing.process 7 import multiprocessing.process
8 import os 8 import os
9 import os.path
9 import sys 10 import sys
11 import traceback
10 12
13 from coverage import env
11 from coverage.misc import contract 14 from coverage.misc import contract
12 15
13 # An attribute that will be set on the module to indicate that it has been 16 # An attribute that will be set on the module to indicate that it has been
14 # monkey-patched. 17 # monkey-patched.
15 PATCHED_MARKER = "_coverage$patched" 18 PATCHED_MARKER = "_coverage$patched"
16 19
17 # The environment variable that specifies the rcfile for subprocesses.
18 COVERAGE_RCFILE_ENV = "_COVERAGE_RCFILE"
19 20
20 21 if env.PYVERSION >= (3, 4):
21 if sys.version_info >= (3, 4):
22 OriginalProcess = multiprocessing.process.BaseProcess 22 OriginalProcess = multiprocessing.process.BaseProcess
23 else: 23 else:
24 OriginalProcess = multiprocessing.Process 24 OriginalProcess = multiprocessing.Process
25 25
26 original_bootstrap = OriginalProcess._bootstrap 26 original_bootstrap = OriginalProcess._bootstrap
27 27
28 class ProcessWithCoverage(OriginalProcess): 28 class ProcessWithCoverage(OriginalProcess): # pylint: disable=abstract-method
29 """A replacement for multiprocess.Process that starts coverage.""" 29 """A replacement for multiprocess.Process that starts coverage."""
30 30
31 def _bootstrap(self, *args, **kwargs): # pylint: disable=arguments-differ 31 def _bootstrap(self, *args, **kwargs): # pylint: disable=arguments-differ
32 """Wrapper around _bootstrap to start coverage.""" 32 """Wrapper around _bootstrap to start coverage."""
33 from coverage import Coverage # avoid circular import
34 rcfile = os.environ[COVERAGE_RCFILE_ENV]
35 cov = Coverage(data_suffix=True, config_file=rcfile)
36 cov.start()
37 debug = cov.debug
38 try: 33 try:
34 from coverage import Coverage # avoid circular import
35 cov = Coverage(data_suffix=True)
36 cov._warn_preimported_source = False
37 cov.start()
38 debug = cov._debug
39 if debug.should("multiproc"): 39 if debug.should("multiproc"):
40 debug.write("Calling multiprocessing bootstrap") 40 debug.write("Calling multiprocessing bootstrap")
41 except Exception:
42 print("Exception during multiprocessing bootstrap init:")
43 traceback.print_exc(file=sys.stdout)
44 sys.stdout.flush()
45 raise
46 try:
41 return original_bootstrap(self, *args, **kwargs) 47 return original_bootstrap(self, *args, **kwargs)
42 finally: 48 finally:
43 if debug.should("multiproc"): 49 if debug.should("multiproc"):
44 debug.write("Finished multiprocessing bootstrap") 50 debug.write("Finished multiprocessing bootstrap")
45 cov.stop() 51 cov.stop()
71 """ 77 """
72 78
73 if hasattr(multiprocessing, PATCHED_MARKER): 79 if hasattr(multiprocessing, PATCHED_MARKER):
74 return 80 return
75 81
76 if sys.version_info >= (3, 4): 82 if env.PYVERSION >= (3, 4):
77 OriginalProcess._bootstrap = ProcessWithCoverage._bootstrap 83 OriginalProcess._bootstrap = ProcessWithCoverage._bootstrap
78 else: 84 else:
79 multiprocessing.Process = ProcessWithCoverage 85 multiprocessing.Process = ProcessWithCoverage
80 86
81 # Set the value in ProcessWithCoverage that will be pickled into the child 87 # Set the value in ProcessWithCoverage that will be pickled into the child
82 # process. 88 # process.
83 os.environ[COVERAGE_RCFILE_ENV] = rcfile 89 os.environ["COVERAGE_RCFILE"] = os.path.abspath(rcfile)
84 90
85 # When spawning processes rather than forking them, we have no state in the 91 # When spawning processes rather than forking them, we have no state in the
86 # new process. We sneak in there with a Stowaway: we stuff one of our own 92 # new process. We sneak in there with a Stowaway: we stuff one of our own
87 # objects into the data that gets pickled and sent to the sub-process. When 93 # objects into the data that gets pickled and sent to the sub-process. When
88 # the Stowaway is unpickled, it's __setstate__ method is called, which 94 # the Stowaway is unpickled, it's __setstate__ method is called, which

eric ide

mercurial