2424from coverage import env
2525from coverage .annotate import AnnotateReporter
2626from coverage .collector import Collector
27- from coverage .config import CoverageConfig , read_coverage_config
27+ from coverage .config import CoverageConfig , deserialize_config , read_coverage_config
2828from coverage .context import combine_context_switchers , should_start_context_test_function
2929from coverage .core import CTRACER_FILE , Core
3030from coverage .data import CoverageData , combine_parallel_data
@@ -89,6 +89,7 @@ def override_config(cov: Coverage, **kwargs: TConfigValueIn) -> Iterator[None]:
8989
9090DEFAULT_DATAFILE = DefaultValue ("MISSING" )
9191_DEFAULT_DATAFILE = DEFAULT_DATAFILE # Just in case, for backwards compatibility
92+ CONFIG_FROM_ENVIRONMENT = ":envvar:"
9293
9394class Coverage (TConfigurable ):
9495 """Programmatic access to coverage.py.
@@ -316,27 +317,30 @@ def __init__( # pylint: disable=too-many-arguments
316317 self ._should_write_debug = True
317318
318319 # Build our configuration from a number of sources.
319- if not isinstance (config_file , bool ):
320- config_file = os .fspath (config_file )
321- self .config = read_coverage_config (
322- config_file = config_file ,
323- warn = self ._warn ,
324- data_file = data_file ,
325- cover_pylib = cover_pylib ,
326- timid = timid ,
327- branch = branch ,
328- parallel = bool_or_none (data_suffix ),
329- source = source ,
330- source_pkgs = source_pkgs ,
331- source_dirs = source_dirs ,
332- run_omit = omit ,
333- run_include = include ,
334- debug = debug ,
335- report_omit = omit ,
336- report_include = include ,
337- concurrency = concurrency ,
338- context = context ,
339- )
320+ if config_file == CONFIG_FROM_ENVIRONMENT :
321+ self .config = deserialize_config (cast (str , os .getenv ("COVERAGE_PROCESS_CONFIG" )))
322+ else :
323+ if not isinstance (config_file , bool ):
324+ config_file = os .fspath (config_file )
325+ self .config = read_coverage_config (
326+ config_file = config_file ,
327+ warn = self ._warn ,
328+ data_file = data_file ,
329+ cover_pylib = cover_pylib ,
330+ timid = timid ,
331+ branch = branch ,
332+ parallel = bool_or_none (data_suffix ),
333+ source = source ,
334+ source_pkgs = source_pkgs ,
335+ source_dirs = source_dirs ,
336+ run_omit = omit ,
337+ run_include = include ,
338+ debug = debug ,
339+ report_omit = omit ,
340+ report_include = include ,
341+ concurrency = concurrency ,
342+ context = context ,
343+ )
340344
341345 # If we have subprocess measurement happening automatically, then we
342346 # want any explicit creation of a Coverage object to mean, this process
@@ -1413,24 +1417,19 @@ def process_startup() -> Coverage | None:
14131417 measurement is started. The value of the variable is the config file
14141418 to use.
14151419
1416- There are two ways to configure your Python installation to invoke this
1417- function when Python starts:
1418-
1419- #. Create or append to sitecustomize.py to add these lines::
1420-
1421- import coverage
1422- coverage.process_startup()
1423-
1424- #. Create a .pth file in your Python installation containing::
1425-
1426- import coverage; coverage.process_startup()
1420+ For details, see https://coverage.readthedocs.io/en/latest/subprocess.html.
14271421
14281422 Returns the :class:`Coverage` instance that was started, or None if it was
14291423 not started by this call.
14301424
14311425 """
14321426 cps = os .getenv ("COVERAGE_PROCESS_START" )
1433- if not cps :
1427+ config_data = os .getenv ("COVERAGE_PROCESS_CONFIG" )
1428+ if cps is not None :
1429+ config_file = cps
1430+ elif config_data is not None :
1431+ config_file = CONFIG_FROM_ENVIRONMENT
1432+ else :
14341433 # No request for coverage, nothing to do.
14351434 return None
14361435
@@ -1445,13 +1444,10 @@ def process_startup() -> Coverage | None:
14451444
14461445 if hasattr (process_startup , "coverage" ):
14471446 # We've annotated this function before, so we must have already
1448- # started coverage.py in this process. Nothing to do.
1447+ # auto- started coverage.py in this process. Nothing to do.
14491448 return None
14501449
1451- cov = Coverage (
1452- config_file = cps ,
1453- data_file = os .getenv ("COVERAGE_PROCESS_DATAFILE" ) or DEFAULT_DATAFILE ,
1454- )
1450+ cov = Coverage (config_file = config_file )
14551451 process_startup .coverage = cov # type: ignore[attr-defined]
14561452 cov ._warn_no_data = False
14571453 cov ._warn_unimported_source = False
0 commit comments