Skip to content

Commit 5e883f5

Browse files
committed
Move tmpdir to legacypath plugin
1 parent 1df28a4 commit 5e883f5

File tree

6 files changed

+117
-77
lines changed

6 files changed

+117
-77
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.tmpdir.tmpdir()
641+
.. autofunction:: _pytest.legacypath.tmpdir()
642642
:no-auto-options:
643643

644644

src/_pytest/legacypath.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
"""Add backward compatibility support for the legacy py path type."""
22
import subprocess
3+
from pathlib import Path
34
from typing import List
45
from typing import Optional
56
from typing import TYPE_CHECKING
67
from typing import Union
78

9+
import attr
810
from iniconfig import SectionWrapper
911

1012
import pytest
@@ -252,3 +254,73 @@ def testdir(pytester: pytest.Pytester) -> Testdir:
252254
New code should avoid using :fixture:`testdir` in favor of :fixture:`pytester`.
253255
"""
254256
return Testdir(pytester, _ispytest=True)
257+
258+
259+
@final
260+
@attr.s(init=False, auto_attribs=True)
261+
class TempdirFactory:
262+
"""Backward compatibility wrapper that implements :class:``_pytest.compat.LEGACY_PATH``
263+
for :class:``TempPathFactory``."""
264+
265+
_tmppath_factory: pytest.TempPathFactory
266+
267+
def __init__(
268+
self, tmppath_factory: pytest.TempPathFactory, *, _ispytest: bool = False
269+
) -> None:
270+
check_ispytest(_ispytest)
271+
self._tmppath_factory = tmppath_factory
272+
273+
def mktemp(self, basename: str, numbered: bool = True) -> LEGACY_PATH:
274+
"""Same as :meth:`TempPathFactory.mktemp`, but returns a ``_pytest.compat.LEGACY_PATH`` object."""
275+
return legacy_path(self._tmppath_factory.mktemp(basename, numbered).resolve())
276+
277+
def getbasetemp(self) -> LEGACY_PATH:
278+
"""Backward compat wrapper for ``_tmppath_factory.getbasetemp``."""
279+
return legacy_path(self._tmppath_factory.getbasetemp().resolve())
280+
281+
282+
pytest.TempdirFactory = TempdirFactory # type: ignore[attr-defined]
283+
284+
285+
@pytest.fixture(scope="session")
286+
def tmpdir_factory(request: pytest.FixtureRequest) -> TempdirFactory:
287+
"""Return a :class:`pytest.TempdirFactory` instance for the test session."""
288+
# Set dynamically by pytest_configure().
289+
return request.config._tmpdirhandler # type: ignore
290+
291+
292+
@pytest.fixture
293+
def tmpdir(tmp_path: Path) -> LEGACY_PATH:
294+
"""Return a temporary directory path object which is unique to each test
295+
function invocation, created as a sub directory of the base temporary
296+
directory.
297+
298+
By default, a new base temporary directory is created each test session,
299+
and old bases are removed after 3 sessions, to aid in debugging. If
300+
``--basetemp`` is used then it is cleared each session. See :ref:`base
301+
temporary directory`.
302+
303+
The returned object is a `legacy_path`_ object.
304+
305+
.. _legacy_path: https://py.readthedocs.io/en/latest/path.html
306+
"""
307+
return legacy_path(tmp_path)
308+
309+
310+
def pytest_configure(config: pytest.Config) -> None:
311+
mp = pytest.MonkeyPatch()
312+
config.add_cleanup(mp.undo)
313+
314+
# Create TmpdirFactory and attach it to the config object.
315+
#
316+
# This is to comply with existing plugins which expect the handler to be
317+
# available at pytest_configure time, but ideally should be moved entirely
318+
# to the tmpdir_factory session fixture.
319+
try:
320+
tmp_path_factory = config._tmp_path_factory # type: ignore[attr-defined]
321+
except AttributeError:
322+
# tmpdir plugin is blocked.
323+
pass
324+
else:
325+
_tmpdirhandler = TempdirFactory(tmp_path_factory, _ispytest=True)
326+
mp.setattr(config, "_tmpdirhandler", _tmpdirhandler, raising=False)

src/_pytest/tmpdir.py

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
from .pathlib import make_numbered_dir_with_cleanup
1414
from .pathlib import rm_rf
1515
from _pytest.compat import final
16-
from _pytest.compat import LEGACY_PATH
17-
from _pytest.compat import legacy_path
1816
from _pytest.config import Config
1917
from _pytest.deprecated import check_ispytest
2018
from _pytest.fixtures import fixture
@@ -157,29 +155,6 @@ def getbasetemp(self) -> Path:
157155
return basetemp
158156

159157

160-
@final
161-
@attr.s(init=False, auto_attribs=True)
162-
class TempdirFactory:
163-
"""Backward compatibility wrapper that implements :class:``_pytest.compat.LEGACY_PATH``
164-
for :class:``TempPathFactory``."""
165-
166-
_tmppath_factory: TempPathFactory
167-
168-
def __init__(
169-
self, tmppath_factory: TempPathFactory, *, _ispytest: bool = False
170-
) -> None:
171-
check_ispytest(_ispytest)
172-
self._tmppath_factory = tmppath_factory
173-
174-
def mktemp(self, basename: str, numbered: bool = True) -> LEGACY_PATH:
175-
"""Same as :meth:`TempPathFactory.mktemp`, but returns a ``_pytest.compat.LEGACY_PATH`` object."""
176-
return legacy_path(self._tmppath_factory.mktemp(basename, numbered).resolve())
177-
178-
def getbasetemp(self) -> LEGACY_PATH:
179-
"""Backward compat wrapper for ``_tmppath_factory.getbasetemp``."""
180-
return legacy_path(self._tmppath_factory.getbasetemp().resolve())
181-
182-
183158
def get_user() -> Optional[str]:
184159
"""Return the current user name, or None if getuser() does not work
185160
in the current environment (see #1010)."""
@@ -201,16 +176,7 @@ def pytest_configure(config: Config) -> None:
201176
mp = MonkeyPatch()
202177
config.add_cleanup(mp.undo)
203178
_tmp_path_factory = TempPathFactory.from_config(config, _ispytest=True)
204-
_tmpdirhandler = TempdirFactory(_tmp_path_factory, _ispytest=True)
205179
mp.setattr(config, "_tmp_path_factory", _tmp_path_factory, raising=False)
206-
mp.setattr(config, "_tmpdirhandler", _tmpdirhandler, raising=False)
207-
208-
209-
@fixture(scope="session")
210-
def tmpdir_factory(request: FixtureRequest) -> TempdirFactory:
211-
"""Return a :class:`pytest.TempdirFactory` instance for the test session."""
212-
# Set dynamically by pytest_configure() above.
213-
return request.config._tmpdirhandler # type: ignore
214180

215181

216182
@fixture(scope="session")
@@ -228,24 +194,6 @@ def _mk_tmp(request: FixtureRequest, factory: TempPathFactory) -> Path:
228194
return factory.mktemp(name, numbered=True)
229195

230196

231-
@fixture
232-
def tmpdir(tmp_path: Path) -> LEGACY_PATH:
233-
"""Return a temporary directory path object which is unique to each test
234-
function invocation, created as a sub directory of the base temporary
235-
directory.
236-
237-
By default, a new base temporary directory is created each test session,
238-
and old bases are removed after 3 sessions, to aid in debugging. If
239-
``--basetemp`` is used then it is cleared each session. See :ref:`base
240-
temporary directory`.
241-
242-
The returned object is a `legacy_path`_ object.
243-
244-
.. _legacy_path: https://py.readthedocs.io/en/latest/path.html
245-
"""
246-
return legacy_path(tmp_path)
247-
248-
249197
@fixture
250198
def tmp_path(request: FixtureRequest, tmp_path_factory: TempPathFactory) -> Path:
251199
"""Return a temporary directory path object which is unique to each test

src/pytest/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@
6060
from _pytest.runner import CallInfo
6161
from _pytest.stash import Stash
6262
from _pytest.stash import StashKey
63-
from _pytest.tmpdir import TempdirFactory
6463
from _pytest.tmpdir import TempPathFactory
6564
from _pytest.warning_types import PytestAssertRewriteWarning
6665
from _pytest.warning_types import PytestCacheWarning
@@ -144,7 +143,6 @@
144143
"StashKey",
145144
"version_tuple",
146145
"TempPathFactory",
147-
"TempdirFactory",
148146
"UsageError",
149147
"WarningsRecorder",
150148
"warns",

testing/test_legacypath.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
from pathlib import Path
2+
13
import pytest
4+
from _pytest.compat import LEGACY_PATH
5+
from _pytest.legacypath import TempdirFactory
26
from _pytest.legacypath import Testdir
37

48

@@ -25,3 +29,41 @@ def test_testdir_makefile_ext_empty_string_makes_file(testdir: Testdir) -> None:
2529
"""For backwards compat #8192"""
2630
p1 = testdir.makefile("", "")
2731
assert "test_testdir_makefile" in str(p1)
32+
33+
34+
def attempt_symlink_to(path: str, to_path: str) -> None:
35+
"""Try to make a symlink from "path" to "to_path", skipping in case this platform
36+
does not support it or we don't have sufficient privileges (common on Windows)."""
37+
try:
38+
Path(path).symlink_to(Path(to_path))
39+
except OSError:
40+
pytest.skip("could not create symbolic link")
41+
42+
43+
def test_tmpdir_factory(
44+
tmpdir_factory: TempdirFactory,
45+
tmp_path_factory: pytest.TempPathFactory,
46+
) -> None:
47+
assert str(tmpdir_factory.getbasetemp()) == str(tmp_path_factory.getbasetemp())
48+
dir = tmpdir_factory.mktemp("foo")
49+
assert dir.exists()
50+
51+
52+
def test_tmpdir_equals_tmp_path(tmpdir: LEGACY_PATH, tmp_path: Path) -> None:
53+
assert Path(tmpdir) == tmp_path
54+
55+
56+
def test_tmpdir_always_is_realpath(pytester: pytest.Pytester) -> None:
57+
# See test_tmp_path_always_is_realpath.
58+
realtemp = pytester.mkdir("myrealtemp")
59+
linktemp = pytester.path.joinpath("symlinktemp")
60+
attempt_symlink_to(str(linktemp), str(realtemp))
61+
p = pytester.makepyfile(
62+
"""
63+
def test_1(tmpdir):
64+
import os
65+
assert os.path.realpath(str(tmpdir)) == str(tmpdir)
66+
"""
67+
)
68+
result = pytester.runpytest("-s", p, "--basetemp=%s/bt" % linktemp)
69+
assert not result.ret

testing/test_tmpdir.py

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,8 @@ def test_abs_path(tmp_path_factory):
118118
result.stdout.fnmatch_lines("*ValueError*")
119119

120120

121-
def test_tmpdir_always_is_realpath(pytester: Pytester) -> None:
122-
# the reason why tmpdir should be a realpath is that
121+
def test_tmp_path_always_is_realpath(pytester: Pytester, monkeypatch) -> None:
122+
# the reason why tmp_path should be a realpath is that
123123
# when you cd to it and do "os.getcwd()" you will anyway
124124
# get the realpath. Using the symlinked path can thus
125125
# easily result in path-inequality
@@ -128,22 +128,6 @@ def test_tmpdir_always_is_realpath(pytester: Pytester) -> None:
128128
realtemp = pytester.mkdir("myrealtemp")
129129
linktemp = pytester.path.joinpath("symlinktemp")
130130
attempt_symlink_to(linktemp, str(realtemp))
131-
p = pytester.makepyfile(
132-
"""
133-
def test_1(tmpdir):
134-
import os
135-
assert os.path.realpath(str(tmpdir)) == str(tmpdir)
136-
"""
137-
)
138-
result = pytester.runpytest("-s", p, "--basetemp=%s/bt" % linktemp)
139-
assert not result.ret
140-
141-
142-
def test_tmp_path_always_is_realpath(pytester: Pytester, monkeypatch) -> None:
143-
# for reasoning see: test_tmpdir_always_is_realpath test-case
144-
realtemp = pytester.mkdir("myrealtemp")
145-
linktemp = pytester.path.joinpath("symlinktemp")
146-
attempt_symlink_to(linktemp, str(realtemp))
147131
monkeypatch.setenv("PYTEST_DEBUG_TEMPROOT", str(linktemp))
148132
pytester.makepyfile(
149133
"""
@@ -423,10 +407,6 @@ def attempt_symlink_to(path, to_path):
423407
pytest.skip("could not create symbolic link")
424408

425409

426-
def test_tmpdir_equals_tmp_path(tmpdir, tmp_path):
427-
assert Path(tmpdir) == tmp_path
428-
429-
430410
def test_basetemp_with_read_only_files(pytester: Pytester) -> None:
431411
"""Integration test for #5524"""
432412
pytester.makepyfile(

0 commit comments

Comments
 (0)