Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pre-PR for warnings on unknown markers #5015

Merged
merged 5 commits into from
Mar 31, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/4935.doc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Expand docs on registering marks and the effect of ``--strict``.
17 changes: 10 additions & 7 deletions doc/en/mark.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,10 @@ which also serve as documentation.
:ref:`fixtures <fixtures>`.


Raising errors on unknown marks: --strict
-----------------------------------------
.. _unknown-marks:

When the ``--strict`` command-line flag is passed, any unknown marks applied
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.
Raising errors on unknown marks
-------------------------------

Marks can be registered in ``pytest.ini`` like this:

Expand All @@ -42,8 +40,10 @@ Marks can be registered in ``pytest.ini`` like this:
slow
serial

This can be used to prevent users mistyping mark names by accident. Test suites that want to enforce this
should add ``--strict`` to ``addopts``:
When the ``--strict`` command-line flag is passed, any unknown marks applied
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Zac-HD how about using this PR and add --strict-marks as an alias to --strict, while also updating the docs to use the former?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to leave functional changes to the other PR - will discuss there.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, thanks!

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

Expand All @@ -53,6 +53,9 @@ should add ``--strict`` to ``addopts``:
slow
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:

Expand Down
20 changes: 20 additions & 0 deletions doc/en/writing_plugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,26 @@ the plugin manager like this:
If you want to look at the names of existing plugins, use
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
---------------

Expand Down
4 changes: 2 additions & 2 deletions src/_pytest/mark/structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def _for_parametrize(cls, argnames, argvalues, func, config, function_definition
)
else:
# 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)
parameters.append(
ParameterSet(values=(NOTSET,) * len(argnames), marks=[mark], id=None)
Expand All @@ -152,7 +152,7 @@ def combined_with(self, other):
:type other: Mark
:rtype: Mark

combines by appending aargs and merging the mappings
combines by appending args and merging the mappings
"""
assert self.name == other.name
return Mark(
Expand Down
6 changes: 6 additions & 0 deletions src/_pytest/pytester.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ def pytest_configure(config):
if checker.matching_platform():
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):
if kwargs:
Expand Down
8 changes: 4 additions & 4 deletions testing/python/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -1927,7 +1927,7 @@ def test_hello(arg1):
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)

@pytest.mark.issue226
@pytest.mark.issue(226)
@pytest.mark.parametrize("param1", ["", "params=[1]"], ids=["p00", "p01"])
@pytest.mark.parametrize("param2", ["", "params=[1]"], ids=["p10", "p11"])
def test_ordering_dependencies_torndown_first(self, testdir, param1, param2):
Expand Down Expand Up @@ -2709,7 +2709,7 @@ def test_3():
reprec = testdir.inline_run("-v")
reprec.assertoutcome(passed=5)

@pytest.mark.issue246
@pytest.mark.issue(246)
@pytest.mark.parametrize("scope", ["session", "function", "module"])
def test_finalizer_order_on_parametrization(self, scope, testdir):
testdir.makepyfile(
Expand Down Expand Up @@ -2746,7 +2746,7 @@ def test_other():
reprec = testdir.inline_run("-lvs")
reprec.assertoutcome(passed=3)

@pytest.mark.issue396
@pytest.mark.issue(396)
def test_class_scope_parametrization_ordering(self, testdir):
testdir.makepyfile(
"""
Expand Down Expand Up @@ -2867,7 +2867,7 @@ def test_foo(fix):
res = testdir.runpytest("-v")
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):
testdir.makepyfile(
"""
Expand Down
2 changes: 1 addition & 1 deletion testing/python/integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ def test_blah(self):
assert not call.items


@pytest.mark.issue351
@pytest.mark.issue(351)
class TestParameterize(object):
def test_idfn_marker(self, testdir):
testdir.makepyfile(
Expand Down
36 changes: 18 additions & 18 deletions testing/python/metafunc.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def func(x, y):
("x", "y"), [("abc", "def"), ("ghi", "jkl")], ids=["one"]
)

@pytest.mark.issue510
@pytest.mark.issue(510)
def test_parametrize_empty_list(self):
def func(y):
pass
Expand Down Expand Up @@ -262,7 +262,7 @@ def test_function():
for val, expected in values:
assert _idval(val, "a", 6, None, item=None, config=None) == expected

@pytest.mark.issue250
@pytest.mark.issue(250)
def test_idmaker_autoname(self):
from _pytest.python import idmaker

Expand Down Expand Up @@ -356,7 +356,7 @@ def test_idmaker_enum(self):
result = idmaker(("a", "b"), [pytest.param(e.one, e.two)])
assert result == ["Foo.one-Foo.two"]

@pytest.mark.issue351
@pytest.mark.issue(351)
def test_idmaker_idfn(self):
from _pytest.python import idmaker

Expand All @@ -375,7 +375,7 @@ def ids(val):
)
assert result == ["10.0-IndexError()", "20-KeyError()", "three-b2"]

@pytest.mark.issue351
@pytest.mark.issue(351)
def test_idmaker_idfn_unique_names(self):
from _pytest.python import idmaker

Expand Down Expand Up @@ -459,7 +459,7 @@ def test_idmaker_with_ids_unique_names(self):
)
assert result == ["a0", "a1", "b0", "c", "b1"]

@pytest.mark.issue714
@pytest.mark.issue(714)
def test_parametrize_indirect(self):
def func(x, y):
pass
Expand All @@ -473,7 +473,7 @@ def func(x, y):
assert metafunc._calls[0].params == dict(x=1, y=2)
assert metafunc._calls[1].params == dict(x=1, y=3)

@pytest.mark.issue714
@pytest.mark.issue(714)
def test_parametrize_indirect_list(self):
def func(x, y):
pass
Expand All @@ -483,7 +483,7 @@ def func(x, y):
assert metafunc._calls[0].funcargs == dict(y="b")
assert metafunc._calls[0].params == dict(x="a")

@pytest.mark.issue714
@pytest.mark.issue(714)
def test_parametrize_indirect_list_all(self):
def func(x, y):
pass
Expand All @@ -493,7 +493,7 @@ def func(x, y):
assert metafunc._calls[0].funcargs == {}
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 func(x, y):
pass
Expand All @@ -503,7 +503,7 @@ def func(x, y):
assert metafunc._calls[0].funcargs == dict(x="a", y="b")
assert metafunc._calls[0].params == {}

@pytest.mark.issue714
@pytest.mark.issue(714)
def test_parametrize_indirect_list_functional(self, testdir):
"""
Test parametrization with 'indirect' parameter applied on
Expand Down Expand Up @@ -532,7 +532,7 @@ def test_simple(x,y):
result = testdir.runpytest("-v")
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 func(x, y):
pass
Expand All @@ -541,7 +541,7 @@ def func(x, y):
with pytest.raises(pytest.fail.Exception):
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):
"""The 'uses no fixture' error tells the user at collection time
that the parametrize data they've set up doesn't correspond to the
Expand All @@ -560,7 +560,7 @@ def test_simple(x):
result = testdir.runpytest("--collect-only")
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):
testdir.makepyfile(
"""
Expand All @@ -580,7 +580,7 @@ def test_simple(x):
result = testdir.runpytest("--collect-only")
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):
testdir.makepyfile(
"""
Expand All @@ -597,7 +597,7 @@ def test_simple(x):
result = testdir.runpytest("--collect-only")
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):
testdir.makepyfile(
"""
Expand All @@ -614,7 +614,7 @@ def test_simple(x):
result = testdir.runpytest("--collect-only")
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):
testdir.makepyfile(
"""
Expand Down Expand Up @@ -1201,7 +1201,7 @@ def test_foo(x):
reprec = testdir.runpytest()
reprec.assert_outcomes(passed=4)

@pytest.mark.issue463
@pytest.mark.issue(463)
@pytest.mark.parametrize("attr", ["parametrise", "parameterize", "parameterise"])
def test_parametrize_misspelling(self, testdir, attr):
testdir.makepyfile(
Expand Down Expand Up @@ -1386,7 +1386,7 @@ def pytest_generate_tests(metafunc):
assert output.count("preparing foo-3") == 1


@pytest.mark.issue308
@pytest.mark.issue(308)
class TestMarkersWithParametrization(object):
def test_simple_mark(self, testdir):
s = """
Expand Down Expand Up @@ -1575,7 +1575,7 @@ def test_increment(n, expected):
reprec = testdir.inline_run(SHOW_PYTEST_WARNINGS_ARG)
reprec.assertoutcome(passed=2, skipped=2)

@pytest.mark.issue290
@pytest.mark.issue(290)
def test_parametrize_ID_generation_string_int_works(self, testdir):
testdir.makepyfile(
"""
Expand Down
2 changes: 1 addition & 1 deletion testing/test_capture.py
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ def test_hello(capfd):
result.stdout.fnmatch_lines(["*KeyboardInterrupt*"])
assert result.ret == 2

@pytest.mark.issue14
@pytest.mark.issue(14)
def test_capture_and_logging(self, testdir):
p = testdir.makepyfile(
"""\
Expand Down
2 changes: 1 addition & 1 deletion testing/test_conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ def test_no_conftest(fxtr):
("snc", ".", 1),
],
)
@pytest.mark.issue616
@pytest.mark.issue(616)
def test_parsefactories_relative_node_ids(
self, testdir, chdir, testarg, expect_ntests_passed
):
Expand Down
4 changes: 2 additions & 2 deletions testing/test_mark.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ def test_bar(self): pass
items, rec = testdir.inline_genitems(p)
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):
p = testdir.makepyfile(
"""
Expand Down Expand Up @@ -651,7 +651,7 @@ def assert_markers(self, items, **expected):
markers = {m.name for m in items[name].iter_markers()}
assert markers == set(expected_markers)

@pytest.mark.issue1540
@pytest.mark.issue(1540)
@pytest.mark.filterwarnings("ignore")
def test_mark_from_parameters(self, testdir):
testdir.makepyfile(
Expand Down
2 changes: 2 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ filterwarnings =
# Do not cause SyntaxError for invalid escape sequences in py37.
default:invalid escape sequence:DeprecationWarning
pytester_example_dir = testing/example_scripts
markers =
issue
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/issue/gh_issue/ maybe?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're already using issue, so I'd rather leave any changes to a future PR and just standardise here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, a) I do not know how this is used actually, but b) you're touching all those lines already (and therefore it would be good to do it right away).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're already using issue, so I'd rather leave any changes to a future PR and just standardise here.

I never used it myself. I think we can actually remove them in the future, unless someone steps up and mentions he/she uses it on their workflow.


[flake8]
max-line-length = 120
Expand Down