A :py:class:`pluggy.PluginManager ` with additional pytest-specific functionality: * Loading plugins from the command line, ``PYTEST_PLUGINS`` env variable and ``pytest_plugins`` global variables found in plugins being loaded. * ``conftest.py`` loading during
| 341 | |
| 342 | @final |
| 343 | class PytestPluginManager(PluginManager): |
| 344 | """A :py:class:`pluggy.PluginManager <pluggy.PluginManager>` with |
| 345 | additional pytest-specific functionality: |
| 346 | |
| 347 | * Loading plugins from the command line, ``PYTEST_PLUGINS`` env variable and |
| 348 | ``pytest_plugins`` global variables found in plugins being loaded. |
| 349 | * ``conftest.py`` loading during start-up. |
| 350 | """ |
| 351 | |
| 352 | def __init__(self) -> None: |
| 353 | import _pytest.assertion |
| 354 | |
| 355 | super().__init__("pytest") |
| 356 | # The objects are module objects, only used generically. |
| 357 | self._conftest_plugins: Set[types.ModuleType] = set() |
| 358 | |
| 359 | # State related to local conftest plugins. |
| 360 | self._dirpath2confmods: Dict[Path, List[types.ModuleType]] = {} |
| 361 | self._conftestpath2mod: Dict[Path, types.ModuleType] = {} |
| 362 | self._confcutdir: Optional[Path] = None |
| 363 | self._noconftest = False |
| 364 | |
| 365 | # _getconftestmodules()'s call to _get_directory() causes a stat |
| 366 | # storm when it's called potentially thousands of times in a test |
| 367 | # session (#9478), often with the same path, so cache it. |
| 368 | self._get_directory = lru_cache(256)(_get_directory) |
| 369 | |
| 370 | self._duplicatepaths: Set[Path] = set() |
| 371 | |
| 372 | # plugins that were explicitly skipped with pytest.skip |
| 373 | # list of (module name, skip reason) |
| 374 | # previously we would issue a warning when a plugin was skipped, but |
| 375 | # since we refactored warnings as first citizens of Config, they are |
| 376 | # just stored here to be used later. |
| 377 | self.skipped_plugins: List[Tuple[str, str]] = [] |
| 378 | |
| 379 | self.add_hookspecs(_pytest.hookspec) |
| 380 | self.register(self) |
| 381 | if os.environ.get("PYTEST_DEBUG"): |
| 382 | err: IO[str] = sys.stderr |
| 383 | encoding: str = getattr(err, "encoding", "utf8") |
| 384 | try: |
| 385 | err = open( |
| 386 | os.dup(err.fileno()), |
| 387 | mode=err.mode, |
| 388 | buffering=1, |
| 389 | encoding=encoding, |
| 390 | ) |
| 391 | except Exception: |
| 392 | pass |
| 393 | self.trace.root.setwriter(err.write) |
| 394 | self.enable_tracing() |
| 395 | |
| 396 | # Config._consider_importhook will set a real object if required. |
| 397 | self.rewrite_hook = _pytest.assertion.DummyRewriteHook() |
| 398 | # Used to know when we are importing conftests after the pytest_configure stage. |
| 399 | self._configured = False |
| 400 |
no outgoing calls