From 6aa4d1c7ab968aecf44ad89e568a4515bd7e5343 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Sun, 20 Dec 2020 15:36:24 +0200 Subject: [PATCH] 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. --- changelog/7469.deprecation.rst | 1 + changelog/7469.feature.rst | 1 + doc/en/reference.rst | 2 +- src/_pytest/mark/structures.py | 11 +++++++---- src/pytest/__init__.py | 2 ++ testing/test_mark.py | 4 ++-- 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/changelog/7469.deprecation.rst b/changelog/7469.deprecation.rst index 6922b3bbb..6bbc80755 100644 --- a/changelog/7469.deprecation.rst +++ b/changelog/7469.deprecation.rst @@ -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. diff --git a/changelog/7469.feature.rst b/changelog/7469.feature.rst index 66113aa58..81f93d1f7 100644 --- a/changelog/7469.feature.rst +++ b/changelog/7469.feature.rst @@ -4,6 +4,7 @@ The newly-exported types are: - ``pytest.Mark`` for :class:`marks `. - ``pytest.MarkDecorator`` for :class:`mark decorators `. +- ``pytest.MarkGenerator`` for the :class:`pytest.mark ` 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. diff --git a/doc/en/reference.rst b/doc/en/reference.rst index 8bd4111a1..c8e8dca75 100644 --- a/doc/en/reference.rst +++ b/doc/en/reference.rst @@ -856,7 +856,7 @@ MarkDecorator MarkGenerator ~~~~~~~~~~~~~ -.. autoclass:: _pytest.mark.MarkGenerator +.. autoclass:: pytest.MarkGenerator() :members: diff --git a/src/_pytest/mark/structures.py b/src/_pytest/mark/structures.py index 8bce33e68..ae6920735 100644 --- a/src/_pytest/mark/structures.py +++ b/src/_pytest/mark/structures.py @@ -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 diff --git a/src/pytest/__init__.py b/src/pytest/__init__.py index 1d5b38ee0..74cf00ee2 100644 --- a/src/pytest/__init__.py +++ b/src/pytest/__init__.py @@ -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", diff --git a/testing/test_mark.py b/testing/test_mark.py index e0b91f0ce..5f4b3e063 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -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