Skip to content

Commit b3fb5a2

Browse files
committed
Type annotate pytest.mark.* builtin marks
1 parent a67c553 commit b3fb5a2

File tree

1 file changed

+90
-10
lines changed

1 file changed

+90
-10
lines changed

src/_pytest/mark/structures.py

Lines changed: 90 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,19 @@ def get_empty_parameterset_mark(
4646
) -> "MarkDecorator":
4747
from ..nodes import Collector
4848

49+
fs, lineno = getfslineno(func)
50+
reason = "got empty parameter set %r, function %s at %s:%d" % (
51+
argnames,
52+
func.__name__,
53+
fs,
54+
lineno,
55+
)
56+
4957
requested_mark = config.getini(EMPTY_PARAMETERSET_OPTION)
5058
if requested_mark in ("", None, "skip"):
51-
mark = MARK_GEN.skip
59+
mark = MARK_GEN.skip(reason=reason)
5260
elif requested_mark == "xfail":
53-
mark = MARK_GEN.xfail(run=False)
61+
mark = MARK_GEN.xfail(reason=reason, run=False)
5462
elif requested_mark == "fail_at_collect":
5563
f_name = func.__name__
5664
_, lineno = getfslineno(func)
@@ -59,14 +67,7 @@ def get_empty_parameterset_mark(
5967
)
6068
else:
6169
raise LookupError(requested_mark)
62-
fs, lineno = getfslineno(func)
63-
reason = "got empty parameter set %r, function %s at %s:%d" % (
64-
argnames,
65-
func.__name__,
66-
fs,
67-
lineno,
68-
)
69-
return mark(reason=reason)
70+
return mark
7071

7172

7273
class ParameterSet(
@@ -379,6 +380,76 @@ def store_mark(obj, mark: Mark) -> None:
379380
obj.pytestmark = get_unpacked_marks(obj) + [mark]
380381

381382

383+
# Typing for builtin pytest marks. This is cheating; it gives builtin marks
384+
# special privilege, and breaks modularity. But practicality beats purity...
385+
if TYPE_CHECKING:
386+
from _pytest.fixtures import _Scope
387+
388+
class _SkipMarkDecorator(MarkDecorator):
389+
@overload # type: ignore[override,misc]
390+
def __call__(self, arg: _Markable) -> _Markable:
391+
raise NotImplementedError()
392+
393+
@overload # noqa: F811
394+
def __call__(self, reason: str = ...) -> "MarkDecorator": # noqa: F811
395+
raise NotImplementedError()
396+
397+
class _SkipifMarkDecorator(MarkDecorator):
398+
def __call__( # type: ignore[override]
399+
self,
400+
condition: Union[str, bool] = ...,
401+
*conditions: Union[str, bool],
402+
reason: str = ...
403+
) -> MarkDecorator:
404+
raise NotImplementedError()
405+
406+
class _XfailMarkDecorator(MarkDecorator):
407+
@overload # type: ignore[override,misc]
408+
def __call__(self, arg: _Markable) -> _Markable:
409+
raise NotImplementedError()
410+
411+
@overload # noqa: F811
412+
def __call__( # noqa: F811
413+
self,
414+
condition: Union[str, bool] = ...,
415+
*conditions: Union[str, bool],
416+
reason: str = ...,
417+
run: bool = ...,
418+
raises: Union[BaseException, Tuple[BaseException, ...]] = ...,
419+
strict: bool = ...
420+
) -> MarkDecorator:
421+
raise NotImplementedError()
422+
423+
class _ParametrizeMarkDecorator(MarkDecorator):
424+
def __call__( # type: ignore[override]
425+
self,
426+
argnames: Union[str, List[str], Tuple[str, ...]],
427+
argvalues: Iterable[Union[ParameterSet, Sequence[object], object]],
428+
*,
429+
indirect: Union[bool, Sequence[str]] = ...,
430+
ids: Optional[
431+
Union[
432+
Iterable[Union[None, str, float, int, bool]],
433+
Callable[[object], Optional[object]],
434+
]
435+
] = ...,
436+
scope: Optional[_Scope] = ...
437+
) -> MarkDecorator:
438+
raise NotImplementedError()
439+
440+
class _UsefixturesMarkDecorator(MarkDecorator):
441+
def __call__( # type: ignore[override]
442+
self, *fixtures: str
443+
) -> MarkDecorator:
444+
raise NotImplementedError()
445+
446+
class _FilterwarningsMarkDecorator(MarkDecorator):
447+
def __call__( # type: ignore[override]
448+
self, *filters: str
449+
) -> MarkDecorator:
450+
raise NotImplementedError()
451+
452+
382453
class MarkGenerator:
383454
"""Factory for :class:`MarkDecorator` objects - exposed as
384455
a ``pytest.mark`` singleton instance.
@@ -397,6 +468,15 @@ def test_function():
397468
_config = None # type: Optional[Config]
398469
_markers = set() # type: Set[str]
399470

471+
# See TYPE_CHECKING above.
472+
if TYPE_CHECKING:
473+
skip = None # type: _SkipMarkDecorator
474+
skipif = None # type: _SkipifMarkDecorator
475+
xfail = None # type: _XfailMarkDecorator
476+
parametrize = None # type: _ParametrizeMarkDecorator
477+
usefixtures = None # type: _UsefixturesMarkDecorator
478+
filterwarnings = None # type: _FilterwarningsMarkDecorator
479+
400480
def __getattr__(self, name: str) -> MarkDecorator:
401481
if name[0] == "_":
402482
raise AttributeError("Marker name must NOT start with underscore")

0 commit comments

Comments
 (0)