mark: export pytest.MarkGenerator for typing purposes

The type cannot be constructed directly, but is exported for use in type
annotations, since it is reachable through existing public API.
This commit is contained in:
Ran Benita 2020-12-20 15:36:24 +02:00
parent 69c302479e
commit 6aa4d1c7ab
6 changed files with 14 additions and 7 deletions

View File

@ -2,5 +2,6 @@ Directly constructing the following classes is now deprecated:
- ``_pytest.mark.structures.Mark`` - ``_pytest.mark.structures.Mark``
- ``_pytest.mark.structures.MarkDecorator`` - ``_pytest.mark.structures.MarkDecorator``
- ``_pytest.mark.structures.MarkGenerator``
These have always been considered private, but now issue a deprecation warning, which may become a hard error in pytest 7.0.0. These have always been considered private, but now issue a deprecation warning, which may become a hard error in pytest 7.0.0.

View File

@ -4,6 +4,7 @@ The newly-exported types are:
- ``pytest.Mark`` for :class:`marks <pytest.Mark>`. - ``pytest.Mark`` for :class:`marks <pytest.Mark>`.
- ``pytest.MarkDecorator`` for :class:`mark decorators <pytest.MarkDecorator>`. - ``pytest.MarkDecorator`` for :class:`mark decorators <pytest.MarkDecorator>`.
- ``pytest.MarkGenerator`` for the :class:`pytest.mark <pytest.MarkGenerator>` singleton.
Constructing them directly is not supported; they are only meant for use in type annotations. Constructing them directly is not supported; they are only meant for use in type annotations.
Doing so will emit a deprecation warning, and may become a hard-error in pytest 7.0. Doing so will emit a deprecation warning, and may become a hard-error in pytest 7.0.

View File

@ -856,7 +856,7 @@ MarkDecorator
MarkGenerator MarkGenerator
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
.. autoclass:: _pytest.mark.MarkGenerator .. autoclass:: pytest.MarkGenerator()
:members: :members:

View File

@ -488,9 +488,6 @@ class MarkGenerator:
applies a 'slowtest' :class:`Mark` on ``test_function``. applies a 'slowtest' :class:`Mark` on ``test_function``.
""" """
_config: Optional[Config] = None
_markers: Set[str] = set()
# See TYPE_CHECKING above. # See TYPE_CHECKING above.
if TYPE_CHECKING: if TYPE_CHECKING:
skip: _SkipMarkDecorator skip: _SkipMarkDecorator
@ -500,7 +497,13 @@ class MarkGenerator:
usefixtures: _UsefixturesMarkDecorator usefixtures: _UsefixturesMarkDecorator
filterwarnings: _FilterwarningsMarkDecorator filterwarnings: _FilterwarningsMarkDecorator
def __init__(self, *, _ispytest: bool = False) -> None:
check_ispytest(_ispytest)
self._config: Optional[Config] = None
self._markers: Set[str] = set()
def __getattr__(self, name: str) -> MarkDecorator: def __getattr__(self, name: str) -> MarkDecorator:
"""Generate a new :class:`MarkDecorator` with the given name."""
if name[0] == "_": if name[0] == "_":
raise AttributeError("Marker name must NOT start with underscore") raise AttributeError("Marker name must NOT start with underscore")
@ -541,7 +544,7 @@ class MarkGenerator:
return MarkDecorator(Mark(name, (), {}, _ispytest=True), _ispytest=True) return MarkDecorator(Mark(name, (), {}, _ispytest=True), _ispytest=True)
MARK_GEN = MarkGenerator() MARK_GEN = MarkGenerator(_ispytest=True)
@final @final

View File

@ -24,6 +24,7 @@ from _pytest.main import Session
from _pytest.mark import Mark from _pytest.mark import Mark
from _pytest.mark import MARK_GEN as mark from _pytest.mark import MARK_GEN as mark
from _pytest.mark import MarkDecorator from _pytest.mark import MarkDecorator
from _pytest.mark import MarkGenerator
from _pytest.mark import param from _pytest.mark import param
from _pytest.monkeypatch import MonkeyPatch from _pytest.monkeypatch import MonkeyPatch
from _pytest.nodes import Collector from _pytest.nodes import Collector
@ -93,6 +94,7 @@ __all__ = [
"mark", "mark",
"Mark", "Mark",
"MarkDecorator", "MarkDecorator",
"MarkGenerator",
"Module", "Module",
"MonkeyPatch", "MonkeyPatch",
"Package", "Package",

View File

@ -21,7 +21,7 @@ class TestMark:
assert attr in module.__all__ # type: ignore assert attr in module.__all__ # type: ignore
def test_pytest_mark_notcallable(self) -> None: def test_pytest_mark_notcallable(self) -> None:
mark = MarkGenerator() mark = MarkGenerator(_ispytest=True)
with pytest.raises(TypeError): with pytest.raises(TypeError):
mark() # type: ignore[operator] mark() # type: ignore[operator]
@ -40,7 +40,7 @@ class TestMark:
assert pytest.mark.foo.with_args(SomeClass) is not SomeClass # type: ignore[comparison-overlap] assert pytest.mark.foo.with_args(SomeClass) is not SomeClass # type: ignore[comparison-overlap]
def test_pytest_mark_name_starts_with_underscore(self) -> None: def test_pytest_mark_name_starts_with_underscore(self) -> None:
mark = MarkGenerator() mark = MarkGenerator(_ispytest=True)
with pytest.raises(AttributeError): with pytest.raises(AttributeError):
mark._some_name mark._some_name