Coverage for coverage / control.py: 90.601%

479 statements  

« prev     ^ index     » next       coverage.py v7.12.1a0.dev1, created at 2025-11-29 20:34 +0000

1# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 

2# For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt 

3 

4"""Central control stuff for coverage.py.""" 

5 

6from __future__ import annotations 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

7 

8import atexit 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

9import collections 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

10import contextlib 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

11import datetime 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

12import functools 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

13import os 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

14import os.path 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

15import platform 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

16import signal 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

17import sys 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

18import threading 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

19import time 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

20import warnings 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

21from collections.abc import Iterable, Iterator 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

22from types import FrameType 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

23from typing import IO, Any, Callable, cast 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

24 

25from coverage import env 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

26from coverage.annotate import AnnotateReporter 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

27from coverage.collector import Collector 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

28from coverage.config import CoverageConfig, read_coverage_config 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

29from coverage.context import combine_context_switchers, should_start_context_test_function 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

30from coverage.core import CTRACER_FILE, Core 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

31from coverage.data import CoverageData, combine_parallel_data 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

32from coverage.debug import ( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

33 DebugControl, 

34 NoDebugging, 

35 relevant_environment_display, 

36 short_stack, 

37 write_formatted_info, 

38) 

39from coverage.disposition import disposition_debug_msg 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

40from coverage.exceptions import ConfigError, CoverageException, CoverageWarning, PluginError 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

41from coverage.files import PathAliases, abs_file, relative_filename, set_relative_directory 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

42from coverage.html import HtmlReporter 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

43from coverage.inorout import InOrOut 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

44from coverage.jsonreport import JsonReporter 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

45from coverage.lcovreport import LcovReporter 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

46from coverage.misc import ( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

47 DefaultValue, 

48 bool_or_none, 

49 ensure_dir_for_file, 

50 isolate_module, 

51 join_regex, 

52) 

53from coverage.multiproc import patch_multiprocessing 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

54from coverage.patch import apply_patches 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

55from coverage.plugin import FileReporter 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

56from coverage.plugin_support import Plugins, TCoverageInit 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

57from coverage.python import PythonFileReporter 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

58from coverage.report import SummaryReporter 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

59from coverage.report_core import render_report 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

60from coverage.results import Analysis, analysis_from_file_reporter 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

61from coverage.types import ( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

62 FilePath, 

63 TConfigSectionIn, 

64 TConfigurable, 

65 TConfigValueIn, 

66 TConfigValueOut, 

67 TFileDisposition, 

68 TLineNo, 

69 TMorf, 

70) 

71from coverage.version import __url__ 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

72from coverage.xmlreport import XmlReporter 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

73 

74os = isolate_module(os) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

75 

76 

77@contextlib.contextmanager 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

78def override_config(cov: Coverage, **kwargs: TConfigValueIn) -> Iterator[None]: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

79 """Temporarily tweak the configuration of `cov`. 

80 

81 The arguments are applied to `cov.config` with the `from_args` method. 

82 At the end of the with-statement, the old configuration is restored. 

83 """ 

84 original_config = cov.config 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

85 cov.config = cov.config.copy() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

86 try: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

87 cov.config.from_args(**kwargs) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

88 yield 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

89 finally: 

90 cov.config = original_config 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

91 

92 

93DEFAULT_DATAFILE = DefaultValue("MISSING") 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

94_DEFAULT_DATAFILE = DEFAULT_DATAFILE # Just in case, for backwards compatibility 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

95CONFIG_DATA_PREFIX = ":data:" 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

96 

97 

98class Coverage(TConfigurable): 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

99 """Programmatic access to coverage.py. 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

100 

101 To use:: 

102 

103 from coverage import Coverage 

104 

105 cov = Coverage() 

106 cov.start() 

107 #.. call your code .. 

108 cov.stop() 

109 cov.html_report(directory="covhtml") 

110 

111 A context manager is available to do the same thing:: 

112 

113 cov = Coverage() 

114 with cov.collect(): 

115 #.. call your code .. 

116 cov.html_report(directory="covhtml") 

117 

118 Note: in keeping with Python custom, names starting with underscore are 

119 not part of the public API. They might stop working at any point. Please 

120 limit yourself to documented methods to avoid problems. 

121 

122 Methods can raise any of the exceptions described in :ref:`api_exceptions`. 

123 

124 """ 

125 

126 # The stack of started Coverage instances. 

127 _instances: list[Coverage] = [] 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

128 

129 @classmethod 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

130 def current(cls) -> Coverage | None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

131 """Get the latest started `Coverage` instance, if any. 

132 

133 Returns: a `Coverage` instance, or None. 

134 

135 .. versionadded:: 5.0 

136 

137 """ 

138 if cls._instances: 138 ↛ 141line 138 didn't jump to line 141 because the condition on line 138 was always true1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

139 return cls._instances[-1] 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

140 else: 

141 return None 

142 

143 def __init__( # pylint: disable=too-many-arguments 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

144 self, 

145 data_file: FilePath | DefaultValue | None = DEFAULT_DATAFILE, 

146 data_suffix: str | bool | None = None, 

147 cover_pylib: bool | None = None, 

148 auto_data: bool = False, 

149 timid: bool | None = None, 

150 branch: bool | None = None, 

151 config_file: FilePath | bool = True, 

152 source: Iterable[str] | None = None, 

153 source_pkgs: Iterable[str] | None = None, 

154 source_dirs: Iterable[str] | None = None, 

155 omit: str | Iterable[str] | None = None, 

156 include: str | Iterable[str] | None = None, 

157 debug: Iterable[str] | None = None, 

158 concurrency: str | Iterable[str] | None = None, 

159 check_preimported: bool = False, 

160 context: str | None = None, 

161 messages: bool = False, 

162 plugins: Iterable[Callable[..., None]] | None = None, 

163 ) -> None: 

164 """ 

165 Many of these arguments duplicate and override values that can be 

166 provided in a configuration file. Parameters that are missing here 

167 will use values from the config file. 

168 

169 `data_file` is the base name of the data file to use. The config value 

170 defaults to ".coverage". None can be provided to prevent writing a data 

171 file. `data_suffix` is appended (with a dot) to `data_file` to create 

172 the final file name. If `data_suffix` is simply True, then a suffix is 

173 created with the machine and process identity included. 

174 

175 `cover_pylib` is a boolean determining whether Python code installed 

176 with the Python interpreter is measured. This includes the Python 

177 standard library and any packages installed with the interpreter. 

178 

179 If `auto_data` is true, then any existing data file will be read when 

180 coverage measurement starts, and data will be saved automatically when 

181 measurement stops. 

182 

183 If `timid` is true, then a slower and simpler trace function will be 

184 used. This is important for some environments where manipulation of 

185 tracing functions breaks the faster trace function. 

186 

187 If `branch` is true, then branch coverage will be measured in addition 

188 to the usual statement coverage. 

189 

190 `config_file` determines what configuration file to read: 

191 

192 * If it is ".coveragerc", it is interpreted as if it were True, 

193 for backward compatibility. 

194 

195 * If it is a string, it is the name of the file to read. If the 

196 file can't be read, it is an error. 

197 

198 * If it is True, then a few standard files names are tried 

199 (".coveragerc", "setup.cfg", "tox.ini"). It is not an error for 

200 these files to not be found. 

201 

202 * If it is False, then no configuration file is read. 

203 

204 `source` is a list of file paths or package names. Only code located 

205 in the trees indicated by the file paths or package names will be 

206 measured. 

207 

208 `source_pkgs` is a list of package names. It works the same as 

209 `source`, but can be used to name packages where the name can also be 

210 interpreted as a file path. 

211 

212 `source_dirs` is a list of file paths. It works the same as 

213 `source`, but raises an error if the path doesn't exist, rather 

214 than being treated as a package name. 

215 

216 `include` and `omit` are lists of file name patterns. Files that match 

217 `include` will be measured, files that match `omit` will not. Each 

218 will also accept a single string argument. 

219 

220 `debug` is a list of strings indicating what debugging information is 

221 desired. 

222 

223 `concurrency` is a string indicating the concurrency library being used 

224 in the measured code. Without this, coverage.py will get incorrect 

225 results if these libraries are in use. Valid strings are "greenlet", 

226 "eventlet", "gevent", "multiprocessing", or "thread" (the default). 

227 This can also be a list of these strings. 

228 

229 If `check_preimported` is true, then when coverage is started, the 

230 already-imported files will be checked to see if they should be 

231 measured by coverage. Importing measured files before coverage is 

232 started can mean that code is missed. 

233 

234 `context` is a string to use as the :ref:`static context 

235 <static_contexts>` label for collected data. 

236 

237 If `messages` is true, some messages will be printed to stdout 

238 indicating what is happening. 

239 

240 If `plugins` are passed, they are an iterable of function objects 

241 accepting a `reg` object to register plugins, as described in 

242 :ref:`api_plugin`. When they are provided, they will override the 

243 plugins found in the coverage configuration file. 

244 

245 .. versionadded:: 4.0 

246 The `concurrency` parameter. 

247 

248 .. versionadded:: 4.2 

249 The `concurrency` parameter can now be a list of strings. 

250 

251 .. versionadded:: 5.0 

252 The `check_preimported` and `context` parameters. 

253 

254 .. versionadded:: 5.3 

255 The `source_pkgs` parameter. 

256 

257 .. versionadded:: 6.0 

258 The `messages` parameter. 

259 

260 .. versionadded:: 7.7 

261 The `plugins` parameter. 

262 

263 .. versionadded:: 7.8 

264 The `source_dirs` parameter. 

265 """ 

266 # Start self.config as a usable default configuration. It will soon be 

267 # replaced with the real configuration. 

268 self.config = CoverageConfig() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

269 

270 # data_file=None means no disk file at all. data_file missing means 

271 # use the value from the config file. 

272 self._no_disk = data_file is None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

273 if isinstance(data_file, DefaultValue): 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

274 data_file = None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

275 if data_file is not None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

276 data_file = os.fspath(data_file) 1satbTKucvdULwexfVMygzhWNAiBjXOCkDl8YPEm5Fn9ZQGoHp#0RIq$Jr61S234

277 

278 # This is injectable by tests. 

279 self._debug_file: IO[str] | None = None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

280 

281 self._auto_load = self._auto_save = auto_data 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

282 self._data_suffix_specified = data_suffix 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

283 

284 # Is it ok for no data to be collected? 

285 self._warn_no_data = True 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

286 self._warn_unimported_source = True 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

287 self._warn_preimported_source = check_preimported 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

288 self._no_warn_slugs: set[str] = set() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

289 self._messages = messages 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

290 

291 # If we're invoked from a .pth file, we shouldn't try to make another one. 

292 self._make_pth_file = True 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

293 

294 # A record of all the warnings that have been issued. 

295 self._warnings: list[str] = [] 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

296 

297 # Other instance attributes, set with placebos or placeholders. 

298 # More useful objects will be created later. 

299 self._debug: DebugControl = NoDebugging() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

300 self._inorout: InOrOut | None = None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

301 self._plugins: Plugins = Plugins() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

302 self._plugin_override = cast(Iterable[TCoverageInit] | None, plugins) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

303 self._data: CoverageData | None = None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

304 self._data_to_close: list[CoverageData] = [] 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

305 self._core: Core | None = None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

306 self._collector: Collector | None = None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

307 self._metacov = False 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

308 

309 self._file_mapper: Callable[[str], str] = abs_file 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

310 self._data_suffix = self._run_suffix = None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

311 self._exclude_re: dict[str, str] = {} 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

312 self._old_sigterm: Callable[[int, FrameType | None], Any] | None = None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

313 

314 # State machine variables: 

315 # Have we initialized everything? 

316 self._inited = False 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

317 self._inited_for_start = False 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

318 # Have we started collecting and not stopped it? 

319 self._started = False 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

320 # Should we write the debug output? 

321 self._should_write_debug = True 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

322 

323 # Build our configuration from a number of sources. 

324 if isinstance(config_file, str) and config_file.startswith(CONFIG_DATA_PREFIX): 324 ↛ 325line 324 didn't jump to line 325 because the condition on line 324 was never true1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

325 self.config = CoverageConfig.deserialize(config_file[len(CONFIG_DATA_PREFIX) :]) 

326 else: 

327 if not isinstance(config_file, bool): 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

328 config_file = os.fspath(config_file) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

329 self.config = read_coverage_config( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

330 config_file=config_file, 

331 warn=self._warn, 

332 data_file=data_file, 

333 cover_pylib=cover_pylib, 

334 timid=timid, 

335 branch=branch, 

336 parallel=bool_or_none(data_suffix), 

337 source=source, 

338 source_pkgs=source_pkgs, 

339 source_dirs=source_dirs, 

340 run_omit=omit, 

341 run_include=include, 

342 debug=debug, 

343 report_omit=omit, 

344 report_include=include, 

345 concurrency=concurrency, 

346 context=context, 

347 ) 

348 

349 # If we have subprocess measurement happening automatically, then we 

350 # want any explicit creation of a Coverage object to mean, this process 

351 # is already coverage-aware, so don't auto-measure it. By now, the 

352 # auto-creation of a Coverage object has already happened. But we can 

353 # find it and tell it not to save its data. 

354 if not env.METACOV: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

355 _prevent_sub_process_measurement() 

356 

357 def __repr__(self) -> str: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

358 assert self._core is not None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

359 assert self._data is not None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

360 return ( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

361 "<Coverage" 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

362 + f" @0x{id(self):x}" 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

363 + f" core={self._core.tracer_class.__name__}" 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

364 + f" data_file={self._data._filename!r}" 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

365 + ">" 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

366 ) 

367 

368 def _init(self) -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

369 """Set all the initial state. 

370 

371 This is called by the public methods to initialize state. This lets us 

372 construct a :class:`Coverage` object, then tweak its state before this 

373 function is called. 

374 

375 """ 

376 if self._inited: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

377 return 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

378 

379 self._inited = True 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

380 

381 # Create and configure the debugging controller. 

382 self._debug = DebugControl(self.config.debug, self._debug_file, self.config.debug_file) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

383 if self._debug.should("process"): 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

384 self._debug.write("Coverage._init") 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YPEm5Fn9ZQGo!Hp#0RIq$Jr61S234

385 

386 if "multiprocessing" in (self.config.concurrency or ()): 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

387 # Multi-processing uses parallel for the subprocesses, so also use 

388 # it for the main process. 

389 self.config.parallel = True 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

390 

391 # _exclude_re is a dict that maps exclusion list names to compiled regexes. 

392 self._exclude_re = {} 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

393 

394 set_relative_directory() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

395 if self.config.relative_files: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

396 self._file_mapper = relative_filename 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYP%EmFnZQGoHp0RIqJr1S234

397 

398 # Load plugins 

399 self._plugins = Plugins(self._debug) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

400 if self._plugin_override: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

401 self._plugins.load_from_callables(self._plugin_override) 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGoHp0RIqJr1S234

402 else: 

403 self._plugins.load_from_config(self.config.plugins, self.config) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

404 

405 # Run configuring plugins. 

406 for plugin in self._plugins.configurers: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

407 # We need an object with set_option and get_option. Either self or 

408 # self.config will do. Choosing randomly stops people from doing 

409 # other things with those objects, against the public API. Yes, 

410 # this is a bit childish. :) 

411 plugin.configure([self, self.config][int(time.time()) % 2]) 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGoHp0RIqJr1S234

412 

413 def _post_init(self) -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

414 """Stuff to do after everything is initialized.""" 

415 if self._should_write_debug: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

416 self._should_write_debug = False 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

417 self._write_startup_debug() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

418 

419 # "[run] _crash" will raise an exception if the value is close by in 

420 # the call stack, for testing error handling. 

421 if self.config._crash and self.config._crash in short_stack(): 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

422 raise RuntimeError(f"Crashing because called by {self.config._crash}") 1satbTKucvdULwexfVMygzhWNAiBjXOCk7DlYP%Em5FnZQ'Go!Hp0R(Iq$Jr1S)234

423 

424 def _write_startup_debug(self) -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

425 """Write out debug info at startup if needed.""" 

426 wrote_any = False 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

427 with self._debug.without_callers(): 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

428 if self._debug.should("config"): 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

429 write_formatted_info(self._debug.write, "config", self.config.debug_info()) 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGoHp0RIqJr1S234

430 wrote_any = True 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGoHp0RIqJr1S234

431 

432 if self._debug.should("sys"): 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

433 write_formatted_info(self._debug.write, "sys", self.sys_info()) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

434 for plugin in self._plugins: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

435 header = "sys: " + plugin._coverage_plugin_name 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGoHp0RIqJr1S234

436 write_formatted_info(self._debug.write, header, plugin.sys_info()) 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGoHp0RIqJr1S234

437 wrote_any = True 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

438 

439 if self._debug.should("pybehave"): 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

440 write_formatted_info(self._debug.write, "pybehave", env.debug_info()) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

441 wrote_any = True 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

442 

443 if self._debug.should("sqlite"): 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

444 write_formatted_info(self._debug.write, "sqlite", CoverageData.sys_info()) 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGoHp0RIqJr1S234

445 wrote_any = True 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGoHp0RIqJr1S234

446 

447 if wrote_any: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

448 write_formatted_info(self._debug.write, "end", ()) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

449 

450 def _should_trace(self, filename: str, frame: FrameType) -> TFileDisposition: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

451 """Decide whether to trace execution in `filename`. 

452 

453 Calls `_should_trace_internal`, and returns the FileDisposition. 

454 

455 """ 

456 assert self._inorout is not None 

457 disp = self._inorout.should_trace(filename, frame) 

458 if self._debug.should("trace"): 

459 self._debug.write(disposition_debug_msg(disp)) 

460 return disp 

461 

462 def _check_include_omit_etc(self, filename: str, frame: FrameType) -> bool: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

463 """Check a file name against the include/omit/etc, rules, verbosely. 

464 

465 Returns a boolean: True if the file should be traced, False if not. 

466 

467 """ 

468 assert self._inorout is not None 

469 reason = self._inorout.check_include_omit_etc(filename, frame) 

470 if self._debug.should("trace"): 

471 if not reason: 

472 msg = f"Including {filename!r}" 

473 else: 

474 msg = f"Not including {filename!r}: {reason}" 

475 self._debug.write(msg) 

476 

477 return not reason 

478 

479 def _warn(self, msg: str, slug: str | None = None, once: bool = False) -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

480 """Use `msg` as a warning. 

481 

482 For warning suppression, use `slug` as the shorthand. 

483 

484 If `once` is true, only show this warning once (determined by the 

485 slug.) 

486 

487 """ 

488 if not self._no_warn_slugs: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

489 self._no_warn_slugs = set(self.config.disable_warnings) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

490 

491 if slug in self._no_warn_slugs: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

492 # Don't issue the warning 

493 return 1satbTKucvdULwexfVMygzhWNAiBjXOCkDl8YP%EmFn9ZQ'GoHp#0R(IqJr61S)234

494 

495 self._warnings.append(msg) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

496 if slug: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

497 msg = f"{msg} ({slug}); see {__url__}/messages.html#warning-{slug}" 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

498 if self._debug.should("pid"): 498 ↛ 499line 498 didn't jump to line 499 because the condition on line 498 was never true1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

499 msg = f"[{os.getpid()}] {msg}" 

500 warnings.warn(msg, category=CoverageWarning, stacklevel=2) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

501 

502 if once: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

503 assert slug is not None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'GoHp#0R(IqJr1S)234

504 self._no_warn_slugs.add(slug) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'GoHp#0R(IqJr1S)234

505 

506 def _message(self, msg: str) -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

507 """Write a message to the user, if configured to do so.""" 

508 if self._messages: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

509 print(msg) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

510 

511 def get_option(self, option_name: str) -> TConfigValueOut | None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

512 """Get an option from the configuration. 

513 

514 `option_name` is a colon-separated string indicating the section and 

515 option name. For example, the ``branch`` option in the ``[run]`` 

516 section of the config file would be indicated with `"run:branch"`. 

517 

518 Returns the value of the option. The type depends on the option 

519 selected. 

520 

521 As a special case, an `option_name` of ``"paths"`` will return an 

522 dictionary with the entire ``[paths]`` section value. 

523 

524 .. versionadded:: 4.0 

525 

526 """ 

527 return self.config.get_option(option_name) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

528 

529 def set_option(self, option_name: str, value: TConfigValueIn | TConfigSectionIn) -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

530 """Set an option in the configuration. 

531 

532 `option_name` is a colon-separated string indicating the section and 

533 option name. For example, the ``branch`` option in the ``[run]`` 

534 section of the config file would be indicated with ``"run:branch"``. 

535 

536 `value` is the new value for the option. This should be an 

537 appropriate Python value. For example, use True for booleans, not the 

538 string ``"True"``. 

539 

540 As an example, calling: 

541 

542 .. code-block:: python 

543 

544 cov.set_option("run:branch", True) 

545 

546 has the same effect as this configuration file: 

547 

548 .. code-block:: ini 

549 

550 [run] 

551 branch = True 

552 

553 As a special case, an `option_name` of ``"paths"`` will replace the 

554 entire ``[paths]`` section. The value should be a dictionary. 

555 

556 .. versionadded:: 4.0 

557 

558 """ 

559 self.config.set_option(option_name, value) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

560 

561 def load(self) -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

562 """Load previously-collected coverage data from the data file.""" 

563 self._init() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

564 if self._collector is not None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

565 self._collector.reset() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

566 should_skip = self.config.parallel and not os.path.exists(self.config.data_file) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

567 if not should_skip: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

568 self._init_data(suffix=None) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

569 self._post_init() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

570 if not should_skip: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

571 assert self._data is not None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

572 self._data.read() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

573 

574 def _init_for_start(self) -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

575 """Initialization for start()""" 

576 # Construct the collector. 

577 concurrency: list[str] = self.config.concurrency 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

578 if "multiprocessing" in concurrency: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

579 if self.config.config_file is None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

580 raise ConfigError("multiprocessing requires a configuration file") 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGoHp0RIqJr1S234

581 patch_multiprocessing(rcfile=self.config.config_file) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

582 

583 dycon = self.config.dynamic_context 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

584 if not dycon or dycon == "none": 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

585 context_switchers = [] 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

586 elif dycon == "test_function": 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

587 context_switchers = [should_start_context_test_function] 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

588 else: 

589 raise ConfigError(f"Don't understand dynamic_context setting: {dycon!r}") 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGoHp0RIqJr1S234

590 

591 context_switchers.extend( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

592 plugin.dynamic_context for plugin in self._plugins.context_switchers 

593 ) 

594 

595 should_start_context = combine_context_switchers(context_switchers) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

596 

597 self._core = Core( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

598 warn=self._warn, 

599 debug=(self._debug if self._debug.should("core") else None), 

600 config=self.config, 

601 dynamic_contexts=(should_start_context is not None), 

602 metacov=self._metacov, 

603 ) 

604 self._collector = Collector( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

605 core=self._core, 

606 should_trace=self._should_trace, 

607 check_include=self._check_include_omit_etc, 

608 should_start_context=should_start_context, 

609 file_mapper=self._file_mapper, 

610 branch=self.config.branch, 

611 warn=self._warn, 

612 concurrency=concurrency, 

613 ) 

614 

615 suffix = self._data_suffix_specified 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

616 if suffix: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

617 if not isinstance(suffix, str): 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

618 # if data_suffix=True, use .machinename.pid.random 

619 suffix = True 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

620 elif self.config.parallel: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

621 if suffix is None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

622 suffix = True 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

623 elif not isinstance(suffix, str): 623 ↛ 628line 623 didn't jump to line 628 because the condition on line 623 was always true1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGoHp0RIqJr1S234

624 suffix = bool(suffix) 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGoHp0RIqJr1S234

625 else: 

626 suffix = None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

627 

628 self._init_data(suffix) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

629 

630 assert self._data is not None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

631 self._collector.use_data(self._data, self.config.context) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

632 

633 # Early warning if we aren't going to be able to support plugins. 

634 if self._plugins.file_tracers and not self._core.supports_plugins: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

635 self._warn( 1abKcdLefMghNijOk7l8P%m5n9Q'o!p#R(q$r6S)234

636 "Plugin file tracers ({}) aren't supported with {}".format( 

637 ", ".join( 

638 plugin._coverage_plugin_name for plugin in self._plugins.file_tracers 

639 ), 

640 self._collector.tracer_name(), 

641 ), 

642 ) 

643 for plugin in self._plugins.file_tracers: 1abKcdLefMghNijOklPmnQopRqrS234

644 plugin._coverage_enabled = False 1abKcdLefMghNijOklPmnQopRqrS234

645 

646 # Create the file classifying substructure. 

647 self._inorout = InOrOut( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

648 config=self.config, 

649 warn=self._warn, 

650 debug=(self._debug if self._debug.should("trace") else None), 

651 include_namespace_packages=self.config.include_namespace_packages, 

652 ) 

653 self._inorout.plugins = self._plugins 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

654 self._inorout.disp_class = self._core.file_disposition_class 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

655 

656 # It's useful to write debug info after initing for start. 

657 self._should_write_debug = True 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

658 

659 # Register our clean-up handlers. 

660 atexit.register(self._atexit) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

661 if self.config.sigterm: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

662 is_main = (threading.current_thread() == threading.main_thread()) # fmt: skip 1satbucvdwexfygzhAiBjCk7Dl8Em5Fn9Go!Hp#Iq$Jr623

663 if is_main and not env.WINDOWS: 663 ↛ exitline 663 didn't return from function '_init_for_start' because the condition on line 663 was always true1satbucvdwexfygzhAiBjCk7Dl8Em5Fn9Go!Hp#Iq$Jr623

664 # The Python docs seem to imply that SIGTERM works uniformly even 

665 # on Windows, but that's not my experience, and this agrees: 

666 # https://stackoverflow.com/questions/35772001/x/35792192#35792192 

667 self._old_sigterm = signal.signal( # type: ignore[assignment] 1satbucvdwexfygzhAiBjCk7Dl8Em5Fn9Go!Hp#Iq$Jr623

668 signal.SIGTERM, 

669 self._on_sigterm, 

670 ) 

671 

672 def _init_data(self, suffix: str | bool | None) -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

673 """Create a data file if we don't have one yet.""" 

674 if self._data is None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

675 # Create the data file. We do this at construction time so that the 

676 # data file will be written into the directory where the process 

677 # started rather than wherever the process eventually chdir'd to. 

678 ensure_dir_for_file(self.config.data_file) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

679 self._data = CoverageData( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

680 basename=self.config.data_file, 

681 suffix=suffix, 

682 warn=self._warn, 

683 debug=self._debug, 

684 no_disk=self._no_disk, 

685 ) 

686 self._data_to_close.append(self._data) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

687 

688 def start(self) -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

689 """Start measuring code coverage. 

690 

691 Coverage measurement is only collected in functions called after 

692 :meth:`start` is invoked. Statements in the same scope as 

693 :meth:`start` won't be measured. 

694 

695 Once you invoke :meth:`start`, you must also call :meth:`stop` 

696 eventually, or your process might not shut down cleanly. 

697 

698 The :meth:`collect` method is a context manager to handle both 

699 starting and stopping collection. 

700 

701 """ 

702 self._init() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

703 if not self._inited_for_start: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

704 self._inited_for_start = True 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

705 self._init_for_start() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

706 self._post_init() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

707 

708 assert self._collector is not None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

709 assert self._inorout is not None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

710 

711 # Issue warnings for possible problems. 

712 self._inorout.warn_conflicting_settings() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

713 

714 # See if we think some code that would eventually be measured has 

715 # already been imported. 

716 if self._warn_preimported_source: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

717 self._inorout.warn_already_imported_files() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

718 

719 if self._auto_load: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

720 self.load() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

721 

722 apply_patches(self, self.config, self._debug, make_pth_file=self._make_pth_file) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

723 

724 self._collector.start() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

725 self._started = True 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

726 self._instances.append(self) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

727 

728 def stop(self) -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

729 """Stop measuring code coverage.""" 

730 if self._instances: 730 ↛ 733line 730 didn't jump to line 733 because the condition on line 730 was always true1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

731 if self._instances[-1] is self: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

732 self._instances.pop() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

733 if self._started: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

734 assert self._collector is not None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

735 self._collector.stop() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

736 self._started = False 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

737 

738 @contextlib.contextmanager 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

739 def collect(self) -> Iterator[None]: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

740 """A context manager to start/stop coverage measurement collection. 

741 

742 .. versionadded:: 7.3 

743 

744 """ 

745 self.start() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

746 try: 1abKcdLefMghNijOklPmnQopRqrS234

747 yield 1abKcdLefMghNijOklPmnQopRqrS234

748 finally: 

749 self.stop() # pragma: nested 

750 

751 def _atexit(self, event: str = "atexit") -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

752 """Clean up on process shutdown.""" 

753 if self._debug.should("process"): 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

754 self._debug.write(f"{event}: pid: {os.getpid()}, instance: {self!r}") 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

755 if self._started: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

756 self.stop() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

757 if self._auto_save or event == "sigterm": 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

758 self.save() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

759 for d in self._data_to_close: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

760 d.close(force=True) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

761 

762 def _on_sigterm(self, signum_unused: int, frame_unused: FrameType | None) -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

763 """A handler for signal.SIGTERM.""" 

764 self._atexit("sigterm") 

765 # Statements after here won't be seen by metacov because we just wrote 

766 # the data, and are about to kill the process. 

767 signal.signal(signal.SIGTERM, self._old_sigterm) # pragma: not covered 

768 os.kill(os.getpid(), signal.SIGTERM) # pragma: not covered 

769 

770 def erase(self) -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

771 """Erase previously collected coverage data. 

772 

773 This removes the in-memory data collected in this session as well as 

774 discarding the data file. 

775 

776 """ 

777 self._init() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

778 self._post_init() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

779 if self._collector is not None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

780 self._collector.reset() 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGoHp0RIqJr1S234

781 self._init_data(suffix=None) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

782 assert self._data is not None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

783 self._data.erase(parallel=self.config.parallel) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

784 self._data = None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

785 self._inited_for_start = False 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

786 

787 def switch_context(self, new_context: str) -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

788 """Switch to a new dynamic context. 

789 

790 `new_context` is a string to use as the :ref:`dynamic context 

791 <dynamic_contexts>` label for collected data. If a :ref:`static 

792 context <static_contexts>` is in use, the static and dynamic context 

793 labels will be joined together with a pipe character. 

794 

795 Coverage collection must be started already. 

796 

797 .. versionadded:: 5.0 

798 

799 """ 

800 if not self._started: # pragma: part started 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGoHp0RIqJr1S234

801 raise CoverageException("Cannot switch context, coverage is not started") 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGoHp0RIqJr1S234

802 

803 assert self._collector is not None 

804 if self._collector.should_start_context: 

805 self._warn("Conflicting dynamic contexts", slug="dynamic-conflict", once=True) 

806 

807 self._collector.switch_context(new_context) 

808 

809 def clear_exclude(self, which: str = "exclude") -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

810 """Clear the exclude list.""" 

811 self._init() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

812 setattr(self.config, f"{which}_list", []) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

813 self._exclude_regex_stale() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

814 

815 def exclude(self, regex: str, which: str = "exclude") -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

816 """Exclude source lines from execution consideration. 

817 

818 A number of lists of regular expressions are maintained. Each list 

819 selects lines that are treated differently during reporting. 

820 

821 `which` determines which list is modified. The "exclude" list selects 

822 lines that are not considered executable at all. The "partial" list 

823 indicates lines with branches that are not taken. 

824 

825 `regex` is a regular expression. The regex is added to the specified 

826 list. If any of the regexes in the list is found in a line, the line 

827 is marked for special treatment during reporting. 

828 

829 """ 

830 self._init() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

831 excl_list = getattr(self.config, f"{which}_list") 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

832 excl_list.append(regex) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

833 self._exclude_regex_stale() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

834 

835 def _exclude_regex_stale(self) -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

836 """Drop all the compiled exclusion regexes, a list was modified.""" 

837 self._exclude_re.clear() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

838 

839 def _exclude_regex(self, which: str) -> str: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

840 """Return a regex string for the given exclusion list.""" 

841 if which not in self._exclude_re: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

842 excl_list = getattr(self.config, f"{which}_list") 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

843 self._exclude_re[which] = join_regex(excl_list) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

844 return self._exclude_re[which] 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

845 

846 def get_exclude_list(self, which: str = "exclude") -> list[str]: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

847 """Return a list of excluded regex strings. 

848 

849 `which` indicates which list is desired. See :meth:`exclude` for the 

850 lists that are available, and their meaning. 

851 

852 """ 

853 self._init() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

854 return cast(list[str], getattr(self.config, f"{which}_list")) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

855 

856 def save(self) -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

857 """Save the collected coverage data to the data file.""" 

858 data = self.get_data() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

859 data.write() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

860 

861 def _make_aliases(self) -> PathAliases: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

862 """Create a PathAliases from our configuration.""" 

863 aliases = PathAliases( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

864 debugfn=(self._debug.write if self._debug.should("pathmap") else None), 

865 relative=self.config.relative_files, 

866 ) 

867 for paths in self.config.paths.values(): 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

868 result = paths[0] 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

869 for pattern in paths[1:]: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

870 aliases.add(pattern, result) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

871 return aliases 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

872 

873 def combine( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

874 self, 

875 data_paths: Iterable[str] | None = None, 

876 strict: bool = False, 

877 keep: bool = False, 

878 ) -> None: 

879 """Combine together a number of similarly-named coverage data files. 

880 

881 All coverage data files whose name starts with `data_file` (from the 

882 coverage() constructor) will be read, and combined together into the 

883 current measurements. 

884 

885 `data_paths` is a list of files or directories from which data should 

886 be combined. If no list is passed, then the data files from the 

887 directory indicated by the current data file (probably the current 

888 directory) will be combined. 

889 

890 If `strict` is true, then it is an error to attempt to combine when 

891 there are no data files to combine. 

892 

893 If `keep` is true, then original input data files won't be deleted. 

894 

895 .. versionadded:: 4.0 

896 The `data_paths` parameter. 

897 

898 .. versionadded:: 4.3 

899 The `strict` parameter. 

900 

901 .. versionadded: 5.5 

902 The `keep` parameter. 

903 """ 

904 self._init() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

905 self._init_data(suffix=None) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

906 self._post_init() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

907 self.get_data() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

908 

909 assert self._data is not None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

910 combine_parallel_data( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

911 self._data, 

912 aliases=self._make_aliases(), 

913 data_paths=data_paths, 

914 strict=strict, 

915 keep=keep, 

916 message=self._message, 

917 ) 

918 

919 def get_data(self) -> CoverageData: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

920 """Get the collected data. 

921 

922 Also warn about various problems collecting data. 

923 

924 Returns a :class:`coverage.CoverageData`, the collected coverage data. 

925 

926 .. versionadded:: 4.0 

927 

928 """ 

929 self._init() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

930 self._init_data(suffix=None) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

931 self._post_init() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

932 

933 if self._collector is not None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

934 for plugin in self._plugins: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

935 if not plugin._coverage_enabled: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

936 self._collector.plugin_was_disabled(plugin) 1stTuvUwxVyzWABXCDYEFZGH0IJ1

937 

938 if self._collector.flush_data(): 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

939 self._post_save_work() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

940 

941 assert self._data is not None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

942 return self._data 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

943 

944 def _post_save_work(self) -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

945 """After saving data, look for warnings, post-work, etc. 

946 

947 Warn about things that should have happened but didn't. 

948 Look for un-executed files. 

949 

950 """ 

951 assert self._data is not None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

952 assert self._inorout is not None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

953 

954 # If there are still entries in the source_pkgs_unmatched list, 

955 # then we never encountered those packages. 

956 if self._warn_unimported_source: 956 ↛ 960line 956 didn't jump to line 960 because the condition on line 956 was always true1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

957 self._inorout.warn_unimported_source() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

958 

959 # Find out if we got any data. 

960 if not self._data and self._warn_no_data: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

961 self._warn("No data was collected.", slug="no-data-collected") 1satbTKucvdULwexfVMygzhWNAiBjXOCk7DlYP%Em5FnZQ'Go!Hp0R(Iq$Jr1S)234

962 

963 # Touch all the files that could have executed, so that we can 

964 # mark completely un-executed files as 0% covered. 

965 file_paths = collections.defaultdict(list) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

966 for file_path, plugin_name in self._inorout.find_possibly_unexecuted_files(): 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

967 file_path = self._file_mapper(file_path) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

968 file_paths[plugin_name].append(file_path) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

969 for plugin_name, paths in file_paths.items(): 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

970 self._data.touch_files(paths, plugin_name) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

971 

972 # Backward compatibility with version 1. 

973 def analysis(self, morf: TMorf) -> tuple[str, list[TLineNo], list[TLineNo], str]: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

974 """Like `analysis2` but doesn't return excluded line numbers.""" 

975 f, s, _, m, mf = self.analysis2(morf) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

976 return f, s, m, mf 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

977 

978 def analysis2( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

979 self, 

980 morf: TMorf, 

981 ) -> tuple[str, list[TLineNo], list[TLineNo], list[TLineNo], str]: 

982 """Analyze a module. 

983 

984 `morf` is a module or a file name. It will be analyzed to determine 

985 its coverage statistics. The return value is a 5-tuple: 

986 

987 * The file name for the module. 

988 * A list of line numbers of executable statements. 

989 * A list of line numbers of excluded statements. 

990 * A list of line numbers of statements not run (missing from 

991 execution). 

992 * A readable formatted string of the missing line numbers. 

993 

994 The analysis uses the source file itself and the current measured 

995 coverage data. 

996 

997 """ 

998 analysis = self._analyze(morf) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

999 return ( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1000 analysis.filename, 

1001 sorted(analysis.statements), 

1002 sorted(analysis.excluded), 

1003 sorted(analysis.missing), 

1004 analysis.missing_formatted(), 

1005 ) 

1006 

1007 @functools.lru_cache(maxsize=1) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1008 def _analyze(self, morf: TMorf) -> Analysis: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1009 """Analyze a module or file. Private for now.""" 

1010 self._init() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1011 self._post_init() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1012 

1013 data = self.get_data() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1014 file_reporter = self._get_file_reporter(morf) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1015 filename = self._file_mapper(file_reporter.filename) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1016 return analysis_from_file_reporter(data, self.config.precision, file_reporter, filename) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1017 

1018 def branch_stats(self, morf: TMorf) -> dict[TLineNo, tuple[int, int]]: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1019 """Get branch statistics about a module. 

1020 

1021 `morf` is a module or a file name. 

1022 

1023 Returns a dict mapping line numbers to a tuple: 

1024 (total_exits, taken_exits). 

1025 

1026 .. versionadded:: 7.7 

1027 

1028 """ 

1029 analysis = self._analyze(morf) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1030 return analysis.branch_stats() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1031 

1032 @functools.lru_cache(maxsize=1) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1033 def _get_file_reporter(self, morf: TMorf) -> FileReporter: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1034 """Get a FileReporter for a module or file name.""" 

1035 assert self._data is not None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1036 plugin = None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1037 file_reporter: str | FileReporter = "python" 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1038 

1039 if isinstance(morf, str): 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1040 mapped_morf = self._file_mapper(morf) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1041 plugin_name = self._data.file_tracer(mapped_morf) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1042 if plugin_name: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1043 plugin = self._plugins.get(plugin_name) 1stTuvUwxVyzWABXCDYEFZGH0IJ1

1044 

1045 if plugin: 1045 ↛ 1055line 1045 didn't jump to line 1055 because the condition on line 1045 was always true1stTuvUwxVyzWABXCDYEFZGH0IJ1

1046 file_reporter = plugin.file_reporter(mapped_morf) 1stTuvUwxVyzWABXCDYEFZGH0IJ1

1047 if file_reporter is None: 1047 ↛ 1048line 1047 didn't jump to line 1048 because the condition on line 1047 was never true1stTuvUwxVyzWABXCDYEFZGH0IJ1

1048 raise PluginError( 

1049 "Plugin {!r} did not provide a file reporter for {!r}.".format( 

1050 plugin._coverage_plugin_name, 

1051 morf, 

1052 ), 

1053 ) 

1054 

1055 if file_reporter == "python": 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1056 file_reporter = PythonFileReporter(morf, self) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1057 

1058 assert isinstance(file_reporter, FileReporter) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1059 return file_reporter 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1060 

1061 def _get_file_reporters( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

1062 self, 

1063 morfs: Iterable[TMorf] | None = None, 

1064 ) -> list[tuple[FileReporter, TMorf]]: 

1065 """Get FileReporters for a list of modules or file names. 

1066 

1067 For each module or file name in `morfs`, find a FileReporter. Return 

1068 a list pairing FileReporters with the morfs. 

1069 

1070 If `morfs` is a single module or file name, this returns a list of one 

1071 FileReporter. If `morfs` is empty or None, then the list of all files 

1072 measured is used to find the FileReporters. 

1073 

1074 """ 

1075 assert self._data is not None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1076 if not morfs: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1077 morfs = self._data.measured_files() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1078 

1079 # Be sure we have a collection. 

1080 if not isinstance(morfs, (list, tuple, set)): 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1081 morfs = [morfs] # type: ignore[list-item] 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YPEm5Fn9ZQGoHp0RIq$Jr1S234

1082 

1083 morfs = sorted(morfs, key=lambda m: m if isinstance(m, str) else m.__name__) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1084 return [(self._get_file_reporter(morf), morf) for morf in morfs] 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1085 

1086 def _prepare_data_for_reporting(self) -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1087 """Re-map data before reporting, to get implicit "combine" behavior.""" 

1088 if self.config.paths: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1089 mapped_data = CoverageData(warn=self._warn, debug=self._debug, no_disk=True) 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGoHp0RIqJr1S234

1090 if self._data is not None: 1090 ↛ 1092line 1090 didn't jump to line 1092 because the condition on line 1090 was always true1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGoHp0RIqJr1S234

1091 mapped_data.update(self._data, map_path=self._make_aliases().map) 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGoHp0RIqJr1S234

1092 self._data = mapped_data 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGoHp0RIqJr1S234

1093 self._data_to_close.append(mapped_data) 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGoHp0RIqJr1S234

1094 

1095 def report( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

1096 self, 

1097 morfs: Iterable[TMorf] | None = None, 

1098 show_missing: bool | None = None, 

1099 ignore_errors: bool | None = None, 

1100 file: IO[str] | None = None, 

1101 omit: str | list[str] | None = None, 

1102 include: str | list[str] | None = None, 

1103 skip_covered: bool | None = None, 

1104 contexts: list[str] | None = None, 

1105 skip_empty: bool | None = None, 

1106 precision: int | None = None, 

1107 sort: str | None = None, 

1108 output_format: str | None = None, 

1109 ) -> float: 

1110 """Write a textual summary report to `file`. 

1111 

1112 Each module in `morfs` is listed, with counts of statements, executed 

1113 statements, missing statements, and a list of lines missed. 

1114 

1115 If `show_missing` is true, then details of which lines or branches are 

1116 missing will be included in the report. If `ignore_errors` is true, 

1117 then a failure while reporting a single file will not stop the entire 

1118 report. 

1119 

1120 `file` is a file-like object, suitable for writing. 

1121 

1122 `output_format` determines the format, either "text" (the default), 

1123 "markdown", or "total". 

1124 

1125 `include` is a list of file name patterns. Files that match will be 

1126 included in the report. Files matching `omit` will not be included in 

1127 the report. 

1128 

1129 If `skip_covered` is true, don't report on files with 100% coverage. 

1130 

1131 If `skip_empty` is true, don't report on empty files (those that have 

1132 no statements). 

1133 

1134 `contexts` is a list of regular expression strings. Only data from 

1135 :ref:`dynamic contexts <dynamic_contexts>` that match one of those 

1136 expressions (using :func:`re.search <python:re.search>`) will be 

1137 included in the report. 

1138 

1139 `precision` is the number of digits to display after the decimal 

1140 point for percentages. 

1141 

1142 All of the arguments default to the settings read from the 

1143 :ref:`configuration file <config>`. 

1144 

1145 Returns a float, the total percentage covered. 

1146 

1147 .. versionadded:: 4.0 

1148 The `skip_covered` parameter. 

1149 

1150 .. versionadded:: 5.0 

1151 The `contexts` and `skip_empty` parameters. 

1152 

1153 .. versionadded:: 5.2 

1154 The `precision` parameter. 

1155 

1156 .. versionadded:: 7.0 

1157 The `format` parameter. 

1158 

1159 """ 

1160 self._prepare_data_for_reporting() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1161 with override_config( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1162 self, 

1163 ignore_errors=ignore_errors, 

1164 report_omit=omit, 

1165 report_include=include, 

1166 show_missing=show_missing, 

1167 skip_covered=skip_covered, 

1168 report_contexts=contexts, 

1169 skip_empty=skip_empty, 

1170 precision=precision, 

1171 sort=sort, 

1172 format=output_format, 

1173 ): 

1174 reporter = SummaryReporter(self) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1175 return reporter.report(morfs, outfile=file) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1176 

1177 def annotate( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

1178 self, 

1179 morfs: Iterable[TMorf] | None = None, 

1180 directory: str | None = None, 

1181 ignore_errors: bool | None = None, 

1182 omit: str | list[str] | None = None, 

1183 include: str | list[str] | None = None, 

1184 contexts: list[str] | None = None, 

1185 ) -> None: 

1186 """Annotate a list of modules. 

1187 

1188 Each module in `morfs` is annotated. The source is written to a new 

1189 file, named with a ",cover" suffix, with each line prefixed with a 

1190 marker to indicate the coverage of the line. Covered lines have ">", 

1191 excluded lines have "-", and missing lines have "!". 

1192 

1193 See :meth:`report` for other arguments. 

1194 

1195 """ 

1196 self._prepare_data_for_reporting() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1197 with override_config( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1198 self, 

1199 ignore_errors=ignore_errors, 

1200 report_omit=omit, 

1201 report_include=include, 

1202 report_contexts=contexts, 

1203 ): 

1204 reporter = AnnotateReporter(self) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1205 reporter.report(morfs, directory=directory) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1206 

1207 def html_report( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

1208 self, 

1209 morfs: Iterable[TMorf] | None = None, 

1210 directory: str | None = None, 

1211 ignore_errors: bool | None = None, 

1212 omit: str | list[str] | None = None, 

1213 include: str | list[str] | None = None, 

1214 extra_css: str | None = None, 

1215 title: str | None = None, 

1216 skip_covered: bool | None = None, 

1217 show_contexts: bool | None = None, 

1218 contexts: list[str] | None = None, 

1219 skip_empty: bool | None = None, 

1220 precision: int | None = None, 

1221 ) -> float: 

1222 """Generate an HTML report. 

1223 

1224 The HTML is written to `directory`. The file "index.html" is the 

1225 overview starting point, with links to more detailed pages for 

1226 individual modules. 

1227 

1228 `extra_css` is a path to a file of other CSS to apply on the page. 

1229 It will be copied into the HTML directory. 

1230 

1231 `title` is a text string (not HTML) to use as the title of the HTML 

1232 report. 

1233 

1234 See :meth:`report` for other arguments. 

1235 

1236 Returns a float, the total percentage covered. 

1237 

1238 .. note:: 

1239 

1240 The HTML report files are generated incrementally based on the 

1241 source files and coverage results. If you modify the report files, 

1242 the changes will not be considered. You should be careful about 

1243 changing the files in the report folder. 

1244 

1245 """ 

1246 self._prepare_data_for_reporting() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1247 with override_config( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1248 self, 

1249 ignore_errors=ignore_errors, 

1250 report_omit=omit, 

1251 report_include=include, 

1252 html_dir=directory, 

1253 extra_css=extra_css, 

1254 html_title=title, 

1255 html_skip_covered=skip_covered, 

1256 show_contexts=show_contexts, 

1257 report_contexts=contexts, 

1258 html_skip_empty=skip_empty, 

1259 precision=precision, 

1260 ): 

1261 reporter = HtmlReporter(self) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1262 return reporter.report(morfs) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1263 

1264 def xml_report( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

1265 self, 

1266 morfs: Iterable[TMorf] | None = None, 

1267 outfile: str | None = None, 

1268 ignore_errors: bool | None = None, 

1269 omit: str | list[str] | None = None, 

1270 include: str | list[str] | None = None, 

1271 contexts: list[str] | None = None, 

1272 skip_empty: bool | None = None, 

1273 ) -> float: 

1274 """Generate an XML report of coverage results. 

1275 

1276 The report is compatible with Cobertura reports. 

1277 

1278 Each module in `morfs` is included in the report. `outfile` is the 

1279 path to write the file to, "-" will write to stdout. 

1280 

1281 See :meth:`report` for other arguments. 

1282 

1283 Returns a float, the total percentage covered. 

1284 

1285 """ 

1286 self._prepare_data_for_reporting() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1287 with override_config( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1288 self, 

1289 ignore_errors=ignore_errors, 

1290 report_omit=omit, 

1291 report_include=include, 

1292 xml_output=outfile, 

1293 report_contexts=contexts, 

1294 skip_empty=skip_empty, 

1295 ): 

1296 return render_report(self.config.xml_output, XmlReporter(self), morfs, self._message) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1297 

1298 def json_report( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

1299 self, 

1300 morfs: Iterable[TMorf] | None = None, 

1301 outfile: str | None = None, 

1302 ignore_errors: bool | None = None, 

1303 omit: str | list[str] | None = None, 

1304 include: str | list[str] | None = None, 

1305 contexts: list[str] | None = None, 

1306 pretty_print: bool | None = None, 

1307 show_contexts: bool | None = None, 

1308 ) -> float: 

1309 """Generate a JSON report of coverage results. 

1310 

1311 Each module in `morfs` is included in the report. `outfile` is the 

1312 path to write the file to, "-" will write to stdout. 

1313 

1314 `pretty_print` is a boolean, whether to pretty-print the JSON output or not. 

1315 

1316 See :meth:`report` for other arguments. 

1317 

1318 Returns a float, the total percentage covered. 

1319 

1320 .. versionadded:: 5.0 

1321 

1322 """ 

1323 self._prepare_data_for_reporting() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1324 with override_config( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1325 self, 

1326 ignore_errors=ignore_errors, 

1327 report_omit=omit, 

1328 report_include=include, 

1329 json_output=outfile, 

1330 report_contexts=contexts, 

1331 json_pretty_print=pretty_print, 

1332 json_show_contexts=show_contexts, 

1333 ): 

1334 return render_report(self.config.json_output, JsonReporter(self), morfs, self._message) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1335 

1336 def lcov_report( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)

1337 self, 

1338 morfs: Iterable[TMorf] | None = None, 

1339 outfile: str | None = None, 

1340 ignore_errors: bool | None = None, 

1341 omit: str | list[str] | None = None, 

1342 include: str | list[str] | None = None, 

1343 contexts: list[str] | None = None, 

1344 ) -> float: 

1345 """Generate an LCOV report of coverage results. 

1346 

1347 Each module in `morfs` is included in the report. `outfile` is the 

1348 path to write the file to, "-" will write to stdout. 

1349 

1350 See :meth:`report` for other arguments. 

1351 

1352 .. versionadded:: 6.3 

1353 """ 

1354 self._prepare_data_for_reporting() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1355 with override_config( 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1356 self, 

1357 ignore_errors=ignore_errors, 

1358 report_omit=omit, 

1359 report_include=include, 

1360 lcov_output=outfile, 

1361 report_contexts=contexts, 

1362 ): 

1363 return render_report(self.config.lcov_output, LcovReporter(self), morfs, self._message) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1364 

1365 def sys_info(self) -> Iterable[tuple[str, Any]]: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1366 """Return a list of (key, value) pairs showing internal information.""" 

1367 

1368 import coverage as covmod 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1369 

1370 self._init() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1371 self._post_init() 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1372 

1373 def plugin_info(plugins: list[Any]) -> list[str]: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1374 """Make an entry for the sys_info from a list of plug-ins.""" 

1375 entries = [] 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1376 for plugin in plugins: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1377 entry = plugin._coverage_plugin_name 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGo!Hp0RIqJr61S234

1378 if not plugin._coverage_enabled: 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGo!Hp0RIqJr61S234

1379 entry += " (disabled)" 1abKcdLefMghNijOklPmnQopRqr6S234

1380 entries.append(entry) 1satbTKucvdULwexfVMygzhWNAiBjXOCkDlYPEmFnZQGo!Hp0RIqJr61S234

1381 return entries 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1382 

1383 info = [ 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1384 ("coverage_version", covmod.__version__), 

1385 ("coverage_module", covmod.__file__), 

1386 ("core", self._collector.tracer_name() if self._collector is not None else "-none-"), 

1387 ("CTracer", f"available from {CTRACER_FILE}" if CTRACER_FILE else "unavailable"), 

1388 ("plugins.file_tracers", plugin_info(self._plugins.file_tracers)), 

1389 ("plugins.configurers", plugin_info(self._plugins.configurers)), 

1390 ("plugins.context_switchers", plugin_info(self._plugins.context_switchers)), 

1391 ("configs_attempted", self.config.config_files_attempted), 

1392 ("configs_read", self.config.config_files_read), 

1393 ("config_file", self.config.config_file), 

1394 ( 

1395 "config_contents", 

1396 repr(self.config._config_contents) if self.config._config_contents else "-none-", 

1397 ), 

1398 ("data_file", self._data.data_filename() if self._data is not None else "-none-"), 

1399 ("python", sys.version.replace("\n", "")), 

1400 ("platform", platform.platform()), 

1401 ("implementation", platform.python_implementation()), 

1402 ("build", platform.python_build()), 

1403 ("gil_enabled", getattr(sys, "_is_gil_enabled", lambda: True)()), 

1404 ("executable", sys.executable), 

1405 ("def_encoding", sys.getdefaultencoding()), 

1406 ("fs_encoding", sys.getfilesystemencoding()), 

1407 ("pid", os.getpid()), 

1408 ("cwd", os.getcwd()), 

1409 ("path", sys.path), 

1410 ("environment", [f"{k} = {v}" for k, v in relevant_environment_display(os.environ)]), 

1411 ("command_line", " ".join(getattr(sys, "argv", ["-none-"]))), 

1412 ("time", f"{datetime.datetime.now():%Y-%m-%d %H:%M:%S}"), 

1413 ] 

1414 

1415 if self._inorout is not None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1416 info.extend(self._inorout.sys_info()) 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1417 

1418 return info 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1419 

1420 

1421# Mega debugging... 

1422# $set_env.py: COVERAGE_DEBUG_CALLS - Lots and lots of output about calls to Coverage. 

1423if int(os.getenv("COVERAGE_DEBUG_CALLS", 0)): # pragma: debugging 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1424 from coverage.debug import decorate_methods, show_calls 

1425 

1426 Coverage = decorate_methods( # type: ignore[misc] 

1427 show_calls(show_args=True), 

1428 butnot=["get_data"], 

1429 )(Coverage) 

1430 

1431 

1432def process_startup(*, force: bool = False) -> Coverage | None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1433 """Call this at Python start-up to perhaps measure coverage. 

1434 

1435 If the environment variable COVERAGE_PROCESS_START is defined, coverage 

1436 measurement is started. The value of the variable is the config file 

1437 to use. 

1438 

1439 For details, see https://coverage.readthedocs.io/en/latest/subprocess.html. 

1440 

1441 Returns the :class:`Coverage` instance that was started, or None if it was 

1442 not started by this call. 

1443 

1444 """ 

1445 config_data = os.getenv("COVERAGE_PROCESS_CONFIG") 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1446 cps = os.getenv("COVERAGE_PROCESS_START") 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1447 if config_data is not None: 1447 ↛ 1448line 1447 didn't jump to line 1448 because the condition on line 1447 was never true1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1448 config_file = CONFIG_DATA_PREFIX + config_data 

1449 elif cps is not None: 1449 ↛ 1453line 1449 didn't jump to line 1453 because the condition on line 1449 was always true1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1450 config_file = cps 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1451 else: 

1452 # No request for coverage, nothing to do. 

1453 return None 

1454 

1455 # This function can be called more than once in a process. This happens 

1456 # because some virtualenv configurations make the same directory visible 

1457 # twice in sys.path. This means that the .pth file will be found twice, 

1458 # and executed twice, executing this function twice. We set a global 

1459 # flag (an attribute on this function) to indicate that coverage.py has 

1460 # already been started, so we can avoid doing it twice. 

1461 # 

1462 # https://github.com/coveragepy/coveragepy/issues/340 has more details. 

1463 

1464 if not force and hasattr(process_startup, "coverage"): 1464 ↛ 1469line 1464 didn't jump to line 1469 because the condition on line 1464 was always true1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1465 # We've annotated this function before, so we must have already 

1466 # auto-started coverage.py in this process. Nothing to do. 

1467 return None 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1468 

1469 cov = Coverage(config_file=config_file) 

1470 process_startup.coverage = cov # type: ignore[attr-defined] 

1471 cov._warn_no_data = False 

1472 cov._warn_unimported_source = False 

1473 cov._warn_preimported_source = False 

1474 cov._auto_save = True 

1475 cov._make_pth_file = False 

1476 cov.start() 

1477 

1478 return cov 

1479 

1480 

1481def _after_fork_in_child() -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1482 """Used by patch=fork in the child process to restart coverage.""" 

1483 if cov := Coverage.current(): 

1484 cov.stop() 

1485 process_startup(force=True) 

1486 

1487 

1488def _prevent_sub_process_measurement() -> None: 1satbTKucvdULwexfVMygzhWNAiBjXOCk7Dl8YP%Em5Fn9ZQ'Go!Hp#0R(Iq$Jr61S)234

1489 """Stop any subprocess auto-measurement from writing data.""" 

1490 auto_created_coverage = getattr(process_startup, "coverage", None) 

1491 if auto_created_coverage is not None: 

1492 auto_created_coverage._auto_save = False