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.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.

View File

@ -4,6 +4,7 @@ The newly-exported types are:
- ``pytest.Mark`` for :class:`marks <pytest.Mark>`.
- ``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.
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
~~~~~~~~~~~~~
.. autoclass:: _pytest.mark.MarkGenerator
.. autoclass:: pytest.MarkGenerator()
:members:

View File

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

View File

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

View File

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