Skip to content

Commit 1b0e0be

Browse files
committed
Migrate tests to use pathlib.Path
The pip-specific Path implementation has been removed, and all its usages replaced by pathlib.Path. The tmpdir and tmpdir_factory fixtures are also removed, and all usages are replaced by tmp_path and tmp_path_factory, which use pathlib.Path. The pip() function now also accepts pathlib.Path so we don't need to put str() everywhere. Path arguments are coerced with os.fspath() into str.
1 parent e58a8a5 commit 1b0e0be

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+1416
-1480
lines changed

tests/conftest.py

+80-65
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,25 @@
22
import fnmatch
33
import io
44
import os
5+
import pathlib
56
import re
67
import shutil
78
import subprocess
89
import sys
910
import time
1011
from contextlib import ExitStack, contextmanager
11-
from typing import TYPE_CHECKING, Callable, Dict, Iterable, Iterator, List, Optional
12+
from typing import (
13+
TYPE_CHECKING,
14+
Callable,
15+
Dict,
16+
Iterable,
17+
Iterator,
18+
List,
19+
Optional,
20+
Union,
21+
)
1222
from unittest.mock import patch
1323

14-
import py.path
1524
import pytest
1625

1726
# Config will be available from the public API in pytest >= 7.0.0:
@@ -27,7 +36,6 @@
2736
from pip._internal.locations import _USE_SYSCONFIG
2837
from pip._internal.utils.temp_dir import global_tempdir_manager
2938
from tests.lib import DATA_DIR, SRC_DIR, PipTestEnvironment, TestData
30-
from tests.lib.path import Path
3139
from tests.lib.server import MockServer as _MockServer
3240
from tests.lib.server import make_mock_server, server_running
3341
from tests.lib.venv import VirtualEnvironment, VirtualEnvironmentType
@@ -37,7 +45,7 @@
3745
if TYPE_CHECKING:
3846
from typing import Protocol
3947

40-
from wsgi import WSGIApplication
48+
from _typeshed.wsgi import WSGIApplication
4149
else:
4250
# TODO: Protocol was introduced in Python 3.8. Remove this branch when
4351
# dropping support for Python 3.7.
@@ -146,42 +154,44 @@ def resolver_variant(request: pytest.FixtureRequest) -> Iterator[str]:
146154

147155

148156
@pytest.fixture(scope="session")
149-
def tmpdir_factory(
150-
request: pytest.FixtureRequest, tmpdir_factory: pytest.TempdirFactory
151-
) -> Iterator[pytest.TempdirFactory]:
157+
def tmp_path_factory(
158+
request: pytest.FixtureRequest, tmp_path_factory: pytest.TempPathFactory
159+
) -> Iterator[pytest.TempPathFactory]:
152160
"""Modified `tmpdir_factory` session fixture
153161
that will automatically cleanup after itself.
154162
"""
155-
yield tmpdir_factory
163+
yield tmp_path_factory
156164
if not request.config.getoption("--keep-tmpdir"):
157165
shutil.rmtree(
158-
tmpdir_factory.getbasetemp(),
166+
tmp_path_factory.getbasetemp(),
159167
ignore_errors=True,
160168
)
161169

162170

163171
@pytest.fixture
164-
def tmpdir(request: pytest.FixtureRequest, tmpdir: py.path.local) -> Iterator[Path]:
172+
def tmp_path(
173+
request: pytest.FixtureRequest,
174+
tmp_path: pathlib.Path,
175+
) -> Iterator[pathlib.Path]:
165176
"""
166177
Return a temporary directory path object which is unique to each test
167178
function invocation, created as a sub directory of the base temporary
168-
directory. The returned object is a ``tests.lib.path.Path`` object.
179+
directory. The returned object is a ``pathlib.Path`` object.
169180
170-
This uses the built-in tmpdir fixture from pytest itself but modified
171-
to return our typical path object instead of py.path.local as well as
172-
deleting the temporary directories at the end of each test case.
181+
This uses the built-in tmp_path fixture from pytest itself, but deletes the
182+
temporary directories at the end of each test case.
173183
"""
174-
assert tmpdir.isdir()
175-
yield Path(str(tmpdir))
184+
assert tmp_path.is_dir()
185+
yield tmp_path
176186
# Clear out the temporary directory after the test has finished using it.
177187
# This should prevent us from needing a multiple gigabyte temporary
178188
# directory while running the tests.
179189
if not request.config.getoption("--keep-tmpdir"):
180-
tmpdir.remove(ignore_errors=True)
190+
shutil.rmtree(tmp_path, ignore_errors=True)
181191

182192

183193
@pytest.fixture(autouse=True)
184-
def isolate(tmpdir: Path, monkeypatch: pytest.MonkeyPatch) -> None:
194+
def isolate(tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch) -> None:
185195
"""
186196
Isolate our tests so that things like global configuration files and the
187197
like do not affect our test results.
@@ -194,11 +204,11 @@ def isolate(tmpdir: Path, monkeypatch: pytest.MonkeyPatch) -> None:
194204
# as well as user level configuration files.
195205

196206
# Create a directory to use as our home location.
197-
home_dir = os.path.join(str(tmpdir), "home")
207+
home_dir = os.path.join(tmp_path, "home")
198208
os.makedirs(home_dir)
199209

200210
# Create a directory to use as a fake root
201-
fake_root = os.path.join(str(tmpdir), "fake-root")
211+
fake_root = os.path.join(tmp_path, "fake-root")
202212
os.makedirs(fake_root)
203213

204214
if sys.platform == "win32":
@@ -296,7 +306,7 @@ def scoped_global_tempdir_manager(request: pytest.FixtureRequest) -> Iterator[No
296306

297307

298308
@pytest.fixture(scope="session")
299-
def pip_src(tmpdir_factory: pytest.TempdirFactory) -> Path:
309+
def pip_src(tmp_path_factory: pytest.TempPathFactory) -> pathlib.Path:
300310
def not_code_files_and_folders(path: str, names: List[str]) -> Iterable[str]:
301311
# In the root directory...
302312
if path == SRC_DIR:
@@ -317,7 +327,7 @@ def not_code_files_and_folders(path: str, names: List[str]) -> Iterable[str]:
317327
ignored.update(fnmatch.filter(names, pattern))
318328
return ignored
319329

320-
pip_src = Path(str(tmpdir_factory.mktemp("pip_src"))).joinpath("pip_src")
330+
pip_src = tmp_path_factory.mktemp("pip_src").joinpath("pip_src")
321331
# Copy over our source tree so that each use is self contained
322332
shutil.copytree(
323333
SRC_DIR,
@@ -328,11 +338,11 @@ def not_code_files_and_folders(path: str, names: List[str]) -> Iterable[str]:
328338

329339

330340
def _common_wheel_editable_install(
331-
tmpdir_factory: pytest.TempdirFactory, common_wheels: Path, package: str
332-
) -> Path:
341+
tmp_path_factory: pytest.TempPathFactory, common_wheels: pathlib.Path, package: str
342+
) -> pathlib.Path:
333343
wheel_candidates = list(common_wheels.glob(f"{package}-*.whl"))
334344
assert len(wheel_candidates) == 1, wheel_candidates
335-
install_dir = Path(str(tmpdir_factory.mktemp(package))) / "install"
345+
install_dir = tmp_path_factory.mktemp(package) / "install"
336346
Wheel(wheel_candidates[0]).install_as_egg(install_dir)
337347
(install_dir / "EGG-INFO").rename(install_dir / f"{package}.egg-info")
338348
assert compileall.compile_dir(str(install_dir), quiet=1)
@@ -341,25 +351,28 @@ def _common_wheel_editable_install(
341351

342352
@pytest.fixture(scope="session")
343353
def setuptools_install(
344-
tmpdir_factory: pytest.TempdirFactory, common_wheels: Path
345-
) -> Path:
346-
return _common_wheel_editable_install(tmpdir_factory, common_wheels, "setuptools")
354+
tmp_path_factory: pytest.TempPathFactory, common_wheels: pathlib.Path
355+
) -> pathlib.Path:
356+
return _common_wheel_editable_install(tmp_path_factory, common_wheels, "setuptools")
347357

348358

349359
@pytest.fixture(scope="session")
350-
def wheel_install(tmpdir_factory: pytest.TempdirFactory, common_wheels: Path) -> Path:
351-
return _common_wheel_editable_install(tmpdir_factory, common_wheels, "wheel")
360+
def wheel_install(
361+
tmp_path_factory: pytest.TempPathFactory,
362+
common_wheels: pathlib.Path,
363+
) -> pathlib.Path:
364+
return _common_wheel_editable_install(tmp_path_factory, common_wheels, "wheel")
352365

353366

354367
@pytest.fixture(scope="session")
355368
def coverage_install(
356-
tmpdir_factory: pytest.TempdirFactory, common_wheels: Path
357-
) -> Path:
358-
return _common_wheel_editable_install(tmpdir_factory, common_wheels, "coverage")
369+
tmp_path_factory: pytest.TempPathFactory, common_wheels: pathlib.Path
370+
) -> pathlib.Path:
371+
return _common_wheel_editable_install(tmp_path_factory, common_wheels, "coverage")
359372

360373

361374
def install_egg_link(
362-
venv: VirtualEnvironment, project_name: str, egg_info_dir: Path
375+
venv: VirtualEnvironment, project_name: str, egg_info_dir: pathlib.Path
363376
) -> None:
364377
with open(venv.site / "easy-install.pth", "a") as fp:
365378
fp.write(str(egg_info_dir.resolve()) + "\n")
@@ -370,10 +383,10 @@ def install_egg_link(
370383
@pytest.fixture(scope="session")
371384
def virtualenv_template(
372385
request: pytest.FixtureRequest,
373-
tmpdir_factory: pytest.TempdirFactory,
374-
pip_src: Path,
375-
setuptools_install: Path,
376-
coverage_install: Path,
386+
tmp_path_factory: pytest.TempPathFactory,
387+
pip_src: pathlib.Path,
388+
setuptools_install: pathlib.Path,
389+
coverage_install: pathlib.Path,
377390
) -> Iterator[VirtualEnvironment]:
378391

379392
venv_type: VirtualEnvironmentType
@@ -383,12 +396,12 @@ def virtualenv_template(
383396
venv_type = "virtualenv"
384397

385398
# Create the virtual environment
386-
tmpdir = Path(str(tmpdir_factory.mktemp("virtualenv")))
387-
venv = VirtualEnvironment(tmpdir.joinpath("venv_orig"), venv_type=venv_type)
399+
tmp_path = tmp_path_factory.mktemp("virtualenv")
400+
venv = VirtualEnvironment(tmp_path.joinpath("venv_orig"), venv_type=venv_type)
388401

389402
# Install setuptools and pip.
390403
install_egg_link(venv, "setuptools", setuptools_install)
391-
pip_editable = Path(str(tmpdir_factory.mktemp("pip"))) / "pip"
404+
pip_editable = tmp_path_factory.mktemp("pip") / "pip"
392405
shutil.copytree(pip_src, pip_editable, symlinks=True)
393406
# noxfile.py is Python 3 only
394407
assert compileall.compile_dir(
@@ -420,58 +433,60 @@ def virtualenv_template(
420433

421434
# Rename original virtualenv directory to make sure
422435
# it's not reused by mistake from one of the copies.
423-
venv_template = tmpdir / "venv_template"
436+
venv_template = tmp_path / "venv_template"
424437
venv.move(venv_template)
425438
yield venv
426439

427440

428441
@pytest.fixture(scope="session")
429442
def virtualenv_factory(
430443
virtualenv_template: VirtualEnvironment,
431-
) -> Callable[[Path], VirtualEnvironment]:
432-
def factory(tmpdir: Path) -> VirtualEnvironment:
433-
return VirtualEnvironment(tmpdir, virtualenv_template)
444+
) -> Callable[[pathlib.Path], VirtualEnvironment]:
445+
def factory(tmp_path: pathlib.Path) -> VirtualEnvironment:
446+
return VirtualEnvironment(tmp_path, virtualenv_template)
434447

435448
return factory
436449

437450

438451
@pytest.fixture
439452
def virtualenv(
440-
virtualenv_factory: Callable[[Path], VirtualEnvironment], tmpdir: Path
453+
virtualenv_factory: Callable[[pathlib.Path], VirtualEnvironment],
454+
tmp_path: pathlib.Path,
441455
) -> Iterator[VirtualEnvironment]:
442456
"""
443457
Return a virtual environment which is unique to each test function
444458
invocation created inside of a sub directory of the test function's
445459
temporary directory. The returned object is a
446460
``tests.lib.venv.VirtualEnvironment`` object.
447461
"""
448-
yield virtualenv_factory(tmpdir.joinpath("workspace", "venv"))
462+
yield virtualenv_factory(tmp_path.joinpath("workspace", "venv"))
449463

450464

451465
@pytest.fixture
452-
def with_wheel(virtualenv: VirtualEnvironment, wheel_install: Path) -> None:
466+
def with_wheel(virtualenv: VirtualEnvironment, wheel_install: pathlib.Path) -> None:
453467
install_egg_link(virtualenv, "wheel", wheel_install)
454468

455469

456470
class ScriptFactory(Protocol):
457471
def __call__(
458-
self, tmpdir: Path, virtualenv: Optional[VirtualEnvironment] = None
472+
self, tmp_path: pathlib.Path, virtualenv: Optional[VirtualEnvironment] = None
459473
) -> PipTestEnvironment:
460474
...
461475

462476

463477
@pytest.fixture(scope="session")
464478
def script_factory(
465-
virtualenv_factory: Callable[[Path], VirtualEnvironment], deprecated_python: bool
479+
virtualenv_factory: Callable[[pathlib.Path], VirtualEnvironment],
480+
deprecated_python: bool,
466481
) -> ScriptFactory:
467482
def factory(
468-
tmpdir: Path, virtualenv: Optional[VirtualEnvironment] = None
483+
tmp_path: pathlib.Path, virtualenv: Optional[VirtualEnvironment] = None
469484
) -> PipTestEnvironment:
470485
if virtualenv is None:
471-
virtualenv = virtualenv_factory(tmpdir.joinpath("venv"))
486+
virtualenv = virtualenv_factory(tmp_path.joinpath("venv"))
472487
return PipTestEnvironment(
473488
# The base location for our test environment
474-
tmpdir,
489+
tmp_path,
475490
# Tell the Test Environment where our virtualenv is located
476491
virtualenv=virtualenv,
477492
# Do not ignore hidden files, they need to be checked as well
@@ -491,33 +506,33 @@ def factory(
491506

492507
@pytest.fixture
493508
def script(
494-
tmpdir: Path,
509+
tmp_path: pathlib.Path,
495510
virtualenv: VirtualEnvironment,
496-
script_factory: Callable[[Path, Optional[VirtualEnvironment]], PipTestEnvironment],
511+
script_factory: ScriptFactory,
497512
) -> PipTestEnvironment:
498513
"""
499514
Return a PipTestEnvironment which is unique to each test function and
500515
will execute all commands inside of the unique virtual environment for this
501516
test function. The returned object is a
502517
``tests.lib.PipTestEnvironment``.
503518
"""
504-
return script_factory(tmpdir.joinpath("workspace"), virtualenv)
519+
return script_factory(tmp_path.joinpath("workspace"), virtualenv)
505520

506521

507522
@pytest.fixture(scope="session")
508-
def common_wheels() -> Path:
523+
def common_wheels() -> pathlib.Path:
509524
"""Provide a directory with latest setuptools and wheel wheels"""
510525
return DATA_DIR.joinpath("common_wheels")
511526

512527

513528
@pytest.fixture(scope="session")
514-
def shared_data(tmpdir_factory: pytest.TempdirFactory) -> TestData:
515-
return TestData.copy(Path(str(tmpdir_factory.mktemp("data"))))
529+
def shared_data(tmp_path_factory: pytest.TempPathFactory) -> TestData:
530+
return TestData.copy(tmp_path_factory.mktemp("data"))
516531

517532

518533
@pytest.fixture
519-
def data(tmpdir: Path) -> TestData:
520-
return TestData.copy(tmpdir.joinpath("data"))
534+
def data(tmp_path: pathlib.Path) -> TestData:
535+
return TestData.copy(tmp_path.joinpath("data"))
521536

522537

523538
class InMemoryPipResult:
@@ -527,12 +542,12 @@ def __init__(self, returncode: int, stdout: str) -> None:
527542

528543

529544
class InMemoryPip:
530-
def pip(self, *args: str) -> InMemoryPipResult:
545+
def pip(self, *args: Union[str, pathlib.Path]) -> InMemoryPipResult:
531546
orig_stdout = sys.stdout
532547
stdout = io.StringIO()
533548
sys.stdout = stdout
534549
try:
535-
returncode = pip_entry_point(list(args))
550+
returncode = pip_entry_point([os.fspath(a) for a in args])
536551
except SystemExit as e:
537552
returncode = e.code or 0
538553
finally:
@@ -555,15 +570,15 @@ def deprecated_python() -> bool:
555570

556571

557572
@pytest.fixture(scope="session")
558-
def cert_factory(tmpdir_factory: pytest.TempdirFactory) -> CertFactory:
573+
def cert_factory(tmp_path_factory: pytest.TempPathFactory) -> CertFactory:
559574
# Delay the import requiring cryptography in order to make it possible
560575
# to deselect relevant tests on systems where cryptography cannot
561576
# be installed.
562577
from tests.lib.certs import make_tls_cert, serialize_cert, serialize_key
563578

564579
def factory() -> str:
565580
"""Returns path to cert/key file."""
566-
output_path = Path(str(tmpdir_factory.mktemp("certs"))) / "cert.pem"
581+
output_path = tmp_path_factory.mktemp("certs") / "cert.pem"
567582
# Must be Text on PY2.
568583
cert, key = make_tls_cert("localhost")
569584
with open(str(output_path), "wb") as f:

tests/functional/test_broken_stdout.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import os
2+
import pathlib
23
import subprocess
34
from typing import List, Tuple
45

5-
from tests.lib.path import Path
6-
76
_BROKEN_STDOUT_RETURN_CODE = 120
87

98

@@ -47,11 +46,14 @@ def test_broken_stdout_pipe(deprecated_python: bool) -> None:
4746
assert returncode == _BROKEN_STDOUT_RETURN_CODE
4847

4948

50-
def test_broken_stdout_pipe__log_option(deprecated_python: bool, tmpdir: Path) -> None:
49+
def test_broken_stdout_pipe__log_option(
50+
deprecated_python: bool,
51+
tmp_path: pathlib.Path,
52+
) -> None:
5153
"""
5254
Test a broken pipe to stdout when --log is passed.
5355
"""
54-
log_path = os.path.join(str(tmpdir), "log.txt")
56+
log_path = os.path.join(tmp_path, "log.txt")
5557
stderr, returncode = setup_broken_stdout_test(
5658
["pip", "--log", log_path, "list"],
5759
deprecated_python=deprecated_python,

0 commit comments

Comments
 (0)