A :py:class:`pluggy.PluginManager <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
| 458 | |
| 459 | @final |
| 460 | class PytestPluginManager(PluginManager): |
| 461 | """A :py:class:`pluggy.PluginManager <pluggy.PluginManager>` with |
| 462 | additional pytest-specific functionality: |
| 463 | |
| 464 | * Loading plugins from the command line, ``PYTEST_PLUGINS`` env variable and |
| 465 | ``pytest_plugins`` global variables found in plugins being loaded. |
| 466 | * ``conftest.py`` loading during start-up. |
| 467 | """ |
| 468 | |
| 469 | def __init__(self) -> None: |
| 470 | from _pytest.assertion import DummyRewriteHook |
| 471 | from _pytest.assertion import RewriteHook |
| 472 | |
| 473 | super().__init__("pytest") |
| 474 | |
| 475 | # -- State related to local conftest plugins. |
| 476 | # All loaded conftest modules. |
| 477 | self._conftest_plugins: set[types.ModuleType] = set() |
| 478 | # All conftest modules applicable for a directory. |
| 479 | # This includes the directory's own conftest modules as well |
| 480 | # as those of its parent directories. |
| 481 | self._dirpath2confmods: dict[pathlib.Path, list[types.ModuleType]] = {} |
| 482 | # Cutoff directory above which conftests are no longer discovered. |
| 483 | self._confcutdir: pathlib.Path | None = None |
| 484 | # If set, conftest loading is skipped. |
| 485 | self._noconftest = False |
| 486 | |
| 487 | # _getconftestmodules()'s call to _get_directory() causes a stat |
| 488 | # storm when it's called potentially thousands of times in a test |
| 489 | # session (#9478), often with the same path, so cache it. |
| 490 | self._get_directory = lru_cache(256)(_get_directory) |
| 491 | |
| 492 | # plugins that were explicitly skipped with pytest.skip |
| 493 | # list of (module name, skip reason) |
| 494 | # previously we would issue a warning when a plugin was skipped, but |
| 495 | # since we refactored warnings as first citizens of Config, they are |
| 496 | # just stored here to be used later. |
| 497 | self.skipped_plugins: list[tuple[str, str]] = [] |
| 498 | |
| 499 | self.add_hookspecs(_pytest.hookspec) |
| 500 | self.register(self) |
| 501 | if os.environ.get("PYTEST_DEBUG"): |
| 502 | err: IO[str] = sys.stderr |
| 503 | encoding: str = getattr(err, "encoding", "utf8") |
| 504 | try: |
| 505 | err = open( |
| 506 | os.dup(err.fileno()), |
| 507 | mode=err.mode, |
| 508 | buffering=1, |
| 509 | encoding=encoding, |
| 510 | ) |
| 511 | except Exception: |
| 512 | pass |
| 513 | self.trace.root.setwriter(err.write) |
| 514 | self.enable_tracing() |
| 515 | |
| 516 | # Config._consider_importhook will set a real object if required. |
| 517 | self.rewrite_hook: RewriteHook = DummyRewriteHook() |
no outgoing calls