diff --git a/_pytest/mark.py b/_pytest/mark.py index 4e304650a..6b66b1876 100644 --- a/_pytest/mark.py +++ b/_pytest/mark.py @@ -206,6 +206,24 @@ class MarkDecorator: @mark2 def test_function(): pass + + When a MarkDecorator instance is called it does the following: + 1. If called with a single class as its only positional argument and no + additional keyword arguments, it attaches itself to the class so it + gets applied automatically to all test cases found in that class. + 2. If called with a single function as its only positional argument and + no additional keyword arguments, it attaches a MarkInfo object to the + function, containing all the arguments already stored internally in + the MarkDecorator. + 3. When called in any other case, it performs a 'fake construction' call, + i.e. it returns a new MarkDecorator instance with the original + MarkDecorator's content updated with the arguments passed to this + call. + + Note: The rules above prevent MarkDecorator objects from storing only a + single function or class reference as their positional argument with no + additional keyword or positional arguments. + """ def __init__(self, name, args=None, kwargs=None): self.name = name @@ -224,7 +242,7 @@ class MarkDecorator: def __call__(self, *args, **kwargs): """ if passed a single callable argument: decorate it with mark info. otherwise add *args/**kwargs in-place to mark information. """ - if args: + if args and not kwargs: func = args[0] if len(args) == 1 and (istestfunc(func) or hasattr(func, '__bases__')): diff --git a/testing/test_mark.py b/testing/test_mark.py index ba4c427fe..ce2e4b60d 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -57,6 +57,17 @@ class TestMark: assert f.world.args[0] == "hello" mark.world("world")(f) + def test_pytest_mark_positional_func_and_keyword(self): + mark = Mark() + def f(): + raise Exception + m = mark.world(f, omega="hello") + def g(): + pass + assert m(g) == g + assert g.world.args[0] is f + assert g.world.kwargs["omega"] == "hello" + def test_pytest_mark_reuse(self): mark = Mark() def f():