Merge pull request #5015 from Zac-HD/mark-warning-prep

Pre-PR for warnings on unknown markers
This commit is contained in:
Zac Hatfield-Dodds 2019-04-01 10:07:43 +11:00 committed by GitHub
commit 407d74be27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 68 additions and 36 deletions

1
changelog/4935.doc.rst Normal file
View File

@ -0,0 +1 @@
Expand docs on registering marks and the effect of ``--strict``.

View File

@ -26,12 +26,10 @@ which also serve as documentation.
:ref:`fixtures <fixtures>`. :ref:`fixtures <fixtures>`.
Raising errors on unknown marks: --strict .. _unknown-marks:
-----------------------------------------
When the ``--strict`` command-line flag is passed, any unknown marks applied Raising errors on unknown marks
with the ``@pytest.mark.name_of_the_mark`` decorator will trigger an error. -------------------------------
Marks defined or added by pytest or by a plugin will not trigger an error.
Marks can be registered in ``pytest.ini`` like this: Marks can be registered in ``pytest.ini`` like this:
@ -42,8 +40,10 @@ Marks can be registered in ``pytest.ini`` like this:
slow slow
serial serial
This can be used to prevent users mistyping mark names by accident. Test suites that want to enforce this When the ``--strict`` command-line flag is passed, any unknown marks applied
should add ``--strict`` to ``addopts``: with the ``@pytest.mark.name_of_the_mark`` decorator will trigger an error.
Marks added by pytest or by a plugin instead of the decorator will not trigger
this error. To enforce validation of markers, add ``--strict`` to ``addopts``:
.. code-block:: ini .. code-block:: ini
@ -53,6 +53,9 @@ should add ``--strict`` to ``addopts``:
slow slow
serial serial
Third-party plugins should always :ref:`register their markers <registering-markers>`
so that they appear in pytest's help text and do not emit warnings.
.. _marker-revamp: .. _marker-revamp:

View File

@ -286,6 +286,26 @@ the plugin manager like this:
If you want to look at the names of existing plugins, use If you want to look at the names of existing plugins, use
the ``--trace-config`` option. the ``--trace-config`` option.
.. _registering-markers:
Registering custom markers
--------------------------
If your plugin uses any markers, you should register them so that they appear in
pytest's help text and do not :ref:`cause spurious warnings <unknown-marks>`.
For example, the following plugin would register ``cool_marker`` and
``mark_with`` for all users:
.. code-block:: python
def pytest_configure(config):
config.addinivalue_line("markers", "cool_marker: this one is for cool tests.")
config.addinivalue_line(
"markers", "mark_with(arg, arg2): this marker takes arguments."
)
Testing plugins Testing plugins
--------------- ---------------

View File

@ -129,7 +129,7 @@ class ParameterSet(namedtuple("ParameterSet", "values, marks, id")):
) )
else: else:
# empty parameter set (likely computed at runtime): create a single # empty parameter set (likely computed at runtime): create a single
# parameter set with NOSET values, with the "empty parameter set" mark applied to it # parameter set with NOTSET values, with the "empty parameter set" mark applied to it
mark = get_empty_parameterset_mark(config, argnames, func) mark = get_empty_parameterset_mark(config, argnames, func)
parameters.append( parameters.append(
ParameterSet(values=(NOTSET,) * len(argnames), marks=[mark], id=None) ParameterSet(values=(NOTSET,) * len(argnames), marks=[mark], id=None)
@ -152,7 +152,7 @@ class Mark(object):
:type other: Mark :type other: Mark
:rtype: Mark :rtype: Mark
combines by appending aargs and merging the mappings combines by appending args and merging the mappings
""" """
assert self.name == other.name assert self.name == other.name
return Mark( return Mark(

View File

@ -68,6 +68,12 @@ def pytest_configure(config):
if checker.matching_platform(): if checker.matching_platform():
config.pluginmanager.register(checker) config.pluginmanager.register(checker)
config.addinivalue_line(
"markers",
"pytester_example_path(*path_segments): join the given path "
"segments to `pytester_example_dir` for this test.",
)
def raise_on_kwargs(kwargs): def raise_on_kwargs(kwargs):
if kwargs: if kwargs:

View File

@ -1927,7 +1927,7 @@ class TestAutouseManagement(object):
reprec = testdir.inline_run() reprec = testdir.inline_run()
reprec.assertoutcome(passed=1) reprec.assertoutcome(passed=1)
@pytest.mark.issue226 @pytest.mark.issue(226)
@pytest.mark.parametrize("param1", ["", "params=[1]"], ids=["p00", "p01"]) @pytest.mark.parametrize("param1", ["", "params=[1]"], ids=["p00", "p01"])
@pytest.mark.parametrize("param2", ["", "params=[1]"], ids=["p10", "p11"]) @pytest.mark.parametrize("param2", ["", "params=[1]"], ids=["p10", "p11"])
def test_ordering_dependencies_torndown_first(self, testdir, param1, param2): def test_ordering_dependencies_torndown_first(self, testdir, param1, param2):
@ -2709,7 +2709,7 @@ class TestFixtureMarker(object):
reprec = testdir.inline_run("-v") reprec = testdir.inline_run("-v")
reprec.assertoutcome(passed=5) reprec.assertoutcome(passed=5)
@pytest.mark.issue246 @pytest.mark.issue(246)
@pytest.mark.parametrize("scope", ["session", "function", "module"]) @pytest.mark.parametrize("scope", ["session", "function", "module"])
def test_finalizer_order_on_parametrization(self, scope, testdir): def test_finalizer_order_on_parametrization(self, scope, testdir):
testdir.makepyfile( testdir.makepyfile(
@ -2746,7 +2746,7 @@ class TestFixtureMarker(object):
reprec = testdir.inline_run("-lvs") reprec = testdir.inline_run("-lvs")
reprec.assertoutcome(passed=3) reprec.assertoutcome(passed=3)
@pytest.mark.issue396 @pytest.mark.issue(396)
def test_class_scope_parametrization_ordering(self, testdir): def test_class_scope_parametrization_ordering(self, testdir):
testdir.makepyfile( testdir.makepyfile(
""" """
@ -2867,7 +2867,7 @@ class TestFixtureMarker(object):
res = testdir.runpytest("-v") res = testdir.runpytest("-v")
res.stdout.fnmatch_lines(["*test_foo*alpha*", "*test_foo*beta*"]) res.stdout.fnmatch_lines(["*test_foo*alpha*", "*test_foo*beta*"])
@pytest.mark.issue920 @pytest.mark.issue(920)
def test_deterministic_fixture_collection(self, testdir, monkeypatch): def test_deterministic_fixture_collection(self, testdir, monkeypatch):
testdir.makepyfile( testdir.makepyfile(
""" """

View File

@ -393,7 +393,7 @@ class TestNoselikeTestAttribute(object):
assert not call.items assert not call.items
@pytest.mark.issue351 @pytest.mark.issue(351)
class TestParameterize(object): class TestParameterize(object):
def test_idfn_marker(self, testdir): def test_idfn_marker(self, testdir):
testdir.makepyfile( testdir.makepyfile(

View File

@ -159,7 +159,7 @@ class TestMetafunc(object):
("x", "y"), [("abc", "def"), ("ghi", "jkl")], ids=["one"] ("x", "y"), [("abc", "def"), ("ghi", "jkl")], ids=["one"]
) )
@pytest.mark.issue510 @pytest.mark.issue(510)
def test_parametrize_empty_list(self): def test_parametrize_empty_list(self):
def func(y): def func(y):
pass pass
@ -262,7 +262,7 @@ class TestMetafunc(object):
for val, expected in values: for val, expected in values:
assert _idval(val, "a", 6, None, item=None, config=None) == expected assert _idval(val, "a", 6, None, item=None, config=None) == expected
@pytest.mark.issue250 @pytest.mark.issue(250)
def test_idmaker_autoname(self): def test_idmaker_autoname(self):
from _pytest.python import idmaker from _pytest.python import idmaker
@ -356,7 +356,7 @@ class TestMetafunc(object):
result = idmaker(("a", "b"), [pytest.param(e.one, e.two)]) result = idmaker(("a", "b"), [pytest.param(e.one, e.two)])
assert result == ["Foo.one-Foo.two"] assert result == ["Foo.one-Foo.two"]
@pytest.mark.issue351 @pytest.mark.issue(351)
def test_idmaker_idfn(self): def test_idmaker_idfn(self):
from _pytest.python import idmaker from _pytest.python import idmaker
@ -375,7 +375,7 @@ class TestMetafunc(object):
) )
assert result == ["10.0-IndexError()", "20-KeyError()", "three-b2"] assert result == ["10.0-IndexError()", "20-KeyError()", "three-b2"]
@pytest.mark.issue351 @pytest.mark.issue(351)
def test_idmaker_idfn_unique_names(self): def test_idmaker_idfn_unique_names(self):
from _pytest.python import idmaker from _pytest.python import idmaker
@ -459,7 +459,7 @@ class TestMetafunc(object):
) )
assert result == ["a0", "a1", "b0", "c", "b1"] assert result == ["a0", "a1", "b0", "c", "b1"]
@pytest.mark.issue714 @pytest.mark.issue(714)
def test_parametrize_indirect(self): def test_parametrize_indirect(self):
def func(x, y): def func(x, y):
pass pass
@ -473,7 +473,7 @@ class TestMetafunc(object):
assert metafunc._calls[0].params == dict(x=1, y=2) assert metafunc._calls[0].params == dict(x=1, y=2)
assert metafunc._calls[1].params == dict(x=1, y=3) assert metafunc._calls[1].params == dict(x=1, y=3)
@pytest.mark.issue714 @pytest.mark.issue(714)
def test_parametrize_indirect_list(self): def test_parametrize_indirect_list(self):
def func(x, y): def func(x, y):
pass pass
@ -483,7 +483,7 @@ class TestMetafunc(object):
assert metafunc._calls[0].funcargs == dict(y="b") assert metafunc._calls[0].funcargs == dict(y="b")
assert metafunc._calls[0].params == dict(x="a") assert metafunc._calls[0].params == dict(x="a")
@pytest.mark.issue714 @pytest.mark.issue(714)
def test_parametrize_indirect_list_all(self): def test_parametrize_indirect_list_all(self):
def func(x, y): def func(x, y):
pass pass
@ -493,7 +493,7 @@ class TestMetafunc(object):
assert metafunc._calls[0].funcargs == {} assert metafunc._calls[0].funcargs == {}
assert metafunc._calls[0].params == dict(x="a", y="b") assert metafunc._calls[0].params == dict(x="a", y="b")
@pytest.mark.issue714 @pytest.mark.issue(714)
def test_parametrize_indirect_list_empty(self): def test_parametrize_indirect_list_empty(self):
def func(x, y): def func(x, y):
pass pass
@ -503,7 +503,7 @@ class TestMetafunc(object):
assert metafunc._calls[0].funcargs == dict(x="a", y="b") assert metafunc._calls[0].funcargs == dict(x="a", y="b")
assert metafunc._calls[0].params == {} assert metafunc._calls[0].params == {}
@pytest.mark.issue714 @pytest.mark.issue(714)
def test_parametrize_indirect_list_functional(self, testdir): def test_parametrize_indirect_list_functional(self, testdir):
""" """
Test parametrization with 'indirect' parameter applied on Test parametrization with 'indirect' parameter applied on
@ -532,7 +532,7 @@ class TestMetafunc(object):
result = testdir.runpytest("-v") result = testdir.runpytest("-v")
result.stdout.fnmatch_lines(["*test_simple*a-b*", "*1 passed*"]) result.stdout.fnmatch_lines(["*test_simple*a-b*", "*1 passed*"])
@pytest.mark.issue714 @pytest.mark.issue(714)
def test_parametrize_indirect_list_error(self, testdir): def test_parametrize_indirect_list_error(self, testdir):
def func(x, y): def func(x, y):
pass pass
@ -541,7 +541,7 @@ class TestMetafunc(object):
with pytest.raises(pytest.fail.Exception): with pytest.raises(pytest.fail.Exception):
metafunc.parametrize("x, y", [("a", "b")], indirect=["x", "z"]) metafunc.parametrize("x, y", [("a", "b")], indirect=["x", "z"])
@pytest.mark.issue714 @pytest.mark.issue(714)
def test_parametrize_uses_no_fixture_error_indirect_false(self, testdir): def test_parametrize_uses_no_fixture_error_indirect_false(self, testdir):
"""The 'uses no fixture' error tells the user at collection time """The 'uses no fixture' error tells the user at collection time
that the parametrize data they've set up doesn't correspond to the that the parametrize data they've set up doesn't correspond to the
@ -560,7 +560,7 @@ class TestMetafunc(object):
result = testdir.runpytest("--collect-only") result = testdir.runpytest("--collect-only")
result.stdout.fnmatch_lines(["*uses no argument 'y'*"]) result.stdout.fnmatch_lines(["*uses no argument 'y'*"])
@pytest.mark.issue714 @pytest.mark.issue(714)
def test_parametrize_uses_no_fixture_error_indirect_true(self, testdir): def test_parametrize_uses_no_fixture_error_indirect_true(self, testdir):
testdir.makepyfile( testdir.makepyfile(
""" """
@ -580,7 +580,7 @@ class TestMetafunc(object):
result = testdir.runpytest("--collect-only") result = testdir.runpytest("--collect-only")
result.stdout.fnmatch_lines(["*uses no fixture 'y'*"]) result.stdout.fnmatch_lines(["*uses no fixture 'y'*"])
@pytest.mark.issue714 @pytest.mark.issue(714)
def test_parametrize_indirect_uses_no_fixture_error_indirect_string(self, testdir): def test_parametrize_indirect_uses_no_fixture_error_indirect_string(self, testdir):
testdir.makepyfile( testdir.makepyfile(
""" """
@ -597,7 +597,7 @@ class TestMetafunc(object):
result = testdir.runpytest("--collect-only") result = testdir.runpytest("--collect-only")
result.stdout.fnmatch_lines(["*uses no fixture 'y'*"]) result.stdout.fnmatch_lines(["*uses no fixture 'y'*"])
@pytest.mark.issue714 @pytest.mark.issue(714)
def test_parametrize_indirect_uses_no_fixture_error_indirect_list(self, testdir): def test_parametrize_indirect_uses_no_fixture_error_indirect_list(self, testdir):
testdir.makepyfile( testdir.makepyfile(
""" """
@ -614,7 +614,7 @@ class TestMetafunc(object):
result = testdir.runpytest("--collect-only") result = testdir.runpytest("--collect-only")
result.stdout.fnmatch_lines(["*uses no fixture 'y'*"]) result.stdout.fnmatch_lines(["*uses no fixture 'y'*"])
@pytest.mark.issue714 @pytest.mark.issue(714)
def test_parametrize_argument_not_in_indirect_list(self, testdir): def test_parametrize_argument_not_in_indirect_list(self, testdir):
testdir.makepyfile( testdir.makepyfile(
""" """
@ -1201,7 +1201,7 @@ class TestMetafuncFunctional(object):
reprec = testdir.runpytest() reprec = testdir.runpytest()
reprec.assert_outcomes(passed=4) reprec.assert_outcomes(passed=4)
@pytest.mark.issue463 @pytest.mark.issue(463)
@pytest.mark.parametrize("attr", ["parametrise", "parameterize", "parameterise"]) @pytest.mark.parametrize("attr", ["parametrise", "parameterize", "parameterise"])
def test_parametrize_misspelling(self, testdir, attr): def test_parametrize_misspelling(self, testdir, attr):
testdir.makepyfile( testdir.makepyfile(
@ -1386,7 +1386,7 @@ class TestMetafuncFunctionalAuto(object):
assert output.count("preparing foo-3") == 1 assert output.count("preparing foo-3") == 1
@pytest.mark.issue308 @pytest.mark.issue(308)
class TestMarkersWithParametrization(object): class TestMarkersWithParametrization(object):
def test_simple_mark(self, testdir): def test_simple_mark(self, testdir):
s = """ s = """
@ -1575,7 +1575,7 @@ class TestMarkersWithParametrization(object):
reprec = testdir.inline_run(SHOW_PYTEST_WARNINGS_ARG) reprec = testdir.inline_run(SHOW_PYTEST_WARNINGS_ARG)
reprec.assertoutcome(passed=2, skipped=2) reprec.assertoutcome(passed=2, skipped=2)
@pytest.mark.issue290 @pytest.mark.issue(290)
def test_parametrize_ID_generation_string_int_works(self, testdir): def test_parametrize_ID_generation_string_int_works(self, testdir):
testdir.makepyfile( testdir.makepyfile(
""" """

View File

@ -605,7 +605,7 @@ class TestCaptureFixture(object):
result.stdout.fnmatch_lines(["*KeyboardInterrupt*"]) result.stdout.fnmatch_lines(["*KeyboardInterrupt*"])
assert result.ret == 2 assert result.ret == 2
@pytest.mark.issue14 @pytest.mark.issue(14)
def test_capture_and_logging(self, testdir): def test_capture_and_logging(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
"""\ """\

View File

@ -490,7 +490,7 @@ class TestConftestVisibility(object):
("snc", ".", 1), ("snc", ".", 1),
], ],
) )
@pytest.mark.issue616 @pytest.mark.issue(616)
def test_parsefactories_relative_node_ids( def test_parsefactories_relative_node_ids(
self, testdir, chdir, testarg, expect_ntests_passed self, testdir, chdir, testarg, expect_ntests_passed
): ):

View File

@ -448,7 +448,7 @@ class TestFunctional(object):
items, rec = testdir.inline_genitems(p) items, rec = testdir.inline_genitems(p)
self.assert_markers(items, test_foo=("a", "b"), test_bar=("a",)) self.assert_markers(items, test_foo=("a", "b"), test_bar=("a",))
@pytest.mark.issue568 @pytest.mark.issue(568)
def test_mark_should_not_pass_to_siebling_class(self, testdir): def test_mark_should_not_pass_to_siebling_class(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
""" """
@ -651,7 +651,7 @@ class TestFunctional(object):
markers = {m.name for m in items[name].iter_markers()} markers = {m.name for m in items[name].iter_markers()}
assert markers == set(expected_markers) assert markers == set(expected_markers)
@pytest.mark.issue1540 @pytest.mark.issue(1540)
@pytest.mark.filterwarnings("ignore") @pytest.mark.filterwarnings("ignore")
def test_mark_from_parameters(self, testdir): def test_mark_from_parameters(self, testdir):
testdir.makepyfile( testdir.makepyfile(

View File

@ -166,6 +166,8 @@ filterwarnings =
# Do not cause SyntaxError for invalid escape sequences in py37. # Do not cause SyntaxError for invalid escape sequences in py37.
default:invalid escape sequence:DeprecationWarning default:invalid escape sequence:DeprecationWarning
pytester_example_dir = testing/example_scripts pytester_example_dir = testing/example_scripts
markers =
issue
[flake8] [flake8]
max-line-length = 120 max-line-length = 120