__init__.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. """ generic mechanism for marking and selecting python functions. """
  2. from __future__ import absolute_import, division, print_function
  3. from _pytest.config import UsageError
  4. from .structures import (
  5. ParameterSet,
  6. EMPTY_PARAMETERSET_OPTION,
  7. MARK_GEN,
  8. Mark,
  9. MarkInfo,
  10. MarkDecorator,
  11. MarkGenerator,
  12. transfer_markers,
  13. get_empty_parameterset_mark,
  14. )
  15. from .legacy import matchkeyword, matchmark
  16. __all__ = [
  17. "Mark",
  18. "MarkInfo",
  19. "MarkDecorator",
  20. "MarkGenerator",
  21. "transfer_markers",
  22. "get_empty_parameterset_mark",
  23. ]
  24. class MarkerError(Exception):
  25. """Error in use of a pytest marker/attribute."""
  26. def param(*values, **kw):
  27. """Specify a parameter in `pytest.mark.parametrize`_ calls or
  28. :ref:`parametrized fixtures <fixture-parametrize-marks>`.
  29. .. code-block:: python
  30. @pytest.mark.parametrize("test_input,expected", [
  31. ("3+5", 8),
  32. pytest.param("6*9", 42, marks=pytest.mark.xfail),
  33. ])
  34. def test_eval(test_input, expected):
  35. assert eval(test_input) == expected
  36. :param values: variable args of the values of the parameter set, in order.
  37. :keyword marks: a single mark or a list of marks to be applied to this parameter set.
  38. :keyword str id: the id to attribute to this parameter set.
  39. """
  40. return ParameterSet.param(*values, **kw)
  41. def pytest_addoption(parser):
  42. group = parser.getgroup("general")
  43. group._addoption(
  44. "-k",
  45. action="store",
  46. dest="keyword",
  47. default="",
  48. metavar="EXPRESSION",
  49. help="only run tests which match the given substring expression. "
  50. "An expression is a python evaluatable expression "
  51. "where all names are substring-matched against test names "
  52. "and their parent classes. Example: -k 'test_method or test_"
  53. "other' matches all test functions and classes whose name "
  54. "contains 'test_method' or 'test_other', while -k 'not test_method' "
  55. "matches those that don't contain 'test_method' in their names. "
  56. "Additionally keywords are matched to classes and functions "
  57. "containing extra names in their 'extra_keyword_matches' set, "
  58. "as well as functions which have names assigned directly to them.",
  59. )
  60. group._addoption(
  61. "-m",
  62. action="store",
  63. dest="markexpr",
  64. default="",
  65. metavar="MARKEXPR",
  66. help="only run tests matching given mark expression. "
  67. "example: -m 'mark1 and not mark2'.",
  68. )
  69. group.addoption(
  70. "--markers",
  71. action="store_true",
  72. help="show markers (builtin, plugin and per-project ones).",
  73. )
  74. parser.addini("markers", "markers for test functions", "linelist")
  75. parser.addini(EMPTY_PARAMETERSET_OPTION, "default marker for empty parametersets")
  76. def pytest_cmdline_main(config):
  77. import _pytest.config
  78. if config.option.markers:
  79. config._do_configure()
  80. tw = _pytest.config.create_terminal_writer(config)
  81. for line in config.getini("markers"):
  82. parts = line.split(":", 1)
  83. name = parts[0]
  84. rest = parts[1] if len(parts) == 2 else ""
  85. tw.write("@pytest.mark.%s:" % name, bold=True)
  86. tw.line(rest)
  87. tw.line()
  88. config._ensure_unconfigure()
  89. return 0
  90. pytest_cmdline_main.tryfirst = True
  91. def deselect_by_keyword(items, config):
  92. keywordexpr = config.option.keyword.lstrip()
  93. if keywordexpr.startswith("-"):
  94. keywordexpr = "not " + keywordexpr[1:]
  95. selectuntil = False
  96. if keywordexpr[-1:] == ":":
  97. selectuntil = True
  98. keywordexpr = keywordexpr[:-1]
  99. remaining = []
  100. deselected = []
  101. for colitem in items:
  102. if keywordexpr and not matchkeyword(colitem, keywordexpr):
  103. deselected.append(colitem)
  104. else:
  105. if selectuntil:
  106. keywordexpr = None
  107. remaining.append(colitem)
  108. if deselected:
  109. config.hook.pytest_deselected(items=deselected)
  110. items[:] = remaining
  111. def deselect_by_mark(items, config):
  112. matchexpr = config.option.markexpr
  113. if not matchexpr:
  114. return
  115. remaining = []
  116. deselected = []
  117. for item in items:
  118. if matchmark(item, matchexpr):
  119. remaining.append(item)
  120. else:
  121. deselected.append(item)
  122. if deselected:
  123. config.hook.pytest_deselected(items=deselected)
  124. items[:] = remaining
  125. def pytest_collection_modifyitems(items, config):
  126. deselect_by_keyword(items, config)
  127. deselect_by_mark(items, config)
  128. def pytest_configure(config):
  129. config._old_mark_config = MARK_GEN._config
  130. if config.option.strict:
  131. MARK_GEN._config = config
  132. empty_parameterset = config.getini(EMPTY_PARAMETERSET_OPTION)
  133. if empty_parameterset not in ("skip", "xfail", None, ""):
  134. raise UsageError(
  135. "{!s} must be one of skip and xfail,"
  136. " but it is {!r}".format(EMPTY_PARAMETERSET_OPTION, empty_parameterset)
  137. )
  138. def pytest_unconfigure(config):
  139. MARK_GEN._config = getattr(config, "_old_mark_config", None)