Coverage for /opt/homebrew/lib/python3.11/site-packages/pytest_cov/embed.py: 19%

69 statements  

« prev     ^ index     » next       coverage.py v7.2.3, created at 2023-05-04 13:14 +0700

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 init(): 

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

25 # the env. 

26 global _active_cov 

27 

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

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

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

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

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

33 

34 if cov_datafile: 

35 if _active_cov: 

36 cleanup() 

37 # Import what we need to activate coverage. 

38 import coverage 

39 

40 # Determine all source roots. 

41 if cov_source in os.pathsep: 

42 cov_source = None 

43 else: 

44 cov_source = cov_source.split(os.pathsep) 

45 if cov_config == os.pathsep: 

46 cov_config = True 

47 

48 # Activate coverage for this process. 

49 cov = _active_cov = coverage.Coverage( 

50 source=cov_source, 

51 branch=cov_branch, 

52 data_suffix=True, 

53 config_file=cov_config, 

54 auto_data=True, 

55 data_file=cov_datafile 

56 ) 

57 cov.load() 

58 cov.start() 

59 if cov_context: 

60 cov.switch_context(cov_context) 

61 cov._warn_no_data = False 

62 cov._warn_unimported_source = False 

63 return cov 

64 

65 

66def _cleanup(cov): 

67 if cov is not None: 

68 cov.stop() 

69 cov.save() 

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

71 try: 

72 atexit.unregister(cov._atexit) 

73 except Exception: 

74 pass 

75 

76 

77def cleanup(): 

78 global _active_cov 

79 global _cleanup_in_progress 

80 global _pending_signal 

81 

82 _cleanup_in_progress = True 

83 _cleanup(_active_cov) 

84 _active_cov = None 

85 _cleanup_in_progress = False 

86 if _pending_signal: 

87 pending_signal = _pending_signal 

88 _pending_signal = None 

89 _signal_cleanup_handler(*pending_signal) 

90 

91 

92_previous_handlers = {} 

93_pending_signal = None 

94_cleanup_in_progress = False 

95 

96 

97def _signal_cleanup_handler(signum, frame): 

98 global _pending_signal 

99 if _cleanup_in_progress: 

100 _pending_signal = signum, frame 

101 return 

102 cleanup() 

103 _previous_handler = _previous_handlers.get(signum) 

104 if _previous_handler == signal.SIG_IGN: 

105 return 

106 elif _previous_handler and _previous_handler is not _signal_cleanup_handler: 

107 _previous_handler(signum, frame) 

108 elif signum == signal.SIGTERM: 

109 os._exit(128 + signum) 

110 elif signum == signal.SIGINT: 

111 raise KeyboardInterrupt() 

112 

113 

114def cleanup_on_signal(signum): 

115 previous = signal.getsignal(signum) 

116 if previous is not _signal_cleanup_handler: 

117 _previous_handlers[signum] = previous 

118 signal.signal(signum, _signal_cleanup_handler) 

119 

120 

121def cleanup_on_sigterm(): 

122 cleanup_on_signal(signal.SIGTERM)