Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1"""Activate coverage at python startup if appropriate. 

2 

3The python site initialisation will ensure that anything we import 

4will be removed and not visible at the end of python startup. However 

5we minimise all work by putting these init actions in this separate 

6module and only importing what is needed when needed. 

7 

8For normal python startup when coverage should not be activated the pth 

9file checks a single env var and does not import or call the init fn 

10here. 

11 

12For python startup when an ancestor process has set the env indicating 

13that code coverage is being collected we activate coverage based on 

14info passed via env vars. 

15""" 

16import atexit 

17import os 

18import signal 

19 

20_active_cov = None 

21 

22 

23def multiprocessing_start(_): 

24 global _active_cov 

25 cov = init() 

26 if cov: 

27 _active_cov = cov 

28 multiprocessing.util.Finalize(None, cleanup, exitpriority=1000) 

29 

30 

31try: 

32 import multiprocessing.util 

33except ImportError: 

34 pass 

35else: 

36 multiprocessing.util.register_after_fork(multiprocessing_start, multiprocessing_start) 

37 

38 

39def init(): 

40 # Only continue if ancestor process has set everything needed in 

41 # the env. 

42 global _active_cov 

43 

44 cov_source = os.environ.get('COV_CORE_SOURCE') 

45 cov_config = os.environ.get('COV_CORE_CONFIG') 

46 cov_datafile = os.environ.get('COV_CORE_DATAFILE') 

47 cov_branch = True if os.environ.get('COV_CORE_BRANCH') == 'enabled' else None 

48 cov_context = os.environ.get('COV_CORE_CONTEXT') 

49 

50 if cov_datafile: 

51 if _active_cov: 

52 cleanup() 

53 # Import what we need to activate coverage. 

54 import coverage 

55 

56 # Determine all source roots. 

57 if cov_source in os.pathsep: 

58 cov_source = None 

59 else: 

60 cov_source = cov_source.split(os.pathsep) 

61 if cov_config == os.pathsep: 

62 cov_config = True 

63 

64 # Activate coverage for this process. 

65 cov = _active_cov = coverage.Coverage( 

66 source=cov_source, 

67 branch=cov_branch, 

68 data_suffix=True, 

69 config_file=cov_config, 

70 auto_data=True, 

71 data_file=cov_datafile 

72 ) 

73 cov.load() 

74 cov.start() 

75 if cov_context: 

76 cov.switch_context(cov_context) 

77 cov._warn_no_data = False 

78 cov._warn_unimported_source = False 

79 return cov 

80 

81 

82def _cleanup(cov): 

83 if cov is not None: 

84 cov.stop() 

85 cov.save() 

86 cov._auto_save = False # prevent autosaving from cov._atexit in case the interpreter lacks atexit.unregister 

87 try: 

88 atexit.unregister(cov._atexit) 

89 except Exception: 

90 pass 

91 

92 

93def cleanup(): 

94 global _active_cov 

95 global _cleanup_in_progress 

96 global _pending_signal 

97 

98 _cleanup_in_progress = True 

99 _cleanup(_active_cov) 

100 _active_cov = None 

101 _cleanup_in_progress = False 

102 if _pending_signal: 

103 pending_singal = _pending_signal 

104 _pending_signal = None 

105 _signal_cleanup_handler(*pending_singal) 

106 

107 

108multiprocessing_finish = cleanup # in case someone dared to use this internal 

109 

110_previous_handlers = {} 

111_pending_signal = None 

112_cleanup_in_progress = False 

113 

114 

115def _signal_cleanup_handler(signum, frame): 

116 global _pending_signal 

117 if _cleanup_in_progress: 

118 _pending_signal = signum, frame 

119 return 

120 cleanup() 

121 _previous_handler = _previous_handlers.get(signum) 

122 if _previous_handler == signal.SIG_IGN: 

123 return 

124 elif _previous_handler and _previous_handler is not _signal_cleanup_handler: 

125 _previous_handler(signum, frame) 

126 elif signum == signal.SIGTERM: 

127 os._exit(128 + signum) 

128 elif signum == signal.SIGINT: 

129 raise KeyboardInterrupt() 

130 

131 

132def cleanup_on_signal(signum): 

133 previous = signal.getsignal(signum) 

134 if previous is not _signal_cleanup_handler: 

135 _previous_handlers[signum] = previous 

136 signal.signal(signum, _signal_cleanup_handler) 

137 

138 

139def cleanup_on_sigterm(): 

140 cleanup_on_signal(signal.SIGTERM)