setuponly.py 3.2 KB

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