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
« prev ^ index » next coverage.py v7.2.3, created at 2023-05-04 13:14 +0700
1"""Activate coverage at python startup if appropriate.
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.
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.
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
20_active_cov = None
23def init():
24 # Only continue if ancestor process has set everything needed in
25 # the env.
26 global _active_cov
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')
34 if cov_datafile:
35 if _active_cov:
36 cleanup()
37 # Import what we need to activate coverage.
38 import coverage
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
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
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
77def cleanup():
78 global _active_cov
79 global _cleanup_in_progress
80 global _pending_signal
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)
92_previous_handlers = {}
93_pending_signal = None
94_cleanup_in_progress = False
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()
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)
121def cleanup_on_sigterm():
122 cleanup_on_signal(signal.SIGTERM)