Export types of builtin fixture for type annotations
In order to allow users to type annotate fixtures they request, the types need to be imported from the `pytest` namespace. They are/were always available to import from the `_pytest` namespace, but that is not guaranteed to be stable. These types are only exported for the purpose of typing. Specifically, the following are *not* public: - Construction (`__init__`) - Subclassing - staticmethods and classmethods We try to combat them being used anyway by: - Marking the classes as `@final` when possible (already done). - Not documenting private stuff in the API Reference. - Using `_`-prefixed names or marking as `:meta private:` for private stuff. - Adding a keyword-only `_ispytest=False` to private constructors, warning if False, and changing pytest itself to pass True. In the future it will (hopefully) become a hard error. Hopefully that will be enough.
This commit is contained in:
parent
b050578882
commit
f1e6fdcddb
|
@ -0,0 +1,18 @@
|
||||||
|
Directly constructing/calling the following classes/functions is now deprecated:
|
||||||
|
|
||||||
|
- ``_pytest.cacheprovider.Cache``
|
||||||
|
- ``_pytest.cacheprovider.Cache.for_config()``
|
||||||
|
- ``_pytest.cacheprovider.Cache.clear_cache()``
|
||||||
|
- ``_pytest.cacheprovider.Cache.cache_dir_from_config()``
|
||||||
|
- ``_pytest.capture.CaptureFixture``
|
||||||
|
- ``_pytest.fixtures.FixtureRequest``
|
||||||
|
- ``_pytest.fixtures.SubRequest``
|
||||||
|
- ``_pytest.logging.LogCaptureFixture``
|
||||||
|
- ``_pytest.pytester.Pytester``
|
||||||
|
- ``_pytest.pytester.Testdir``
|
||||||
|
- ``_pytest.recwarn.WarningsRecorder``
|
||||||
|
- ``_pytest.recwarn.WarningsChecker``
|
||||||
|
- ``_pytest.tmpdir.TempPathFactory``
|
||||||
|
- ``_pytest.tmpdir.TempdirFactory``
|
||||||
|
|
||||||
|
These have always been considered private, but now issue a deprecation warning, which may become a hard error in pytest 7.0.0.
|
|
@ -0,0 +1,23 @@
|
||||||
|
It is now possible to construct a :class:`MonkeyPatch` object directly as ``pytest.MonkeyPatch()``,
|
||||||
|
in cases when the :fixture:`monkeypatch` fixture cannot be used. Previously some users imported it
|
||||||
|
from the private `_pytest.monkeypatch.MonkeyPatch` namespace.
|
||||||
|
|
||||||
|
The types of builtin pytest fixtures are now exported so they may be used in type annotations of test functions.
|
||||||
|
The newly-exported types are:
|
||||||
|
|
||||||
|
- ``pytest.FixtureRequest`` for the :fixture:`request` fixture.
|
||||||
|
- ``pytest.Cache`` for the :fixture:`cache` fixture.
|
||||||
|
- ``pytest.CaptureFixture[str]`` for the :fixture:`capfd` and :fixture:`capsys` fixtures.
|
||||||
|
- ``pytest.CaptureFixture[bytes]`` for the :fixture:`capfdbinary` and :fixture:`capsysbinary` fixtures.
|
||||||
|
- ``pytest.LogCaptureFixture`` for the :fixture:`caplog` fixture.
|
||||||
|
- ``pytest.Pytester`` for the :fixture:`pytester` fixture.
|
||||||
|
- ``pytest.Testdir`` for the :fixture:`testdir` fixture.
|
||||||
|
- ``pytest.TempdirFactory`` for the :fixture:`tmpdir_factory` fixture.
|
||||||
|
- ``pytest.TempPathFactory`` for the :fixture:`tmp_path_factory` fixture.
|
||||||
|
- ``pytest.MonkeyPatch`` for the :fixture:`monkeypatch` fixture.
|
||||||
|
- ``pytest.WarningsRecorder`` for the :fixture:`recwarn` fixture.
|
||||||
|
|
||||||
|
Constructing them is not supported (except for `MonkeyPatch`); 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.
|
||||||
|
|
||||||
|
Subclassing them is also not supported. This is not currently enforced at runtime, but is detected by type-checkers such as mypy.
|
|
@ -304,11 +304,10 @@ request ``pytestconfig`` into your fixture and get it with ``pytestconfig.cache`
|
||||||
Under the hood, the cache plugin uses the simple
|
Under the hood, the cache plugin uses the simple
|
||||||
``dumps``/``loads`` API of the :py:mod:`json` stdlib module.
|
``dumps``/``loads`` API of the :py:mod:`json` stdlib module.
|
||||||
|
|
||||||
.. currentmodule:: _pytest.cacheprovider
|
``config.cache`` is an instance of :class:`pytest.Cache`:
|
||||||
|
|
||||||
.. automethod:: Cache.get
|
.. autoclass:: pytest.Cache()
|
||||||
.. automethod:: Cache.set
|
:members:
|
||||||
.. automethod:: Cache.makedir
|
|
||||||
|
|
||||||
|
|
||||||
.. fixture:: capsys
|
.. fixture:: capsys
|
||||||
|
@ -318,12 +317,10 @@ capsys
|
||||||
|
|
||||||
**Tutorial**: :doc:`capture`.
|
**Tutorial**: :doc:`capture`.
|
||||||
|
|
||||||
.. currentmodule:: _pytest.capture
|
.. autofunction:: _pytest.capture.capsys()
|
||||||
|
|
||||||
.. autofunction:: capsys()
|
|
||||||
:no-auto-options:
|
:no-auto-options:
|
||||||
|
|
||||||
Returns an instance of :py:class:`CaptureFixture`.
|
Returns an instance of :class:`CaptureFixture[str] <pytest.CaptureFixture>`.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -334,7 +331,7 @@ capsys
|
||||||
captured = capsys.readouterr()
|
captured = capsys.readouterr()
|
||||||
assert captured.out == "hello\n"
|
assert captured.out == "hello\n"
|
||||||
|
|
||||||
.. autoclass:: CaptureFixture()
|
.. autoclass:: pytest.CaptureFixture()
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|
||||||
|
@ -345,10 +342,10 @@ capsysbinary
|
||||||
|
|
||||||
**Tutorial**: :doc:`capture`.
|
**Tutorial**: :doc:`capture`.
|
||||||
|
|
||||||
.. autofunction:: capsysbinary()
|
.. autofunction:: _pytest.capture.capsysbinary()
|
||||||
:no-auto-options:
|
:no-auto-options:
|
||||||
|
|
||||||
Returns an instance of :py:class:`CaptureFixture`.
|
Returns an instance of :class:`CaptureFixture[bytes] <pytest.CaptureFixture>`.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -367,10 +364,10 @@ capfd
|
||||||
|
|
||||||
**Tutorial**: :doc:`capture`.
|
**Tutorial**: :doc:`capture`.
|
||||||
|
|
||||||
.. autofunction:: capfd()
|
.. autofunction:: _pytest.capture.capfd()
|
||||||
:no-auto-options:
|
:no-auto-options:
|
||||||
|
|
||||||
Returns an instance of :py:class:`CaptureFixture`.
|
Returns an instance of :class:`CaptureFixture[str] <pytest.CaptureFixture>`.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -389,10 +386,10 @@ capfdbinary
|
||||||
|
|
||||||
**Tutorial**: :doc:`capture`.
|
**Tutorial**: :doc:`capture`.
|
||||||
|
|
||||||
.. autofunction:: capfdbinary()
|
.. autofunction:: _pytest.capture.capfdbinary()
|
||||||
:no-auto-options:
|
:no-auto-options:
|
||||||
|
|
||||||
Returns an instance of :py:class:`CaptureFixture`.
|
Returns an instance of :class:`CaptureFixture[bytes] <pytest.CaptureFixture>`.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -433,7 +430,7 @@ request
|
||||||
|
|
||||||
The ``request`` fixture is a special fixture providing information of the requesting test function.
|
The ``request`` fixture is a special fixture providing information of the requesting test function.
|
||||||
|
|
||||||
.. autoclass:: _pytest.fixtures.FixtureRequest()
|
.. autoclass:: pytest.FixtureRequest()
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|
||||||
|
@ -475,9 +472,9 @@ caplog
|
||||||
.. autofunction:: _pytest.logging.caplog()
|
.. autofunction:: _pytest.logging.caplog()
|
||||||
:no-auto-options:
|
:no-auto-options:
|
||||||
|
|
||||||
Returns a :class:`_pytest.logging.LogCaptureFixture` instance.
|
Returns a :class:`pytest.LogCaptureFixture` instance.
|
||||||
|
|
||||||
.. autoclass:: _pytest.logging.LogCaptureFixture
|
.. autoclass:: pytest.LogCaptureFixture()
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|
||||||
|
@ -504,9 +501,7 @@ pytester
|
||||||
|
|
||||||
.. versionadded:: 6.2
|
.. versionadded:: 6.2
|
||||||
|
|
||||||
.. currentmodule:: _pytest.pytester
|
Provides a :class:`~pytest.Pytester` instance that can be used to run and test pytest itself.
|
||||||
|
|
||||||
Provides a :class:`Pytester` instance that can be used to run and test pytest itself.
|
|
||||||
|
|
||||||
It provides an empty directory where pytest can be executed in isolation, and contains facilities
|
It provides an empty directory where pytest can be executed in isolation, and contains facilities
|
||||||
to write tests, configuration files, and match against expected output.
|
to write tests, configuration files, and match against expected output.
|
||||||
|
@ -519,16 +514,16 @@ To use it, include in your topmost ``conftest.py`` file:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. autoclass:: Pytester()
|
.. autoclass:: pytest.Pytester()
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
.. autoclass:: RunResult()
|
.. autoclass:: _pytest.pytester.RunResult()
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
.. autoclass:: LineMatcher()
|
.. autoclass:: _pytest.pytester.LineMatcher()
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
.. autoclass:: HookRecorder()
|
.. autoclass:: _pytest.pytester.HookRecorder()
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
.. fixture:: testdir
|
.. fixture:: testdir
|
||||||
|
@ -541,7 +536,7 @@ legacy ``py.path.local`` objects instead when applicable.
|
||||||
|
|
||||||
New code should avoid using :fixture:`testdir` in favor of :fixture:`pytester`.
|
New code should avoid using :fixture:`testdir` in favor of :fixture:`pytester`.
|
||||||
|
|
||||||
.. autoclass:: Testdir()
|
.. autoclass:: pytest.Testdir()
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|
||||||
|
@ -552,12 +547,10 @@ recwarn
|
||||||
|
|
||||||
**Tutorial**: :ref:`assertwarnings`
|
**Tutorial**: :ref:`assertwarnings`
|
||||||
|
|
||||||
.. currentmodule:: _pytest.recwarn
|
.. autofunction:: _pytest.recwarn.recwarn()
|
||||||
|
|
||||||
.. autofunction:: recwarn()
|
|
||||||
:no-auto-options:
|
:no-auto-options:
|
||||||
|
|
||||||
.. autoclass:: WarningsRecorder()
|
.. autoclass:: pytest.WarningsRecorder()
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
Each recorded warning is an instance of :class:`warnings.WarningMessage`.
|
Each recorded warning is an instance of :class:`warnings.WarningMessage`.
|
||||||
|
@ -574,13 +567,11 @@ tmp_path
|
||||||
|
|
||||||
**Tutorial**: :doc:`tmpdir`
|
**Tutorial**: :doc:`tmpdir`
|
||||||
|
|
||||||
.. currentmodule:: _pytest.tmpdir
|
.. autofunction:: _pytest.tmpdir.tmp_path()
|
||||||
|
|
||||||
.. autofunction:: tmp_path()
|
|
||||||
:no-auto-options:
|
:no-auto-options:
|
||||||
|
|
||||||
|
|
||||||
.. fixture:: tmp_path_factory
|
.. fixture:: _pytest.tmpdir.tmp_path_factory
|
||||||
|
|
||||||
tmp_path_factory
|
tmp_path_factory
|
||||||
~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~
|
||||||
|
@ -589,12 +580,9 @@ tmp_path_factory
|
||||||
|
|
||||||
.. _`tmp_path_factory factory api`:
|
.. _`tmp_path_factory factory api`:
|
||||||
|
|
||||||
``tmp_path_factory`` instances have the following methods:
|
``tmp_path_factory`` is an instance of :class:`~pytest.TempPathFactory`:
|
||||||
|
|
||||||
.. currentmodule:: _pytest.tmpdir
|
.. autoclass:: pytest.TempPathFactory()
|
||||||
|
|
||||||
.. automethod:: TempPathFactory.mktemp
|
|
||||||
.. automethod:: TempPathFactory.getbasetemp
|
|
||||||
|
|
||||||
|
|
||||||
.. fixture:: tmpdir
|
.. fixture:: tmpdir
|
||||||
|
@ -604,9 +592,7 @@ tmpdir
|
||||||
|
|
||||||
**Tutorial**: :doc:`tmpdir`
|
**Tutorial**: :doc:`tmpdir`
|
||||||
|
|
||||||
.. currentmodule:: _pytest.tmpdir
|
.. autofunction:: _pytest.tmpdir.tmpdir()
|
||||||
|
|
||||||
.. autofunction:: tmpdir()
|
|
||||||
:no-auto-options:
|
:no-auto-options:
|
||||||
|
|
||||||
|
|
||||||
|
@ -619,12 +605,9 @@ tmpdir_factory
|
||||||
|
|
||||||
.. _`tmpdir factory api`:
|
.. _`tmpdir factory api`:
|
||||||
|
|
||||||
``tmpdir_factory`` instances have the following methods:
|
``tmp_path_factory`` is an instance of :class:`~pytest.TempdirFactory`:
|
||||||
|
|
||||||
.. currentmodule:: _pytest.tmpdir
|
.. autoclass:: pytest.TempdirFactory()
|
||||||
|
|
||||||
.. automethod:: TempdirFactory.mktemp
|
|
||||||
.. automethod:: TempdirFactory.getbasetemp
|
|
||||||
|
|
||||||
|
|
||||||
.. _`hook-reference`:
|
.. _`hook-reference`:
|
||||||
|
|
|
@ -25,6 +25,7 @@ from _pytest.config import Config
|
||||||
from _pytest.config import ExitCode
|
from _pytest.config import ExitCode
|
||||||
from _pytest.config import hookimpl
|
from _pytest.config import hookimpl
|
||||||
from _pytest.config.argparsing import Parser
|
from _pytest.config.argparsing import Parser
|
||||||
|
from _pytest.deprecated import check_ispytest
|
||||||
from _pytest.fixtures import fixture
|
from _pytest.fixtures import fixture
|
||||||
from _pytest.fixtures import FixtureRequest
|
from _pytest.fixtures import FixtureRequest
|
||||||
from _pytest.main import Session
|
from _pytest.main import Session
|
||||||
|
@ -53,7 +54,7 @@ Signature: 8a477f597d28d172789f06886806bc55
|
||||||
|
|
||||||
|
|
||||||
@final
|
@final
|
||||||
@attr.s
|
@attr.s(init=False)
|
||||||
class Cache:
|
class Cache:
|
||||||
_cachedir = attr.ib(type=Path, repr=False)
|
_cachedir = attr.ib(type=Path, repr=False)
|
||||||
_config = attr.ib(type=Config, repr=False)
|
_config = attr.ib(type=Config, repr=False)
|
||||||
|
@ -64,26 +65,52 @@ class Cache:
|
||||||
# sub-directory under cache-dir for values created by "set"
|
# sub-directory under cache-dir for values created by "set"
|
||||||
_CACHE_PREFIX_VALUES = "v"
|
_CACHE_PREFIX_VALUES = "v"
|
||||||
|
|
||||||
@classmethod
|
def __init__(
|
||||||
def for_config(cls, config: Config) -> "Cache":
|
self, cachedir: Path, config: Config, *, _ispytest: bool = False
|
||||||
cachedir = cls.cache_dir_from_config(config)
|
) -> None:
|
||||||
if config.getoption("cacheclear") and cachedir.is_dir():
|
check_ispytest(_ispytest)
|
||||||
cls.clear_cache(cachedir)
|
self._cachedir = cachedir
|
||||||
return cls(cachedir, config)
|
self._config = config
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def clear_cache(cls, cachedir: Path) -> None:
|
def for_config(cls, config: Config, *, _ispytest: bool = False) -> "Cache":
|
||||||
"""Clear the sub-directories used to hold cached directories and values."""
|
"""Create the Cache instance for a Config.
|
||||||
|
|
||||||
|
:meta private:
|
||||||
|
"""
|
||||||
|
check_ispytest(_ispytest)
|
||||||
|
cachedir = cls.cache_dir_from_config(config, _ispytest=True)
|
||||||
|
if config.getoption("cacheclear") and cachedir.is_dir():
|
||||||
|
cls.clear_cache(cachedir, _ispytest=True)
|
||||||
|
return cls(cachedir, config, _ispytest=True)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def clear_cache(cls, cachedir: Path, _ispytest: bool = False) -> None:
|
||||||
|
"""Clear the sub-directories used to hold cached directories and values.
|
||||||
|
|
||||||
|
:meta private:
|
||||||
|
"""
|
||||||
|
check_ispytest(_ispytest)
|
||||||
for prefix in (cls._CACHE_PREFIX_DIRS, cls._CACHE_PREFIX_VALUES):
|
for prefix in (cls._CACHE_PREFIX_DIRS, cls._CACHE_PREFIX_VALUES):
|
||||||
d = cachedir / prefix
|
d = cachedir / prefix
|
||||||
if d.is_dir():
|
if d.is_dir():
|
||||||
rm_rf(d)
|
rm_rf(d)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def cache_dir_from_config(config: Config) -> Path:
|
def cache_dir_from_config(config: Config, *, _ispytest: bool = False) -> Path:
|
||||||
|
"""Get the path to the cache directory for a Config.
|
||||||
|
|
||||||
|
:meta private:
|
||||||
|
"""
|
||||||
|
check_ispytest(_ispytest)
|
||||||
return resolve_from_str(config.getini("cache_dir"), config.rootpath)
|
return resolve_from_str(config.getini("cache_dir"), config.rootpath)
|
||||||
|
|
||||||
def warn(self, fmt: str, **args: object) -> None:
|
def warn(self, fmt: str, *, _ispytest: bool = False, **args: object) -> None:
|
||||||
|
"""Issue a cache warning.
|
||||||
|
|
||||||
|
:meta private:
|
||||||
|
"""
|
||||||
|
check_ispytest(_ispytest)
|
||||||
import warnings
|
import warnings
|
||||||
from _pytest.warning_types import PytestCacheWarning
|
from _pytest.warning_types import PytestCacheWarning
|
||||||
|
|
||||||
|
@ -152,7 +179,7 @@ class Cache:
|
||||||
cache_dir_exists_already = self._cachedir.exists()
|
cache_dir_exists_already = self._cachedir.exists()
|
||||||
path.parent.mkdir(exist_ok=True, parents=True)
|
path.parent.mkdir(exist_ok=True, parents=True)
|
||||||
except OSError:
|
except OSError:
|
||||||
self.warn("could not create cache path {path}", path=path)
|
self.warn("could not create cache path {path}", path=path, _ispytest=True)
|
||||||
return
|
return
|
||||||
if not cache_dir_exists_already:
|
if not cache_dir_exists_already:
|
||||||
self._ensure_supporting_files()
|
self._ensure_supporting_files()
|
||||||
|
@ -160,7 +187,7 @@ class Cache:
|
||||||
try:
|
try:
|
||||||
f = path.open("w")
|
f = path.open("w")
|
||||||
except OSError:
|
except OSError:
|
||||||
self.warn("cache could not write path {path}", path=path)
|
self.warn("cache could not write path {path}", path=path, _ispytest=True)
|
||||||
else:
|
else:
|
||||||
with f:
|
with f:
|
||||||
f.write(data)
|
f.write(data)
|
||||||
|
@ -469,7 +496,7 @@ def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]:
|
||||||
|
|
||||||
@hookimpl(tryfirst=True)
|
@hookimpl(tryfirst=True)
|
||||||
def pytest_configure(config: Config) -> None:
|
def pytest_configure(config: Config) -> None:
|
||||||
config.cache = Cache.for_config(config)
|
config.cache = Cache.for_config(config, _ispytest=True)
|
||||||
config.pluginmanager.register(LFPlugin(config), "lfplugin")
|
config.pluginmanager.register(LFPlugin(config), "lfplugin")
|
||||||
config.pluginmanager.register(NFPlugin(config), "nfplugin")
|
config.pluginmanager.register(NFPlugin(config), "nfplugin")
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ from _pytest.compat import final
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
from _pytest.config import hookimpl
|
from _pytest.config import hookimpl
|
||||||
from _pytest.config.argparsing import Parser
|
from _pytest.config.argparsing import Parser
|
||||||
|
from _pytest.deprecated import check_ispytest
|
||||||
from _pytest.fixtures import fixture
|
from _pytest.fixtures import fixture
|
||||||
from _pytest.fixtures import SubRequest
|
from _pytest.fixtures import SubRequest
|
||||||
from _pytest.nodes import Collector
|
from _pytest.nodes import Collector
|
||||||
|
@ -826,10 +827,13 @@ class CaptureManager:
|
||||||
|
|
||||||
|
|
||||||
class CaptureFixture(Generic[AnyStr]):
|
class CaptureFixture(Generic[AnyStr]):
|
||||||
"""Object returned by the :py:func:`capsys`, :py:func:`capsysbinary`,
|
"""Object returned by the :fixture:`capsys`, :fixture:`capsysbinary`,
|
||||||
:py:func:`capfd` and :py:func:`capfdbinary` fixtures."""
|
:fixture:`capfd` and :fixture:`capfdbinary` fixtures."""
|
||||||
|
|
||||||
def __init__(self, captureclass, request: SubRequest) -> None:
|
def __init__(
|
||||||
|
self, captureclass, request: SubRequest, *, _ispytest: bool = False
|
||||||
|
) -> None:
|
||||||
|
check_ispytest(_ispytest)
|
||||||
self.captureclass = captureclass
|
self.captureclass = captureclass
|
||||||
self.request = request
|
self.request = request
|
||||||
self._capture: Optional[MultiCapture[AnyStr]] = None
|
self._capture: Optional[MultiCapture[AnyStr]] = None
|
||||||
|
@ -904,7 +908,7 @@ def capsys(request: SubRequest) -> Generator[CaptureFixture[str], None, None]:
|
||||||
``out`` and ``err`` will be ``text`` objects.
|
``out`` and ``err`` will be ``text`` objects.
|
||||||
"""
|
"""
|
||||||
capman = request.config.pluginmanager.getplugin("capturemanager")
|
capman = request.config.pluginmanager.getplugin("capturemanager")
|
||||||
capture_fixture = CaptureFixture[str](SysCapture, request)
|
capture_fixture = CaptureFixture[str](SysCapture, request, _ispytest=True)
|
||||||
capman.set_fixture(capture_fixture)
|
capman.set_fixture(capture_fixture)
|
||||||
capture_fixture._start()
|
capture_fixture._start()
|
||||||
yield capture_fixture
|
yield capture_fixture
|
||||||
|
@ -921,7 +925,7 @@ def capsysbinary(request: SubRequest) -> Generator[CaptureFixture[bytes], None,
|
||||||
``out`` and ``err`` will be ``bytes`` objects.
|
``out`` and ``err`` will be ``bytes`` objects.
|
||||||
"""
|
"""
|
||||||
capman = request.config.pluginmanager.getplugin("capturemanager")
|
capman = request.config.pluginmanager.getplugin("capturemanager")
|
||||||
capture_fixture = CaptureFixture[bytes](SysCaptureBinary, request)
|
capture_fixture = CaptureFixture[bytes](SysCaptureBinary, request, _ispytest=True)
|
||||||
capman.set_fixture(capture_fixture)
|
capman.set_fixture(capture_fixture)
|
||||||
capture_fixture._start()
|
capture_fixture._start()
|
||||||
yield capture_fixture
|
yield capture_fixture
|
||||||
|
@ -938,7 +942,7 @@ def capfd(request: SubRequest) -> Generator[CaptureFixture[str], None, None]:
|
||||||
``out`` and ``err`` will be ``text`` objects.
|
``out`` and ``err`` will be ``text`` objects.
|
||||||
"""
|
"""
|
||||||
capman = request.config.pluginmanager.getplugin("capturemanager")
|
capman = request.config.pluginmanager.getplugin("capturemanager")
|
||||||
capture_fixture = CaptureFixture[str](FDCapture, request)
|
capture_fixture = CaptureFixture[str](FDCapture, request, _ispytest=True)
|
||||||
capman.set_fixture(capture_fixture)
|
capman.set_fixture(capture_fixture)
|
||||||
capture_fixture._start()
|
capture_fixture._start()
|
||||||
yield capture_fixture
|
yield capture_fixture
|
||||||
|
@ -955,7 +959,7 @@ def capfdbinary(request: SubRequest) -> Generator[CaptureFixture[bytes], None, N
|
||||||
``out`` and ``err`` will be ``byte`` objects.
|
``out`` and ``err`` will be ``byte`` objects.
|
||||||
"""
|
"""
|
||||||
capman = request.config.pluginmanager.getplugin("capturemanager")
|
capman = request.config.pluginmanager.getplugin("capturemanager")
|
||||||
capture_fixture = CaptureFixture[bytes](FDCaptureBinary, request)
|
capture_fixture = CaptureFixture[bytes](FDCaptureBinary, request, _ispytest=True)
|
||||||
capman.set_fixture(capture_fixture)
|
capman.set_fixture(capture_fixture)
|
||||||
capture_fixture._start()
|
capture_fixture._start()
|
||||||
yield capture_fixture
|
yield capture_fixture
|
||||||
|
|
|
@ -8,6 +8,8 @@ All constants defined in this module should be either instances of
|
||||||
:class:`PytestWarning`, or :class:`UnformattedWarning`
|
:class:`PytestWarning`, or :class:`UnformattedWarning`
|
||||||
in case of warnings which need to format their messages.
|
in case of warnings which need to format their messages.
|
||||||
"""
|
"""
|
||||||
|
from warnings import warn
|
||||||
|
|
||||||
from _pytest.warning_types import PytestDeprecationWarning
|
from _pytest.warning_types import PytestDeprecationWarning
|
||||||
from _pytest.warning_types import UnformattedWarning
|
from _pytest.warning_types import UnformattedWarning
|
||||||
|
|
||||||
|
@ -59,3 +61,27 @@ FSCOLLECTOR_GETHOOKPROXY_ISINITPATH = PytestDeprecationWarning(
|
||||||
STRICT_OPTION = PytestDeprecationWarning(
|
STRICT_OPTION = PytestDeprecationWarning(
|
||||||
"The --strict option is deprecated, use --strict-markers instead."
|
"The --strict option is deprecated, use --strict-markers instead."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
PRIVATE = PytestDeprecationWarning("A private pytest class or function was used.")
|
||||||
|
|
||||||
|
|
||||||
|
# You want to make some `__init__` or function "private".
|
||||||
|
#
|
||||||
|
# def my_private_function(some, args):
|
||||||
|
# ...
|
||||||
|
#
|
||||||
|
# Do this:
|
||||||
|
#
|
||||||
|
# def my_private_function(some, args, *, _ispytest: bool = False):
|
||||||
|
# check_ispytest(_ispytest)
|
||||||
|
# ...
|
||||||
|
#
|
||||||
|
# Change all internal/allowed calls to
|
||||||
|
#
|
||||||
|
# my_private_function(some, args, _ispytest=True)
|
||||||
|
#
|
||||||
|
# All other calls will get the default _ispytest=False and trigger
|
||||||
|
# the warning (possibly error in the future).
|
||||||
|
def check_ispytest(ispytest: bool) -> None:
|
||||||
|
if not ispytest:
|
||||||
|
warn(PRIVATE, stacklevel=3)
|
||||||
|
|
|
@ -563,7 +563,7 @@ def _setup_fixtures(doctest_item: DoctestItem) -> FixtureRequest:
|
||||||
doctest_item._fixtureinfo = fm.getfixtureinfo( # type: ignore[attr-defined]
|
doctest_item._fixtureinfo = fm.getfixtureinfo( # type: ignore[attr-defined]
|
||||||
node=doctest_item, func=func, cls=None, funcargs=False
|
node=doctest_item, func=func, cls=None, funcargs=False
|
||||||
)
|
)
|
||||||
fixture_request = FixtureRequest(doctest_item)
|
fixture_request = FixtureRequest(doctest_item, _ispytest=True)
|
||||||
fixture_request._fillfixtures()
|
fixture_request._fillfixtures()
|
||||||
return fixture_request
|
return fixture_request
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ from _pytest.compat import safe_getattr
|
||||||
from _pytest.config import _PluggyPlugin
|
from _pytest.config import _PluggyPlugin
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
from _pytest.config.argparsing import Parser
|
from _pytest.config.argparsing import Parser
|
||||||
|
from _pytest.deprecated import check_ispytest
|
||||||
from _pytest.deprecated import FILLFUNCARGS
|
from _pytest.deprecated import FILLFUNCARGS
|
||||||
from _pytest.deprecated import YIELD_FIXTURE
|
from _pytest.deprecated import YIELD_FIXTURE
|
||||||
from _pytest.mark import Mark
|
from _pytest.mark import Mark
|
||||||
|
@ -367,7 +368,7 @@ def _fill_fixtures_impl(function: "Function") -> None:
|
||||||
assert function.parent is not None
|
assert function.parent is not None
|
||||||
fi = fm.getfixtureinfo(function.parent, function.obj, None)
|
fi = fm.getfixtureinfo(function.parent, function.obj, None)
|
||||||
function._fixtureinfo = fi
|
function._fixtureinfo = fi
|
||||||
request = function._request = FixtureRequest(function)
|
request = function._request = FixtureRequest(function, _ispytest=True)
|
||||||
request._fillfixtures()
|
request._fillfixtures()
|
||||||
# Prune out funcargs for jstests.
|
# Prune out funcargs for jstests.
|
||||||
newfuncargs = {}
|
newfuncargs = {}
|
||||||
|
@ -429,7 +430,8 @@ class FixtureRequest:
|
||||||
indirectly.
|
indirectly.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, pyfuncitem) -> None:
|
def __init__(self, pyfuncitem, *, _ispytest: bool = False) -> None:
|
||||||
|
check_ispytest(_ispytest)
|
||||||
self._pyfuncitem = pyfuncitem
|
self._pyfuncitem = pyfuncitem
|
||||||
#: Fixture for which this request is being performed.
|
#: Fixture for which this request is being performed.
|
||||||
self.fixturename: Optional[str] = None
|
self.fixturename: Optional[str] = None
|
||||||
|
@ -674,7 +676,9 @@ class FixtureRequest:
|
||||||
if paramscopenum is not None:
|
if paramscopenum is not None:
|
||||||
scope = scopes[paramscopenum]
|
scope = scopes[paramscopenum]
|
||||||
|
|
||||||
subrequest = SubRequest(self, scope, param, param_index, fixturedef)
|
subrequest = SubRequest(
|
||||||
|
self, scope, param, param_index, fixturedef, _ispytest=True
|
||||||
|
)
|
||||||
|
|
||||||
# Check if a higher-level scoped fixture accesses a lower level one.
|
# Check if a higher-level scoped fixture accesses a lower level one.
|
||||||
subrequest._check_scope(argname, self.scope, scope)
|
subrequest._check_scope(argname, self.scope, scope)
|
||||||
|
@ -751,7 +755,10 @@ class SubRequest(FixtureRequest):
|
||||||
param,
|
param,
|
||||||
param_index: int,
|
param_index: int,
|
||||||
fixturedef: "FixtureDef[object]",
|
fixturedef: "FixtureDef[object]",
|
||||||
|
*,
|
||||||
|
_ispytest: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
check_ispytest(_ispytest)
|
||||||
self._parent_request = request
|
self._parent_request = request
|
||||||
self.fixturename = fixturedef.argname
|
self.fixturename = fixturedef.argname
|
||||||
if param is not NOTSET:
|
if param is not NOTSET:
|
||||||
|
@ -769,6 +776,8 @@ class SubRequest(FixtureRequest):
|
||||||
return f"<SubRequest {self.fixturename!r} for {self._pyfuncitem!r}>"
|
return f"<SubRequest {self.fixturename!r} for {self._pyfuncitem!r}>"
|
||||||
|
|
||||||
def addfinalizer(self, finalizer: Callable[[], object]) -> None:
|
def addfinalizer(self, finalizer: Callable[[], object]) -> None:
|
||||||
|
"""Add finalizer/teardown function to be called after the last test
|
||||||
|
within the requesting test context finished execution."""
|
||||||
self._fixturedef.addfinalizer(finalizer)
|
self._fixturedef.addfinalizer(finalizer)
|
||||||
|
|
||||||
def _schedule_finalizers(
|
def _schedule_finalizers(
|
||||||
|
|
|
@ -27,6 +27,7 @@ from _pytest.config import create_terminal_writer
|
||||||
from _pytest.config import hookimpl
|
from _pytest.config import hookimpl
|
||||||
from _pytest.config import UsageError
|
from _pytest.config import UsageError
|
||||||
from _pytest.config.argparsing import Parser
|
from _pytest.config.argparsing import Parser
|
||||||
|
from _pytest.deprecated import check_ispytest
|
||||||
from _pytest.fixtures import fixture
|
from _pytest.fixtures import fixture
|
||||||
from _pytest.fixtures import FixtureRequest
|
from _pytest.fixtures import FixtureRequest
|
||||||
from _pytest.main import Session
|
from _pytest.main import Session
|
||||||
|
@ -346,7 +347,8 @@ class LogCaptureHandler(logging.StreamHandler):
|
||||||
class LogCaptureFixture:
|
class LogCaptureFixture:
|
||||||
"""Provides access and control of log capturing."""
|
"""Provides access and control of log capturing."""
|
||||||
|
|
||||||
def __init__(self, item: nodes.Node) -> None:
|
def __init__(self, item: nodes.Node, *, _ispytest: bool = False) -> None:
|
||||||
|
check_ispytest(_ispytest)
|
||||||
self._item = item
|
self._item = item
|
||||||
self._initial_handler_level: Optional[int] = None
|
self._initial_handler_level: Optional[int] = None
|
||||||
# Dict of log name -> log level.
|
# Dict of log name -> log level.
|
||||||
|
@ -482,7 +484,7 @@ def caplog(request: FixtureRequest) -> Generator[LogCaptureFixture, None, None]:
|
||||||
* caplog.record_tuples -> list of (logger_name, level, message) tuples
|
* caplog.record_tuples -> list of (logger_name, level, message) tuples
|
||||||
* caplog.clear() -> clear captured records and formatted log output string
|
* caplog.clear() -> clear captured records and formatted log output string
|
||||||
"""
|
"""
|
||||||
result = LogCaptureFixture(request.node)
|
result = LogCaptureFixture(request.node, _ispytest=True)
|
||||||
yield result
|
yield result
|
||||||
result._finalize()
|
result._finalize()
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ from _pytest.config import hookimpl
|
||||||
from _pytest.config import main
|
from _pytest.config import main
|
||||||
from _pytest.config import PytestPluginManager
|
from _pytest.config import PytestPluginManager
|
||||||
from _pytest.config.argparsing import Parser
|
from _pytest.config.argparsing import Parser
|
||||||
|
from _pytest.deprecated import check_ispytest
|
||||||
from _pytest.fixtures import fixture
|
from _pytest.fixtures import fixture
|
||||||
from _pytest.fixtures import FixtureRequest
|
from _pytest.fixtures import FixtureRequest
|
||||||
from _pytest.main import Session
|
from _pytest.main import Session
|
||||||
|
@ -454,7 +455,7 @@ def pytester(request: FixtureRequest, tmp_path_factory: TempPathFactory) -> "Pyt
|
||||||
It is particularly useful for testing plugins. It is similar to the :fixture:`tmp_path`
|
It is particularly useful for testing plugins. It is similar to the :fixture:`tmp_path`
|
||||||
fixture but provides methods which aid in testing pytest itself.
|
fixture but provides methods which aid in testing pytest itself.
|
||||||
"""
|
"""
|
||||||
return Pytester(request, tmp_path_factory)
|
return Pytester(request, tmp_path_factory, _ispytest=True)
|
||||||
|
|
||||||
|
|
||||||
@fixture
|
@fixture
|
||||||
|
@ -465,7 +466,7 @@ def testdir(pytester: "Pytester") -> "Testdir":
|
||||||
|
|
||||||
New code should avoid using :fixture:`testdir` in favor of :fixture:`pytester`.
|
New code should avoid using :fixture:`testdir` in favor of :fixture:`pytester`.
|
||||||
"""
|
"""
|
||||||
return Testdir(pytester)
|
return Testdir(pytester, _ispytest=True)
|
||||||
|
|
||||||
|
|
||||||
@fixture
|
@fixture
|
||||||
|
@ -648,8 +649,13 @@ class Pytester:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, request: FixtureRequest, tmp_path_factory: TempPathFactory
|
self,
|
||||||
|
request: FixtureRequest,
|
||||||
|
tmp_path_factory: TempPathFactory,
|
||||||
|
*,
|
||||||
|
_ispytest: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
check_ispytest(_ispytest)
|
||||||
self._request = request
|
self._request = request
|
||||||
self._mod_collections: WeakKeyDictionary[
|
self._mod_collections: WeakKeyDictionary[
|
||||||
Collector, List[Union[Item, Collector]]
|
Collector, List[Union[Item, Collector]]
|
||||||
|
@ -1480,7 +1486,7 @@ class LineComp:
|
||||||
|
|
||||||
|
|
||||||
@final
|
@final
|
||||||
@attr.s(repr=False, str=False)
|
@attr.s(repr=False, str=False, init=False)
|
||||||
class Testdir:
|
class Testdir:
|
||||||
"""
|
"""
|
||||||
Similar to :class:`Pytester`, but this class works with legacy py.path.local objects instead.
|
Similar to :class:`Pytester`, but this class works with legacy py.path.local objects instead.
|
||||||
|
@ -1495,7 +1501,9 @@ class Testdir:
|
||||||
TimeoutExpired = Pytester.TimeoutExpired
|
TimeoutExpired = Pytester.TimeoutExpired
|
||||||
Session = Pytester.Session
|
Session = Pytester.Session
|
||||||
|
|
||||||
_pytester: Pytester = attr.ib()
|
def __init__(self, pytester: Pytester, *, _ispytest: bool = False) -> None:
|
||||||
|
check_ispytest(_ispytest)
|
||||||
|
self._pytester = pytester
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def tmpdir(self) -> py.path.local:
|
def tmpdir(self) -> py.path.local:
|
||||||
|
|
|
@ -1620,7 +1620,7 @@ class Function(PyobjMixin, nodes.Item):
|
||||||
|
|
||||||
def _initrequest(self) -> None:
|
def _initrequest(self) -> None:
|
||||||
self.funcargs: Dict[str, object] = {}
|
self.funcargs: Dict[str, object] = {}
|
||||||
self._request = fixtures.FixtureRequest(self)
|
self._request = fixtures.FixtureRequest(self, _ispytest=True)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def function(self):
|
def function(self):
|
||||||
|
|
|
@ -16,6 +16,7 @@ from typing import TypeVar
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
from _pytest.compat import final
|
from _pytest.compat import final
|
||||||
|
from _pytest.deprecated import check_ispytest
|
||||||
from _pytest.fixtures import fixture
|
from _pytest.fixtures import fixture
|
||||||
from _pytest.outcomes import fail
|
from _pytest.outcomes import fail
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ def recwarn() -> Generator["WarningsRecorder", None, None]:
|
||||||
See http://docs.python.org/library/warnings.html for information
|
See http://docs.python.org/library/warnings.html for information
|
||||||
on warning categories.
|
on warning categories.
|
||||||
"""
|
"""
|
||||||
wrec = WarningsRecorder()
|
wrec = WarningsRecorder(_ispytest=True)
|
||||||
with wrec:
|
with wrec:
|
||||||
warnings.simplefilter("default")
|
warnings.simplefilter("default")
|
||||||
yield wrec
|
yield wrec
|
||||||
|
@ -142,14 +143,14 @@ def warns(
|
||||||
msg += ", ".join(sorted(kwargs))
|
msg += ", ".join(sorted(kwargs))
|
||||||
msg += "\nUse context-manager form instead?"
|
msg += "\nUse context-manager form instead?"
|
||||||
raise TypeError(msg)
|
raise TypeError(msg)
|
||||||
return WarningsChecker(expected_warning, match_expr=match)
|
return WarningsChecker(expected_warning, match_expr=match, _ispytest=True)
|
||||||
else:
|
else:
|
||||||
func = args[0]
|
func = args[0]
|
||||||
if not callable(func):
|
if not callable(func):
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
"{!r} object (type: {}) must be callable".format(func, type(func))
|
"{!r} object (type: {}) must be callable".format(func, type(func))
|
||||||
)
|
)
|
||||||
with WarningsChecker(expected_warning):
|
with WarningsChecker(expected_warning, _ispytest=True):
|
||||||
return func(*args[1:], **kwargs)
|
return func(*args[1:], **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@ -159,7 +160,8 @@ class WarningsRecorder(warnings.catch_warnings):
|
||||||
Adapted from `warnings.catch_warnings`.
|
Adapted from `warnings.catch_warnings`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self, *, _ispytest: bool = False) -> None:
|
||||||
|
check_ispytest(_ispytest)
|
||||||
# Type ignored due to the way typeshed handles warnings.catch_warnings.
|
# Type ignored due to the way typeshed handles warnings.catch_warnings.
|
||||||
super().__init__(record=True) # type: ignore[call-arg]
|
super().__init__(record=True) # type: ignore[call-arg]
|
||||||
self._entered = False
|
self._entered = False
|
||||||
|
@ -232,8 +234,11 @@ class WarningsChecker(WarningsRecorder):
|
||||||
Union[Type[Warning], Tuple[Type[Warning], ...]]
|
Union[Type[Warning], Tuple[Type[Warning], ...]]
|
||||||
] = None,
|
] = None,
|
||||||
match_expr: Optional[Union[str, Pattern[str]]] = None,
|
match_expr: Optional[Union[str, Pattern[str]]] = None,
|
||||||
|
*,
|
||||||
|
_ispytest: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__()
|
check_ispytest(_ispytest)
|
||||||
|
super().__init__(_ispytest=True)
|
||||||
|
|
||||||
msg = "exceptions must be derived from Warning, not %s"
|
msg = "exceptions must be derived from Warning, not %s"
|
||||||
if expected_warning is None:
|
if expected_warning is None:
|
||||||
|
|
|
@ -14,37 +14,56 @@ from .pathlib import make_numbered_dir
|
||||||
from .pathlib import make_numbered_dir_with_cleanup
|
from .pathlib import make_numbered_dir_with_cleanup
|
||||||
from _pytest.compat import final
|
from _pytest.compat import final
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
|
from _pytest.deprecated import check_ispytest
|
||||||
from _pytest.fixtures import fixture
|
from _pytest.fixtures import fixture
|
||||||
from _pytest.fixtures import FixtureRequest
|
from _pytest.fixtures import FixtureRequest
|
||||||
from _pytest.monkeypatch import MonkeyPatch
|
from _pytest.monkeypatch import MonkeyPatch
|
||||||
|
|
||||||
|
|
||||||
@final
|
@final
|
||||||
@attr.s
|
@attr.s(init=False)
|
||||||
class TempPathFactory:
|
class TempPathFactory:
|
||||||
"""Factory for temporary directories under the common base temp directory.
|
"""Factory for temporary directories under the common base temp directory.
|
||||||
|
|
||||||
The base directory can be configured using the ``--basetemp`` option.
|
The base directory can be configured using the ``--basetemp`` option.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_given_basetemp = attr.ib(
|
_given_basetemp = attr.ib(type=Optional[Path])
|
||||||
type=Optional[Path],
|
_trace = attr.ib()
|
||||||
|
_basetemp = attr.ib(type=Optional[Path])
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
given_basetemp: Optional[Path],
|
||||||
|
trace,
|
||||||
|
basetemp: Optional[Path] = None,
|
||||||
|
*,
|
||||||
|
_ispytest: bool = False,
|
||||||
|
) -> None:
|
||||||
|
check_ispytest(_ispytest)
|
||||||
|
if given_basetemp is None:
|
||||||
|
self._given_basetemp = None
|
||||||
|
else:
|
||||||
# Use os.path.abspath() to get absolute path instead of resolve() as it
|
# Use os.path.abspath() to get absolute path instead of resolve() as it
|
||||||
# does not work the same in all platforms (see #4427).
|
# does not work the same in all platforms (see #4427).
|
||||||
# Path.absolute() exists, but it is not public (see https://bugs.python.org/issue25012).
|
# Path.absolute() exists, but it is not public (see https://bugs.python.org/issue25012).
|
||||||
# Ignore type because of https://github.com/python/mypy/issues/6172.
|
self._given_basetemp = Path(os.path.abspath(str(given_basetemp)))
|
||||||
converter=attr.converters.optional(
|
self._trace = trace
|
||||||
lambda p: Path(os.path.abspath(str(p))) # type: ignore
|
self._basetemp = basetemp
|
||||||
),
|
|
||||||
)
|
|
||||||
_trace = attr.ib()
|
|
||||||
_basetemp = attr.ib(type=Optional[Path], default=None)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_config(cls, config: Config) -> "TempPathFactory":
|
def from_config(
|
||||||
"""Create a factory according to pytest configuration."""
|
cls, config: Config, *, _ispytest: bool = False,
|
||||||
|
) -> "TempPathFactory":
|
||||||
|
"""Create a factory according to pytest configuration.
|
||||||
|
|
||||||
|
:meta private:
|
||||||
|
"""
|
||||||
|
check_ispytest(_ispytest)
|
||||||
return cls(
|
return cls(
|
||||||
given_basetemp=config.option.basetemp, trace=config.trace.get("tmpdir")
|
given_basetemp=config.option.basetemp,
|
||||||
|
trace=config.trace.get("tmpdir"),
|
||||||
|
_ispytest=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _ensure_relative_to_basetemp(self, basename: str) -> str:
|
def _ensure_relative_to_basetemp(self, basename: str) -> str:
|
||||||
|
@ -104,13 +123,19 @@ class TempPathFactory:
|
||||||
|
|
||||||
|
|
||||||
@final
|
@final
|
||||||
@attr.s
|
@attr.s(init=False)
|
||||||
class TempdirFactory:
|
class TempdirFactory:
|
||||||
"""Backward comptibility wrapper that implements :class:``py.path.local``
|
"""Backward comptibility wrapper that implements :class:``py.path.local``
|
||||||
for :class:``TempPathFactory``."""
|
for :class:``TempPathFactory``."""
|
||||||
|
|
||||||
_tmppath_factory = attr.ib(type=TempPathFactory)
|
_tmppath_factory = attr.ib(type=TempPathFactory)
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, tmppath_factory: TempPathFactory, *, _ispytest: bool = False
|
||||||
|
) -> None:
|
||||||
|
check_ispytest(_ispytest)
|
||||||
|
self._tmppath_factory = tmppath_factory
|
||||||
|
|
||||||
def mktemp(self, basename: str, numbered: bool = True) -> py.path.local:
|
def mktemp(self, basename: str, numbered: bool = True) -> py.path.local:
|
||||||
"""Same as :meth:`TempPathFactory.mktemp`, but returns a ``py.path.local`` object."""
|
"""Same as :meth:`TempPathFactory.mktemp`, but returns a ``py.path.local`` object."""
|
||||||
return py.path.local(self._tmppath_factory.mktemp(basename, numbered).resolve())
|
return py.path.local(self._tmppath_factory.mktemp(basename, numbered).resolve())
|
||||||
|
@ -139,8 +164,8 @@ def pytest_configure(config: Config) -> None:
|
||||||
to the tmpdir_factory session fixture.
|
to the tmpdir_factory session fixture.
|
||||||
"""
|
"""
|
||||||
mp = MonkeyPatch()
|
mp = MonkeyPatch()
|
||||||
tmppath_handler = TempPathFactory.from_config(config)
|
tmppath_handler = TempPathFactory.from_config(config, _ispytest=True)
|
||||||
t = TempdirFactory(tmppath_handler)
|
t = TempdirFactory(tmppath_handler, _ispytest=True)
|
||||||
config._cleanup.append(mp.undo)
|
config._cleanup.append(mp.undo)
|
||||||
mp.setattr(config, "_tmp_path_factory", tmppath_handler, raising=False)
|
mp.setattr(config, "_tmp_path_factory", tmppath_handler, raising=False)
|
||||||
mp.setattr(config, "_tmpdirhandler", t, raising=False)
|
mp.setattr(config, "_tmpdirhandler", t, raising=False)
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
from . import collect
|
from . import collect
|
||||||
from _pytest import __version__
|
from _pytest import __version__
|
||||||
from _pytest.assertion import register_assert_rewrite
|
from _pytest.assertion import register_assert_rewrite
|
||||||
|
from _pytest.cacheprovider import Cache
|
||||||
|
from _pytest.capture import CaptureFixture
|
||||||
from _pytest.config import cmdline
|
from _pytest.config import cmdline
|
||||||
from _pytest.config import console_main
|
from _pytest.config import console_main
|
||||||
from _pytest.config import ExitCode
|
from _pytest.config import ExitCode
|
||||||
|
@ -14,8 +16,10 @@ from _pytest.debugging import pytestPDB as __pytestPDB
|
||||||
from _pytest.fixtures import _fillfuncargs
|
from _pytest.fixtures import _fillfuncargs
|
||||||
from _pytest.fixtures import fixture
|
from _pytest.fixtures import fixture
|
||||||
from _pytest.fixtures import FixtureLookupError
|
from _pytest.fixtures import FixtureLookupError
|
||||||
|
from _pytest.fixtures import FixtureRequest
|
||||||
from _pytest.fixtures import yield_fixture
|
from _pytest.fixtures import yield_fixture
|
||||||
from _pytest.freeze_support import freeze_includes
|
from _pytest.freeze_support import freeze_includes
|
||||||
|
from _pytest.logging import LogCaptureFixture
|
||||||
from _pytest.main import Session
|
from _pytest.main import Session
|
||||||
from _pytest.mark import MARK_GEN as mark
|
from _pytest.mark import MARK_GEN as mark
|
||||||
from _pytest.mark import param
|
from _pytest.mark import param
|
||||||
|
@ -28,6 +32,8 @@ from _pytest.outcomes import fail
|
||||||
from _pytest.outcomes import importorskip
|
from _pytest.outcomes import importorskip
|
||||||
from _pytest.outcomes import skip
|
from _pytest.outcomes import skip
|
||||||
from _pytest.outcomes import xfail
|
from _pytest.outcomes import xfail
|
||||||
|
from _pytest.pytester import Pytester
|
||||||
|
from _pytest.pytester import Testdir
|
||||||
from _pytest.python import Class
|
from _pytest.python import Class
|
||||||
from _pytest.python import Function
|
from _pytest.python import Function
|
||||||
from _pytest.python import Instance
|
from _pytest.python import Instance
|
||||||
|
@ -36,7 +42,10 @@ from _pytest.python import Package
|
||||||
from _pytest.python_api import approx
|
from _pytest.python_api import approx
|
||||||
from _pytest.python_api import raises
|
from _pytest.python_api import raises
|
||||||
from _pytest.recwarn import deprecated_call
|
from _pytest.recwarn import deprecated_call
|
||||||
|
from _pytest.recwarn import WarningsRecorder
|
||||||
from _pytest.recwarn import warns
|
from _pytest.recwarn import warns
|
||||||
|
from _pytest.tmpdir import TempdirFactory
|
||||||
|
from _pytest.tmpdir import TempPathFactory
|
||||||
from _pytest.warning_types import PytestAssertRewriteWarning
|
from _pytest.warning_types import PytestAssertRewriteWarning
|
||||||
from _pytest.warning_types import PytestCacheWarning
|
from _pytest.warning_types import PytestCacheWarning
|
||||||
from _pytest.warning_types import PytestCollectionWarning
|
from _pytest.warning_types import PytestCollectionWarning
|
||||||
|
@ -53,6 +62,8 @@ __all__ = [
|
||||||
"__version__",
|
"__version__",
|
||||||
"_fillfuncargs",
|
"_fillfuncargs",
|
||||||
"approx",
|
"approx",
|
||||||
|
"Cache",
|
||||||
|
"CaptureFixture",
|
||||||
"Class",
|
"Class",
|
||||||
"cmdline",
|
"cmdline",
|
||||||
"collect",
|
"collect",
|
||||||
|
@ -65,6 +76,7 @@ __all__ = [
|
||||||
"File",
|
"File",
|
||||||
"fixture",
|
"fixture",
|
||||||
"FixtureLookupError",
|
"FixtureLookupError",
|
||||||
|
"FixtureRequest",
|
||||||
"freeze_includes",
|
"freeze_includes",
|
||||||
"Function",
|
"Function",
|
||||||
"hookimpl",
|
"hookimpl",
|
||||||
|
@ -72,6 +84,7 @@ __all__ = [
|
||||||
"importorskip",
|
"importorskip",
|
||||||
"Instance",
|
"Instance",
|
||||||
"Item",
|
"Item",
|
||||||
|
"LogCaptureFixture",
|
||||||
"main",
|
"main",
|
||||||
"mark",
|
"mark",
|
||||||
"Module",
|
"Module",
|
||||||
|
@ -84,6 +97,7 @@ __all__ = [
|
||||||
"PytestConfigWarning",
|
"PytestConfigWarning",
|
||||||
"PytestDeprecationWarning",
|
"PytestDeprecationWarning",
|
||||||
"PytestExperimentalApiWarning",
|
"PytestExperimentalApiWarning",
|
||||||
|
"Pytester",
|
||||||
"PytestUnhandledCoroutineWarning",
|
"PytestUnhandledCoroutineWarning",
|
||||||
"PytestUnknownMarkWarning",
|
"PytestUnknownMarkWarning",
|
||||||
"PytestWarning",
|
"PytestWarning",
|
||||||
|
@ -92,7 +106,11 @@ __all__ = [
|
||||||
"Session",
|
"Session",
|
||||||
"set_trace",
|
"set_trace",
|
||||||
"skip",
|
"skip",
|
||||||
|
"TempPathFactory",
|
||||||
|
"Testdir",
|
||||||
|
"TempdirFactory",
|
||||||
"UsageError",
|
"UsageError",
|
||||||
|
"WarningsRecorder",
|
||||||
"warns",
|
"warns",
|
||||||
"xfail",
|
"xfail",
|
||||||
"yield_fixture",
|
"yield_fixture",
|
||||||
|
|
|
@ -123,3 +123,17 @@ def test_yield_fixture_is_deprecated() -> None:
|
||||||
@pytest.yield_fixture
|
@pytest.yield_fixture
|
||||||
def fix():
|
def fix():
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
|
||||||
|
def test_private_is_deprecated() -> None:
|
||||||
|
class PrivateInit:
|
||||||
|
def __init__(self, foo: int, *, _ispytest: bool = False) -> None:
|
||||||
|
deprecated.check_ispytest(_ispytest)
|
||||||
|
|
||||||
|
with pytest.warns(
|
||||||
|
pytest.PytestDeprecationWarning, match="private pytest class or function"
|
||||||
|
):
|
||||||
|
PrivateInit(10)
|
||||||
|
|
||||||
|
# Doesn't warn.
|
||||||
|
PrivateInit(10, _ispytest=True)
|
||||||
|
|
|
@ -621,7 +621,7 @@ class TestRequestBasic:
|
||||||
def test_func(something): pass
|
def test_func(something): pass
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
req = fixtures.FixtureRequest(item)
|
req = fixtures.FixtureRequest(item, _ispytest=True)
|
||||||
assert req.function == item.obj
|
assert req.function == item.obj
|
||||||
assert req.keywords == item.keywords
|
assert req.keywords == item.keywords
|
||||||
assert hasattr(req.module, "test_func")
|
assert hasattr(req.module, "test_func")
|
||||||
|
@ -661,7 +661,9 @@ class TestRequestBasic:
|
||||||
)
|
)
|
||||||
(item1,) = testdir.genitems([modcol])
|
(item1,) = testdir.genitems([modcol])
|
||||||
assert item1.name == "test_method"
|
assert item1.name == "test_method"
|
||||||
arg2fixturedefs = fixtures.FixtureRequest(item1)._arg2fixturedefs
|
arg2fixturedefs = fixtures.FixtureRequest(
|
||||||
|
item1, _ispytest=True
|
||||||
|
)._arg2fixturedefs
|
||||||
assert len(arg2fixturedefs) == 1
|
assert len(arg2fixturedefs) == 1
|
||||||
assert arg2fixturedefs["something"][0].argname == "something"
|
assert arg2fixturedefs["something"][0].argname == "something"
|
||||||
|
|
||||||
|
@ -910,7 +912,7 @@ class TestRequestBasic:
|
||||||
def test_request_getmodulepath(self, testdir):
|
def test_request_getmodulepath(self, testdir):
|
||||||
modcol = testdir.getmodulecol("def test_somefunc(): pass")
|
modcol = testdir.getmodulecol("def test_somefunc(): pass")
|
||||||
(item,) = testdir.genitems([modcol])
|
(item,) = testdir.genitems([modcol])
|
||||||
req = fixtures.FixtureRequest(item)
|
req = fixtures.FixtureRequest(item, _ispytest=True)
|
||||||
assert req.fspath == modcol.fspath
|
assert req.fspath == modcol.fspath
|
||||||
|
|
||||||
def test_request_fixturenames(self, testdir):
|
def test_request_fixturenames(self, testdir):
|
||||||
|
@ -1052,7 +1054,7 @@ class TestRequestMarking:
|
||||||
pass
|
pass
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
req1 = fixtures.FixtureRequest(item1)
|
req1 = fixtures.FixtureRequest(item1, _ispytest=True)
|
||||||
assert "xfail" not in item1.keywords
|
assert "xfail" not in item1.keywords
|
||||||
req1.applymarker(pytest.mark.xfail)
|
req1.applymarker(pytest.mark.xfail)
|
||||||
assert "xfail" in item1.keywords
|
assert "xfail" in item1.keywords
|
||||||
|
@ -3882,7 +3884,7 @@ class TestScopeOrdering:
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
items, _ = testdir.inline_genitems()
|
items, _ = testdir.inline_genitems()
|
||||||
request = FixtureRequest(items[0])
|
request = FixtureRequest(items[0], _ispytest=True)
|
||||||
assert request.fixturenames == "m1 f1".split()
|
assert request.fixturenames == "m1 f1".split()
|
||||||
|
|
||||||
def test_func_closure_with_native_fixtures(self, testdir, monkeypatch) -> None:
|
def test_func_closure_with_native_fixtures(self, testdir, monkeypatch) -> None:
|
||||||
|
@ -3928,7 +3930,7 @@ class TestScopeOrdering:
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
items, _ = testdir.inline_genitems()
|
items, _ = testdir.inline_genitems()
|
||||||
request = FixtureRequest(items[0])
|
request = FixtureRequest(items[0], _ispytest=True)
|
||||||
# order of fixtures based on their scope and position in the parameter list
|
# order of fixtures based on their scope and position in the parameter list
|
||||||
assert (
|
assert (
|
||||||
request.fixturenames == "s1 my_tmpdir_factory p1 m1 f1 f2 my_tmpdir".split()
|
request.fixturenames == "s1 my_tmpdir_factory p1 m1 f1 f2 my_tmpdir".split()
|
||||||
|
@ -3954,7 +3956,7 @@ class TestScopeOrdering:
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
items, _ = testdir.inline_genitems()
|
items, _ = testdir.inline_genitems()
|
||||||
request = FixtureRequest(items[0])
|
request = FixtureRequest(items[0], _ispytest=True)
|
||||||
assert request.fixturenames == "m1 f1".split()
|
assert request.fixturenames == "m1 f1".split()
|
||||||
|
|
||||||
def test_func_closure_scopes_reordered(self, testdir):
|
def test_func_closure_scopes_reordered(self, testdir):
|
||||||
|
@ -3987,7 +3989,7 @@ class TestScopeOrdering:
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
items, _ = testdir.inline_genitems()
|
items, _ = testdir.inline_genitems()
|
||||||
request = FixtureRequest(items[0])
|
request = FixtureRequest(items[0], _ispytest=True)
|
||||||
assert request.fixturenames == "s1 m1 c1 f2 f1".split()
|
assert request.fixturenames == "s1 m1 c1 f2 f1".split()
|
||||||
|
|
||||||
def test_func_closure_same_scope_closer_root_first(self, testdir):
|
def test_func_closure_same_scope_closer_root_first(self, testdir):
|
||||||
|
@ -4027,7 +4029,7 @@ class TestScopeOrdering:
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
items, _ = testdir.inline_genitems()
|
items, _ = testdir.inline_genitems()
|
||||||
request = FixtureRequest(items[0])
|
request = FixtureRequest(items[0], _ispytest=True)
|
||||||
assert request.fixturenames == "p_sub m_conf m_sub m_test f1".split()
|
assert request.fixturenames == "p_sub m_conf m_sub m_test f1".split()
|
||||||
|
|
||||||
def test_func_closure_all_scopes_complex(self, testdir):
|
def test_func_closure_all_scopes_complex(self, testdir):
|
||||||
|
@ -4071,7 +4073,7 @@ class TestScopeOrdering:
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
items, _ = testdir.inline_genitems()
|
items, _ = testdir.inline_genitems()
|
||||||
request = FixtureRequest(items[0])
|
request = FixtureRequest(items[0], _ispytest=True)
|
||||||
assert request.fixturenames == "s1 p1 m1 m2 c1 f2 f1".split()
|
assert request.fixturenames == "s1 p1 m1 m2 c1 f2 f1".split()
|
||||||
|
|
||||||
def test_multiple_packages(self, testdir):
|
def test_multiple_packages(self, testdir):
|
||||||
|
|
|
@ -1156,7 +1156,7 @@ def test_gitignore(testdir):
|
||||||
from _pytest.cacheprovider import Cache
|
from _pytest.cacheprovider import Cache
|
||||||
|
|
||||||
config = testdir.parseconfig()
|
config = testdir.parseconfig()
|
||||||
cache = Cache.for_config(config)
|
cache = Cache.for_config(config, _ispytest=True)
|
||||||
cache.set("foo", "bar")
|
cache.set("foo", "bar")
|
||||||
msg = "# Created by pytest automatically.\n*\n"
|
msg = "# Created by pytest automatically.\n*\n"
|
||||||
gitignore_path = cache._cachedir.joinpath(".gitignore")
|
gitignore_path = cache._cachedir.joinpath(".gitignore")
|
||||||
|
@ -1178,7 +1178,7 @@ def test_does_not_create_boilerplate_in_existing_dirs(testdir):
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
config = testdir.parseconfig()
|
config = testdir.parseconfig()
|
||||||
cache = Cache.for_config(config)
|
cache = Cache.for_config(config, _ispytest=True)
|
||||||
cache.set("foo", "bar")
|
cache.set("foo", "bar")
|
||||||
|
|
||||||
assert os.path.isdir("v") # cache contents
|
assert os.path.isdir("v") # cache contents
|
||||||
|
@ -1192,7 +1192,7 @@ def test_cachedir_tag(testdir):
|
||||||
from _pytest.cacheprovider import CACHEDIR_TAG_CONTENT
|
from _pytest.cacheprovider import CACHEDIR_TAG_CONTENT
|
||||||
|
|
||||||
config = testdir.parseconfig()
|
config = testdir.parseconfig()
|
||||||
cache = Cache.for_config(config)
|
cache = Cache.for_config(config, _ispytest=True)
|
||||||
cache.set("foo", "bar")
|
cache.set("foo", "bar")
|
||||||
cachedir_tag_path = cache._cachedir.joinpath("CACHEDIR.TAG")
|
cachedir_tag_path = cache._cachedir.joinpath("CACHEDIR.TAG")
|
||||||
assert cachedir_tag_path.read_bytes() == CACHEDIR_TAG_CONTENT
|
assert cachedir_tag_path.read_bytes() == CACHEDIR_TAG_CONTENT
|
||||||
|
|
|
@ -28,7 +28,7 @@ def test_recwarn_functional(testdir) -> None:
|
||||||
|
|
||||||
class TestWarningsRecorderChecker:
|
class TestWarningsRecorderChecker:
|
||||||
def test_recording(self) -> None:
|
def test_recording(self) -> None:
|
||||||
rec = WarningsRecorder()
|
rec = WarningsRecorder(_ispytest=True)
|
||||||
with rec:
|
with rec:
|
||||||
assert not rec.list
|
assert not rec.list
|
||||||
warnings.warn_explicit("hello", UserWarning, "xyz", 13)
|
warnings.warn_explicit("hello", UserWarning, "xyz", 13)
|
||||||
|
@ -45,7 +45,7 @@ class TestWarningsRecorderChecker:
|
||||||
|
|
||||||
def test_warn_stacklevel(self) -> None:
|
def test_warn_stacklevel(self) -> None:
|
||||||
"""#4243"""
|
"""#4243"""
|
||||||
rec = WarningsRecorder()
|
rec = WarningsRecorder(_ispytest=True)
|
||||||
with rec:
|
with rec:
|
||||||
warnings.warn("test", DeprecationWarning, 2)
|
warnings.warn("test", DeprecationWarning, 2)
|
||||||
|
|
||||||
|
@ -53,21 +53,21 @@ class TestWarningsRecorderChecker:
|
||||||
from _pytest.recwarn import WarningsChecker
|
from _pytest.recwarn import WarningsChecker
|
||||||
|
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
WarningsChecker(5) # type: ignore
|
WarningsChecker(5, _ispytest=True) # type: ignore[arg-type]
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
WarningsChecker(("hi", RuntimeWarning)) # type: ignore
|
WarningsChecker(("hi", RuntimeWarning), _ispytest=True) # type: ignore[arg-type]
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
WarningsChecker([DeprecationWarning, RuntimeWarning]) # type: ignore
|
WarningsChecker([DeprecationWarning, RuntimeWarning], _ispytest=True) # type: ignore[arg-type]
|
||||||
|
|
||||||
def test_invalid_enter_exit(self) -> None:
|
def test_invalid_enter_exit(self) -> None:
|
||||||
# wrap this test in WarningsRecorder to ensure warning state gets reset
|
# wrap this test in WarningsRecorder to ensure warning state gets reset
|
||||||
with WarningsRecorder():
|
with WarningsRecorder(_ispytest=True):
|
||||||
with pytest.raises(RuntimeError):
|
with pytest.raises(RuntimeError):
|
||||||
rec = WarningsRecorder()
|
rec = WarningsRecorder(_ispytest=True)
|
||||||
rec.__exit__(None, None, None) # can't exit before entering
|
rec.__exit__(None, None, None) # can't exit before entering
|
||||||
|
|
||||||
with pytest.raises(RuntimeError):
|
with pytest.raises(RuntimeError):
|
||||||
rec = WarningsRecorder()
|
rec = WarningsRecorder(_ispytest=True)
|
||||||
with rec:
|
with rec:
|
||||||
with rec:
|
with rec:
|
||||||
pass # can't enter twice
|
pass # can't enter twice
|
||||||
|
|
|
@ -48,7 +48,9 @@ class FakeConfig:
|
||||||
class TestTempdirHandler:
|
class TestTempdirHandler:
|
||||||
def test_mktemp(self, tmp_path):
|
def test_mktemp(self, tmp_path):
|
||||||
config = cast(Config, FakeConfig(tmp_path))
|
config = cast(Config, FakeConfig(tmp_path))
|
||||||
t = TempdirFactory(TempPathFactory.from_config(config))
|
t = TempdirFactory(
|
||||||
|
TempPathFactory.from_config(config, _ispytest=True), _ispytest=True
|
||||||
|
)
|
||||||
tmp = t.mktemp("world")
|
tmp = t.mktemp("world")
|
||||||
assert tmp.relto(t.getbasetemp()) == "world0"
|
assert tmp.relto(t.getbasetemp()) == "world0"
|
||||||
tmp = t.mktemp("this")
|
tmp = t.mktemp("this")
|
||||||
|
@ -61,7 +63,7 @@ class TestTempdirHandler:
|
||||||
"""#4425"""
|
"""#4425"""
|
||||||
monkeypatch.chdir(tmp_path)
|
monkeypatch.chdir(tmp_path)
|
||||||
config = cast(Config, FakeConfig("hello"))
|
config = cast(Config, FakeConfig("hello"))
|
||||||
t = TempPathFactory.from_config(config)
|
t = TempPathFactory.from_config(config, _ispytest=True)
|
||||||
assert t.getbasetemp().resolve() == (tmp_path / "hello").resolve()
|
assert t.getbasetemp().resolve() == (tmp_path / "hello").resolve()
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue