Skip to content

Commit e6eac28

Browse files
committed
legacypath: only add testdir and tmpdir fixtures if corresponding plugins are registered
This preserves the existing behavior and gives a proper error message in case e.g. `testdir` is requested without the `pytester` plugin being loaded.
1 parent c3dff75 commit e6eac28

File tree

2 files changed

+51
-41
lines changed

2 files changed

+51
-41
lines changed

doc/en/reference/reference.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ tmpdir
638638

639639
:ref:`tmpdir and tmpdir_factory`
640640

641-
.. autofunction:: _pytest.legacypath.tmpdir()
641+
.. autofunction:: _pytest.legacypath.LegacyTmpdirPlugin.tmpdir()
642642
:no-auto-options:
643643

644644

src/_pytest/legacypath.py

Lines changed: 50 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -248,15 +248,17 @@ def __str__(self) -> str:
248248
pytest.Testdir = Testdir # type: ignore[attr-defined]
249249

250250

251-
@pytest.fixture
252-
def testdir(pytester: pytest.Pytester) -> Testdir:
253-
"""
254-
Identical to :fixture:`pytester`, and provides an instance whose methods return
255-
legacy ``LEGACY_PATH`` objects instead when applicable.
251+
class LegacyTestdirPlugin:
252+
@staticmethod
253+
@pytest.fixture
254+
def testdir(pytester: pytest.Pytester) -> Testdir:
255+
"""
256+
Identical to :fixture:`pytester`, and provides an instance whose methods return
257+
legacy ``LEGACY_PATH`` objects instead when applicable.
256258
257-
New code should avoid using :fixture:`testdir` in favor of :fixture:`pytester`.
258-
"""
259-
return Testdir(pytester, _ispytest=True)
259+
New code should avoid using :fixture:`testdir` in favor of :fixture:`pytester`.
260+
"""
261+
return Testdir(pytester, _ispytest=True)
260262

261263

262264
@final
@@ -285,29 +287,31 @@ def getbasetemp(self) -> LEGACY_PATH:
285287
pytest.TempdirFactory = TempdirFactory # type: ignore[attr-defined]
286288

287289

288-
@pytest.fixture(scope="session")
289-
def tmpdir_factory(request: pytest.FixtureRequest) -> TempdirFactory:
290-
"""Return a :class:`pytest.TempdirFactory` instance for the test session."""
291-
# Set dynamically by pytest_configure().
292-
return request.config._tmpdirhandler # type: ignore
290+
class LegacyTmpdirPlugin:
291+
@staticmethod
292+
@pytest.fixture(scope="session")
293+
def tmpdir_factory(request: pytest.FixtureRequest) -> TempdirFactory:
294+
"""Return a :class:`pytest.TempdirFactory` instance for the test session."""
295+
# Set dynamically by pytest_configure().
296+
return request.config._tmpdirhandler # type: ignore
293297

298+
@staticmethod
299+
@pytest.fixture
300+
def tmpdir(tmp_path: Path) -> LEGACY_PATH:
301+
"""Return a temporary directory path object which is unique to each test
302+
function invocation, created as a sub directory of the base temporary
303+
directory.
294304
295-
@pytest.fixture
296-
def tmpdir(tmp_path: Path) -> LEGACY_PATH:
297-
"""Return a temporary directory path object which is unique to each test
298-
function invocation, created as a sub directory of the base temporary
299-
directory.
305+
By default, a new base temporary directory is created each test session,
306+
and old bases are removed after 3 sessions, to aid in debugging. If
307+
``--basetemp`` is used then it is cleared each session. See :ref:`base
308+
temporary directory`.
300309
301-
By default, a new base temporary directory is created each test session,
302-
and old bases are removed after 3 sessions, to aid in debugging. If
303-
``--basetemp`` is used then it is cleared each session. See :ref:`base
304-
temporary directory`.
310+
The returned object is a `legacy_path`_ object.
305311
306-
The returned object is a `legacy_path`_ object.
307-
308-
.. _legacy_path: https://py.readthedocs.io/en/latest/path.html
309-
"""
310-
return legacy_path(tmp_path)
312+
.. _legacy_path: https://py.readthedocs.io/en/latest/path.html
313+
"""
314+
return legacy_path(tmp_path)
311315

312316

313317
def Cache_makedir(self: pytest.Cache, name: str) -> LEGACY_PATH:
@@ -400,19 +404,25 @@ def pytest_configure(config: pytest.Config) -> None:
400404
mp = pytest.MonkeyPatch()
401405
config.add_cleanup(mp.undo)
402406

403-
# Create TmpdirFactory and attach it to the config object.
404-
#
405-
# This is to comply with existing plugins which expect the handler to be
406-
# available at pytest_configure time, but ideally should be moved entirely
407-
# to the tmpdir_factory session fixture.
408-
try:
409-
tmp_path_factory = config._tmp_path_factory # type: ignore[attr-defined]
410-
except AttributeError:
411-
# tmpdir plugin is blocked.
412-
pass
413-
else:
414-
_tmpdirhandler = TempdirFactory(tmp_path_factory, _ispytest=True)
415-
mp.setattr(config, "_tmpdirhandler", _tmpdirhandler, raising=False)
407+
if config.pluginmanager.has_plugin("pytester"):
408+
config.pluginmanager.register(LegacyTestdirPlugin, "legacypath-pytester")
409+
410+
if config.pluginmanager.has_plugin("tmpdir"):
411+
# Create TmpdirFactory and attach it to the config object.
412+
#
413+
# This is to comply with existing plugins which expect the handler to be
414+
# available at pytest_configure time, but ideally should be moved entirely
415+
# to the tmpdir_factory session fixture.
416+
try:
417+
tmp_path_factory = config._tmp_path_factory # type: ignore[attr-defined]
418+
except AttributeError:
419+
# tmpdir plugin is blocked.
420+
pass
421+
else:
422+
_tmpdirhandler = TempdirFactory(tmp_path_factory, _ispytest=True)
423+
mp.setattr(config, "_tmpdirhandler", _tmpdirhandler, raising=False)
424+
425+
config.pluginmanager.register(LegacyTmpdirPlugin, "legacypath-tmpdir")
416426

417427
# Add Cache.makedir().
418428
mp.setattr(pytest.Cache, "makedir", Cache_makedir, raising=False)

0 commit comments

Comments
 (0)