Slightly improve Mark and MarkDecorator documentation
Mostly I wanted to get rid of mentions of "MarkItem" which is something that no longer exists, but I improved a little beyond that and annotated some simple types.
This commit is contained in:
		
							parent
							
								
									6356583eab
								
							
						
					
					
						commit
						4344c61731
					
				| 
						 | 
					@ -2,10 +2,14 @@ import inspect
 | 
				
			||||||
import warnings
 | 
					import warnings
 | 
				
			||||||
from collections import namedtuple
 | 
					from collections import namedtuple
 | 
				
			||||||
from collections.abc import MutableMapping
 | 
					from collections.abc import MutableMapping
 | 
				
			||||||
 | 
					from typing import Any
 | 
				
			||||||
from typing import Iterable
 | 
					from typing import Iterable
 | 
				
			||||||
from typing import List
 | 
					from typing import List
 | 
				
			||||||
 | 
					from typing import Mapping
 | 
				
			||||||
from typing import Optional
 | 
					from typing import Optional
 | 
				
			||||||
 | 
					from typing import Sequence
 | 
				
			||||||
from typing import Set
 | 
					from typing import Set
 | 
				
			||||||
 | 
					from typing import Tuple
 | 
				
			||||||
from typing import Union
 | 
					from typing import Union
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import attr
 | 
					import attr
 | 
				
			||||||
| 
						 | 
					@ -140,28 +144,32 @@ class ParameterSet(namedtuple("ParameterSet", "values, marks, id")):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@attr.s(frozen=True)
 | 
					@attr.s(frozen=True)
 | 
				
			||||||
class Mark:
 | 
					class Mark:
 | 
				
			||||||
    #: name of the mark
 | 
					    #: Name of the mark.
 | 
				
			||||||
    name = attr.ib(type=str)
 | 
					    name = attr.ib(type=str)
 | 
				
			||||||
    #: positional arguments of the mark decorator
 | 
					    #: Positional arguments of the mark decorator.
 | 
				
			||||||
    args = attr.ib()  # List[object]
 | 
					    args = attr.ib(type=Tuple[Any, ...])
 | 
				
			||||||
    #: keyword arguments of the mark decorator
 | 
					    #: Keyword arguments of the mark decorator.
 | 
				
			||||||
    kwargs = attr.ib()  # Dict[str, object]
 | 
					    kwargs = attr.ib(type=Mapping[str, Any])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #: source Mark for ids with parametrize Marks
 | 
					    #: Source Mark for ids with parametrize Marks.
 | 
				
			||||||
    _param_ids_from = attr.ib(type=Optional["Mark"], default=None, repr=False)
 | 
					    _param_ids_from = attr.ib(type=Optional["Mark"], default=None, repr=False)
 | 
				
			||||||
    #: resolved/generated ids with parametrize Marks
 | 
					    #: Resolved/generated ids with parametrize Marks.
 | 
				
			||||||
    _param_ids_generated = attr.ib(type=Optional[List[str]], default=None, repr=False)
 | 
					    _param_ids_generated = attr.ib(
 | 
				
			||||||
 | 
					        type=Optional[Sequence[str]], default=None, repr=False
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _has_param_ids(self):
 | 
					    def _has_param_ids(self) -> bool:
 | 
				
			||||||
        return "ids" in self.kwargs or len(self.args) >= 4
 | 
					        return "ids" in self.kwargs or len(self.args) >= 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def combined_with(self, other: "Mark") -> "Mark":
 | 
					    def combined_with(self, other: "Mark") -> "Mark":
 | 
				
			||||||
        """
 | 
					        """Return a new Mark which is a combination of this
 | 
				
			||||||
        :param other: the mark to combine with
 | 
					        Mark and another Mark.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Combines by appending args and merging kwargs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param other: The mark to combine with.
 | 
				
			||||||
        :type other: Mark
 | 
					        :type other: Mark
 | 
				
			||||||
        :rtype: Mark
 | 
					        :rtype: Mark
 | 
				
			||||||
 | 
					 | 
				
			||||||
        combines by appending args and merging the mappings
 | 
					 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        assert self.name == other.name
 | 
					        assert self.name == other.name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -183,11 +191,12 @@ class Mark:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@attr.s
 | 
					@attr.s
 | 
				
			||||||
class MarkDecorator:
 | 
					class MarkDecorator:
 | 
				
			||||||
    """ A decorator for test functions and test classes.  When applied
 | 
					    """A decorator for applying a mark on test functions and classes.
 | 
				
			||||||
    it will create :class:`Mark` objects which are often created like this::
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        mark1 = pytest.mark.NAME              # simple MarkDecorator
 | 
					    MarkDecorators are created with ``pytest.mark``::
 | 
				
			||||||
        mark2 = pytest.mark.NAME(name1=value) # parametrized MarkDecorator
 | 
					
 | 
				
			||||||
 | 
					        mark1 = pytest.mark.NAME              # Simple MarkDecorator
 | 
				
			||||||
 | 
					        mark2 = pytest.mark.NAME(name1=value) # Parametrized MarkDecorator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    and can then be applied as decorators to test functions::
 | 
					    and can then be applied as decorators to test functions::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -195,64 +204,64 @@ class MarkDecorator:
 | 
				
			||||||
        def test_function():
 | 
					        def test_function():
 | 
				
			||||||
            pass
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    When a MarkDecorator instance is called it does the following:
 | 
					    When a MarkDecorator is called it does the following:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    1. If called with a single class as its only positional argument and no
 | 
					    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
 | 
					       additional keyword arguments, it attaches the mark to the class so it
 | 
				
			||||||
       gets applied automatically to all test cases found in that class.
 | 
					       gets applied automatically to all test cases found in that class.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    2. If called with a single function as its only positional argument and
 | 
					    2. If called with a single function as its only positional argument and
 | 
				
			||||||
       no additional keyword arguments, it attaches a MarkInfo object to the
 | 
					       no additional keyword arguments, it attaches the mark to the function,
 | 
				
			||||||
       function, containing all the arguments already stored internally in
 | 
					       containing all the arguments already stored internally in the
 | 
				
			||||||
       the MarkDecorator.
 | 
					       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
 | 
					    3. When called in any other case, it returns a new MarkDecorator instance
 | 
				
			||||||
    single function or class reference as their positional argument with no
 | 
					       with the original MarkDecorator's content updated with the arguments
 | 
				
			||||||
    additional keyword or positional arguments.
 | 
					       passed to this call.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Note: The rules above prevent MarkDecorators from storing only a single
 | 
				
			||||||
 | 
					    function or class reference as their positional argument with no
 | 
				
			||||||
 | 
					    additional keyword or positional arguments. You can work around this by
 | 
				
			||||||
 | 
					    using `with_args()`.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mark = attr.ib(validator=attr.validators.instance_of(Mark))
 | 
					    mark = attr.ib(type=Mark, validator=attr.validators.instance_of(Mark))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def name(self):
 | 
					    def name(self) -> str:
 | 
				
			||||||
        """alias for mark.name"""
 | 
					        """Alias for mark.name."""
 | 
				
			||||||
        return self.mark.name
 | 
					        return self.mark.name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def args(self):
 | 
					    def args(self) -> Tuple[Any, ...]:
 | 
				
			||||||
        """alias for mark.args"""
 | 
					        """Alias for mark.args."""
 | 
				
			||||||
        return self.mark.args
 | 
					        return self.mark.args
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def kwargs(self):
 | 
					    def kwargs(self) -> Mapping[str, Any]:
 | 
				
			||||||
        """alias for mark.kwargs"""
 | 
					        """Alias for mark.kwargs."""
 | 
				
			||||||
        return self.mark.kwargs
 | 
					        return self.mark.kwargs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def markname(self):
 | 
					    def markname(self) -> str:
 | 
				
			||||||
        return self.name  # for backward-compat (2.4.1 had this attr)
 | 
					        return self.name  # for backward-compat (2.4.1 had this attr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __repr__(self):
 | 
					    def __repr__(self) -> str:
 | 
				
			||||||
        return "<MarkDecorator {!r}>".format(self.mark)
 | 
					        return "<MarkDecorator {!r}>".format(self.mark)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def with_args(self, *args, **kwargs):
 | 
					    def with_args(self, *args: object, **kwargs: object) -> "MarkDecorator":
 | 
				
			||||||
        """ return a MarkDecorator with extra arguments added
 | 
					        """Return a MarkDecorator with extra arguments added.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        unlike call this can be used even if the sole argument is a callable/class
 | 
					        Unlike calling the MarkDecorator, with_args() can be used even
 | 
				
			||||||
 | 
					        if the sole argument is a callable/class.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        :return: MarkDecorator
 | 
					        :return: 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, **kwargs):
 | 
					    def __call__(self, *args: object, **kwargs: object):
 | 
				
			||||||
        """ if passed a single callable argument: decorate it with mark info.
 | 
					        """Call the MarkDecorator."""
 | 
				
			||||||
            otherwise add *args/**kwargs in-place to mark information. """
 | 
					 | 
				
			||||||
        if args and not kwargs:
 | 
					        if args and not kwargs:
 | 
				
			||||||
            func = args[0]
 | 
					            func = args[0]
 | 
				
			||||||
            is_class = inspect.isclass(func)
 | 
					            is_class = inspect.isclass(func)
 | 
				
			||||||
| 
						 | 
					@ -288,27 +297,31 @@ def normalize_mark_list(mark_list: Iterable[Union[Mark, MarkDecorator]]) -> List
 | 
				
			||||||
    return [x for x in extracted if isinstance(x, Mark)]
 | 
					    return [x for x in extracted if isinstance(x, Mark)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def store_mark(obj, mark):
 | 
					def store_mark(obj, mark: Mark) -> None:
 | 
				
			||||||
    """store a Mark on an object
 | 
					    """Store a Mark on an object.
 | 
				
			||||||
    this is used to implement the Mark declarations/decorators correctly
 | 
					
 | 
				
			||||||
 | 
					    This is used to implement the Mark declarations/decorators correctly.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    assert isinstance(mark, Mark), mark
 | 
					    assert isinstance(mark, Mark), mark
 | 
				
			||||||
    # always reassign name to avoid updating pytestmark
 | 
					    # Always reassign name to avoid updating pytestmark in a reference that
 | 
				
			||||||
    # in a reference that was only borrowed
 | 
					    # was only borrowed.
 | 
				
			||||||
    obj.pytestmark = get_unpacked_marks(obj) + [mark]
 | 
					    obj.pytestmark = get_unpacked_marks(obj) + [mark]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MarkGenerator:
 | 
					class MarkGenerator:
 | 
				
			||||||
    """ Factory for :class:`MarkDecorator` objects - exposed as
 | 
					    """Factory for :class:`MarkDecorator` objects - exposed as
 | 
				
			||||||
    a ``pytest.mark`` singleton instance.  Example::
 | 
					    a ``pytest.mark`` singleton instance.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Example::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
         import pytest
 | 
					         import pytest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
         @pytest.mark.slowtest
 | 
					         @pytest.mark.slowtest
 | 
				
			||||||
         def test_function():
 | 
					         def test_function():
 | 
				
			||||||
            pass
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    will set a 'slowtest' :class:`MarkInfo` object
 | 
					    applies a 'slowtest' :class:`Mark` on ``test_function``.
 | 
				
			||||||
    on the ``test_function`` object. """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _config = None
 | 
					    _config = None
 | 
				
			||||||
    _markers = set()  # type: Set[str]
 | 
					    _markers = set()  # type: Set[str]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue