| 
16 | 16 | import sys  | 
17 | 17 | import threading  | 
18 | 18 | import time  | 
 | 19 | +import typing  | 
19 | 20 | import warnings  | 
20 | 21 | 
 
  | 
21 | 22 | from types import FrameType  | 
 | 
43 | 44 | from coverage.misc import DefaultValue, ensure_dir_for_file, isolate_module  | 
44 | 45 | from coverage.multiproc import patch_multiprocessing  | 
45 | 46 | from coverage.plugin import FileReporter  | 
46 |  | -from coverage.plugin_support import Plugins  | 
 | 47 | +from coverage.plugin_support import Plugins, TCoverageInit  | 
47 | 48 | from coverage.python import PythonFileReporter  | 
48 | 49 | from coverage.report import SummaryReporter  | 
49 | 50 | from coverage.report_core import render_report  | 
50 | 51 | from coverage.results import Analysis, analysis_from_file_reporter  | 
51 | 52 | from coverage.types import (  | 
52 | 53 |     FilePath, TConfigurable, TConfigSectionIn, TConfigValueIn, TConfigValueOut,  | 
53 |  | -    TFileDisposition, TLineNo, TMorf,  | 
 | 54 | +    TFileDisposition, TLineNo, TMorf  | 
54 | 55 | )  | 
55 | 56 | from coverage.xmlreport import XmlReporter  | 
56 | 57 | 
 
  | 
@@ -138,6 +139,7 @@ def __init__(                       # pylint: disable=too-many-arguments  | 
138 | 139 |         check_preimported: bool = False,  | 
139 | 140 |         context: str | None = None,  | 
140 | 141 |         messages: bool = False,  | 
 | 142 | +        plugins: Iterable[Callable] | None = None,  | 
141 | 143 |     ) -> None:  | 
142 | 144 |         """  | 
143 | 145 |         Many of these arguments duplicate and override values that can be  | 
@@ -211,6 +213,12 @@ def __init__(                       # pylint: disable=too-many-arguments  | 
211 | 213 |         If `messages` is true, some messages will be printed to stdout  | 
212 | 214 |         indicating what is happening.  | 
213 | 215 | 
  | 
 | 216 | +        If `plugins` are passed, they are an iterable of functions with the  | 
 | 217 | +        `coverage_init` signature (meaning they take a plugin registry and a  | 
 | 218 | +        dictionary of configuration options as arguments). When they are  | 
 | 219 | +        provided, they will override the plugins found in the coverage  | 
 | 220 | +        configuration file.  | 
 | 221 | +
  | 
214 | 222 |         .. versionadded:: 4.0  | 
215 | 223 |             The `concurrency` parameter.  | 
216 | 224 | 
  | 
@@ -260,6 +268,10 @@ def __init__(                       # pylint: disable=too-many-arguments  | 
260 | 268 |         self._debug: DebugControl = NoDebugging()  | 
261 | 269 |         self._inorout: InOrOut | None = None  | 
262 | 270 |         self._plugins: Plugins = Plugins()  | 
 | 271 | +        self._plugin_override = typing.cast(  | 
 | 272 | +            typing.Union[Iterable[TCoverageInit], None],  | 
 | 273 | +            plugins  | 
 | 274 | +        )  | 
263 | 275 |         self._data: CoverageData | None = None  | 
264 | 276 |         self._core: Core | None = None  | 
265 | 277 |         self._collector: Collector | None = None  | 
@@ -340,7 +352,12 @@ def _init(self) -> None:  | 
340 | 352 |             self._file_mapper = relative_filename  | 
341 | 353 | 
 
  | 
342 | 354 |         # Load plugins  | 
343 |  | -        self._plugins = Plugins.load_plugins(self.config.plugins, self.config, self._debug)  | 
 | 355 | +        self._plugins = Plugins.load_plugins(  | 
 | 356 | +            self.config.plugins,  | 
 | 357 | +            self.config,  | 
 | 358 | +            self._debug,  | 
 | 359 | +            plugin_override=self._plugin_override  | 
 | 360 | +        )  | 
344 | 361 | 
 
  | 
345 | 362 |         # Run configuring plugins.  | 
346 | 363 |         for plugin in self._plugins.configurers:  | 
 | 
0 commit comments