Type annotate `@pytest.mark.foo`

This commit is contained in:
Ran Benita 2020-05-01 14:40:16 +03:00
parent c0af19d8ad
commit 848ab00663
1 changed files with 23 additions and 1 deletions

View File

@ -3,6 +3,7 @@ import inspect
import typing import typing
import warnings import warnings
from typing import Any from typing import Any
from typing import Callable
from typing import Iterable from typing import Iterable
from typing import List from typing import List
from typing import Mapping from typing import Mapping
@ -11,6 +12,7 @@ from typing import Optional
from typing import Sequence from typing import Sequence
from typing import Set from typing import Set
from typing import Tuple from typing import Tuple
from typing import TypeVar
from typing import Union from typing import Union
import attr import attr
@ -19,6 +21,7 @@ from .._code import getfslineno
from ..compat import ascii_escaped from ..compat import ascii_escaped
from ..compat import NOTSET from ..compat import NOTSET
from ..compat import NotSetType from ..compat import NotSetType
from ..compat import overload
from ..compat import TYPE_CHECKING from ..compat import TYPE_CHECKING
from _pytest.config import Config from _pytest.config import Config
from _pytest.outcomes import fail from _pytest.outcomes import fail
@ -240,6 +243,12 @@ class Mark:
) )
# A generic parameter designating an object to which a Mark may
# be applied -- a test function (callable) or class.
# Note: a lambda is not allowed, but this can't be represented.
_Markable = TypeVar("_Markable", bound=Union[Callable[..., object], type])
@attr.s @attr.s
class MarkDecorator: class MarkDecorator:
"""A decorator for applying a mark on test functions and classes. """A decorator for applying a mark on test functions and classes.
@ -311,7 +320,20 @@ class MarkDecorator:
mark = Mark(self.name, args, kwargs) mark = Mark(self.name, args, kwargs)
return self.__class__(self.mark.combined_with(mark)) return self.__class__(self.mark.combined_with(mark))
def __call__(self, *args: object, **kwargs: object): # Type ignored because the overloads overlap with an incompatible
# return type. Not much we can do about that. Thankfully mypy picks
# the first match so it works out even if we break the rules.
@overload
def __call__(self, arg: _Markable) -> _Markable: # type: ignore[misc] # noqa: F821
raise NotImplementedError()
@overload # noqa: F811
def __call__( # noqa: F811
self, *args: object, **kwargs: object
) -> "MarkDecorator":
raise NotImplementedError()
def __call__(self, *args: object, **kwargs: object): # noqa: F811
"""Call the MarkDecorator.""" """Call the MarkDecorator."""
if args and not kwargs: if args and not kwargs:
func = args[0] func = args[0]