setuponly.py 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. from __future__ import annotations
  2. from collections.abc import Generator
  3. from _pytest._io.saferepr import saferepr
  4. from _pytest.config import Config
  5. from _pytest.config import ExitCode
  6. from _pytest.config.argparsing import Parser
  7. from _pytest.fixtures import FixtureDef
  8. from _pytest.fixtures import SubRequest
  9. from _pytest.scope import Scope
  10. import pytest
  11. def pytest_addoption(parser: Parser) -> None:
  12. group = parser.getgroup("debugconfig")
  13. group.addoption(
  14. "--setuponly",
  15. "--setup-only",
  16. action="store_true",
  17. help="Only setup fixtures, do not execute tests",
  18. )
  19. group.addoption(
  20. "--setupshow",
  21. "--setup-show",
  22. action="store_true",
  23. help="Show setup of fixtures while executing tests",
  24. )
  25. @pytest.hookimpl(wrapper=True)
  26. def pytest_fixture_setup(
  27. fixturedef: FixtureDef[object], request: SubRequest
  28. ) -> Generator[None, object, object]:
  29. try:
  30. return (yield)
  31. finally:
  32. if request.config.option.setupshow:
  33. if hasattr(request, "param"):
  34. # Save the fixture parameter so ._show_fixture_action() can
  35. # display it now and during the teardown (in .finish()).
  36. if fixturedef.ids:
  37. if callable(fixturedef.ids):
  38. param = fixturedef.ids(request.param)
  39. else:
  40. param = fixturedef.ids[request.param_index]
  41. else:
  42. param = request.param
  43. fixturedef.cached_param = param # type: ignore[attr-defined]
  44. _show_fixture_action(fixturedef, request.config, "SETUP")
  45. def pytest_fixture_post_finalizer(
  46. fixturedef: FixtureDef[object], request: SubRequest
  47. ) -> None:
  48. if fixturedef.cached_result is not None:
  49. config = request.config
  50. if config.option.setupshow:
  51. _show_fixture_action(fixturedef, request.config, "TEARDOWN")
  52. if hasattr(fixturedef, "cached_param"):
  53. del fixturedef.cached_param
  54. def _show_fixture_action(
  55. fixturedef: FixtureDef[object], config: Config, msg: str
  56. ) -> None:
  57. capman = config.pluginmanager.getplugin("capturemanager")
  58. if capman:
  59. capman.suspend_global_capture()
  60. tw = config.get_terminal_writer()
  61. tw.line()
  62. # Use smaller indentation the higher the scope: Session = 0, Package = 1, etc.
  63. scope_indent = list(reversed(Scope)).index(fixturedef._scope)
  64. tw.write(" " * 2 * scope_indent)
  65. scopename = fixturedef.scope[0].upper()
  66. tw.write(f"{msg:<8} {scopename} {fixturedef.argname}")
  67. if msg == "SETUP":
  68. deps = sorted(arg for arg in fixturedef.argnames if arg != "request")
  69. if deps:
  70. tw.write(" (fixtures used: {})".format(", ".join(deps)))
  71. if hasattr(fixturedef, "cached_param"):
  72. tw.write(f"[{saferepr(fixturedef.cached_param, maxsize=42)}]")
  73. tw.flush()
  74. if capman:
  75. capman.resume_global_capture()
  76. @pytest.hookimpl(tryfirst=True)
  77. def pytest_cmdline_main(config: Config) -> int | ExitCode | None:
  78. if config.option.setuponly:
  79. config.option.setupshow = True
  80. return None