@@ -288,9 +288,6 @@ def __init__( # pylint: disable=too-many-arguments
288288 self ._no_warn_slugs : set [str ] = set ()
289289 self ._messages = messages
290290
291- # If we're invoked from a .pth file, we shouldn't try to make another one.
292- self ._make_pth_file = True
293-
294291 # A record of all the warnings that have been issued.
295292 self ._warnings : list [str ] = []
296293
@@ -719,7 +716,7 @@ def start(self) -> None:
719716 if self ._auto_load :
720717 self .load ()
721718
722- apply_patches (self , self .config , self ._debug , make_pth_file = self . _make_pth_file )
719+ apply_patches (self , self .config , self ._debug )
723720
724721 self ._collector .start ()
725722 self ._started = True
@@ -1429,19 +1426,51 @@ def plugin_info(plugins: list[Any]) -> list[str]:
14291426 )(Coverage )
14301427
14311428
1432- def process_startup (* , force : bool = False ) -> Coverage | None :
1429+ def process_startup (
1430+ * ,
1431+ force : bool = False ,
1432+ slug : str = "default" , # pylint: disable=unused-argument
1433+ ) -> Coverage | None :
14331434 """Call this at Python start-up to perhaps measure coverage.
14341435
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.
1436+ Coverage is started if one of these environment variables is defined:
1437+
1438+ - COVERAGE_PROCESS_START: the config file to use.
1439+ - COVERAGE_PROCESS_CONFIG: the config data to use, a string produced by
1440+ CoverageConfig.serialize, prefixed by ":data:".
1441+
1442+ If one of these is defined, it's used to get the coverage configuration,
1443+ and coverage is started.
14381444
14391445 For details, see https://coverage.readthedocs.io/en/latest/subprocess.html.
14401446
14411447 Returns the :class:`Coverage` instance that was started, or None if it was
14421448 not started by this call.
14431449
14441450 """
1451+ # This function can be called more than once in a process, for a few
1452+ # reasons.
1453+ #
1454+ # 1) We install a .pth file in multiple places reported by the site module,
1455+ # so this function can be called more than once even in simple
1456+ # situations.
1457+ #
1458+ # 2) In some virtualenv configurations the same directory is visible twice
1459+ # in sys.path. This means that the .pth file will be found twice and
1460+ # executed twice, executing this function twice.
1461+ # https://github.com/coveragepy/coveragepy/issues/340 has more details.
1462+ #
1463+ # We set a global flag (an attribute on this function) to indicate that
1464+ # coverage.py has already been started, so we can avoid starting it twice.
1465+
1466+ if not force and hasattr (process_startup , "coverage" ):
1467+ # We've annotated this function before, so we must have already
1468+ # auto-started coverage.py in this process. Nothing to do.
1469+ return None
1470+
1471+ # Now check for the environment variables that request coverage. If they
1472+ # aren't set, do nothing.
1473+
14451474 config_data = os .getenv ("COVERAGE_PROCESS_CONFIG" )
14461475 cps = os .getenv ("COVERAGE_PROCESS_START" )
14471476 if config_data is not None :
@@ -1452,27 +1481,12 @@ def process_startup(*, force: bool = False) -> Coverage | None:
14521481 # No request for coverage, nothing to do.
14531482 return None
14541483
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" ):
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
1468-
14691484 cov = Coverage (config_file = config_file )
14701485 process_startup .coverage = cov # type: ignore[attr-defined]
14711486 cov ._warn_no_data = False
14721487 cov ._warn_unimported_source = False
14731488 cov ._warn_preimported_source = False
14741489 cov ._auto_save = True
1475- cov ._make_pth_file = False
14761490 cov .start ()
14771491
14781492 return cov
@@ -1482,7 +1496,7 @@ def _after_fork_in_child() -> None:
14821496 """Used by patch=fork in the child process to restart coverage."""
14831497 if cov := Coverage .current ():
14841498 cov .stop ()
1485- process_startup (force = True )
1499+ process_startup (force = True , slug = "fork" )
14861500
14871501
14881502def _prevent_sub_process_measurement () -> None :
0 commit comments