From eaa250367a9350ab316615f2b00ca5d9374e741e Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Tue, 7 Jun 2022 17:52:38 +0800 Subject: [PATCH] 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. --- tests/conftest.py | 145 +++++++------ tests/functional/test_broken_stdout.py | 10 +- tests/functional/test_build_env.py | 7 +- tests/functional/test_completion.py | 20 +- tests/functional/test_config_settings.py | 4 +- tests/functional/test_download.py | 127 ++++++------ tests/functional/test_fast_deps.py | 3 +- tests/functional/test_freeze.py | 71 ++++--- tests/functional/test_hash.py | 23 ++- tests/functional/test_install.py | 168 ++++++++-------- tests/functional/test_install_cleanup.py | 12 +- tests/functional/test_install_config.py | 26 +-- tests/functional/test_install_direct_url.py | 18 +- tests/functional/test_install_extras.py | 8 +- tests/functional/test_install_index.py | 9 +- tests/functional/test_install_reqs.py | 84 ++++---- tests/functional/test_install_upgrade.py | 15 +- tests/functional/test_install_user.py | 13 +- tests/functional/test_install_vcs_git.py | 76 +++---- tests/functional/test_install_wheel.py | 157 ++++++++------- tests/functional/test_list.py | 56 +++--- tests/functional/test_new_resolver.py | 107 +++++----- tests/functional/test_new_resolver_errors.py | 17 +- tests/functional/test_new_resolver_hashes.py | 21 +- tests/functional/test_new_resolver_target.py | 10 +- tests/functional/test_new_resolver_user.py | 6 +- tests/functional/test_pep517.py | 130 +++++++----- tests/functional/test_pep660.py | 60 +++--- tests/functional/test_show.py | 2 +- tests/functional/test_uninstall.py | 42 ++-- tests/functional/test_vcs_bazaar.py | 13 +- tests/functional/test_vcs_git.py | 56 +++--- tests/functional/test_vcs_mercurial.py | 4 +- tests/functional/test_vcs_subversion.py | 14 +- tests/functional/test_warning.py | 14 +- tests/functional/test_wheel.py | 42 ++-- tests/lib/__init__.py | 178 ++++++++-------- tests/lib/direct_url.py | 7 +- tests/lib/git_submodule_helpers.py | 18 +- tests/lib/local_repos.py | 26 ++- tests/lib/path.py | 190 ------------------ tests/lib/server.py | 44 ++-- tests/lib/test_wheel.py | 8 +- tests/lib/venv.py | 21 +- tests/lib/wheel.py | 10 +- .../resolution_resolvelib/test_requirement.py | 11 +- tests/unit/test_base_command.py | 30 +-- tests/unit/test_cache.py | 10 +- tests/unit/test_collector.py | 23 +-- tests/unit/test_compat.py | 14 +- tests/unit/test_direct_url_helpers.py | 11 +- tests/unit/test_locations.py | 10 +- tests/unit/test_network_cache.py | 32 +-- tests/unit/test_network_session.py | 22 +- tests/unit/test_operations_prepare.py | 61 +++--- tests/unit/test_options.py | 3 +- tests/unit/test_pep517.py | 14 +- tests/unit/test_req.py | 41 ++-- tests/unit/test_req_file.py | 122 ++++++----- tests/unit/test_req_install.py | 15 +- tests/unit/test_req_uninstall.py | 97 ++++----- tests/unit/test_resolution_legacy_resolver.py | 2 +- tests/unit/test_self_check_outdated.py | 22 +- tests/unit/test_utils.py | 34 ++-- tests/unit/test_utils_filesystem.py | 14 +- tests/unit/test_utils_temp_dir.py | 16 +- tests/unit/test_utils_unpacking.py | 14 +- tests/unit/test_utils_virtualenv.py | 14 +- tests/unit/test_utils_wheel.py | 51 +++-- tests/unit/test_vcs.py | 5 +- tests/unit/test_vcs_mercurial.py | 17 +- tests/unit/test_wheel.py | 96 +++++---- tests/unit/test_wheel_builder.py | 4 +- tools/protected_pip.py | 7 +- 74 files changed, 1423 insertions(+), 1481 deletions(-) delete mode 100644 tests/lib/path.py diff --git a/tests/conftest.py b/tests/conftest.py index c137f844129..6991084e6b5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,16 +2,25 @@ import fnmatch import io import os +import pathlib import re import shutil import subprocess import sys import time from contextlib import ExitStack, contextmanager -from typing import TYPE_CHECKING, Callable, Dict, Iterable, Iterator, List, Optional +from typing import ( + TYPE_CHECKING, + Callable, + Dict, + Iterable, + Iterator, + List, + Optional, + Union, +) from unittest.mock import patch -import py.path import pytest # Config will be available from the public API in pytest >= 7.0.0: @@ -27,7 +36,6 @@ from pip._internal.locations import _USE_SYSCONFIG from pip._internal.utils.temp_dir import global_tempdir_manager from tests.lib import DATA_DIR, SRC_DIR, PipTestEnvironment, TestData -from tests.lib.path import Path from tests.lib.server import MockServer as _MockServer from tests.lib.server import make_mock_server, server_running from tests.lib.venv import VirtualEnvironment, VirtualEnvironmentType @@ -37,7 +45,7 @@ if TYPE_CHECKING: from typing import Protocol - from wsgi import WSGIApplication + from _typeshed.wsgi import WSGIApplication else: # TODO: Protocol was introduced in Python 3.8. Remove this branch when # dropping support for Python 3.7. @@ -146,42 +154,44 @@ def resolver_variant(request: pytest.FixtureRequest) -> Iterator[str]: @pytest.fixture(scope="session") -def tmpdir_factory( - request: pytest.FixtureRequest, tmpdir_factory: pytest.TempdirFactory -) -> Iterator[pytest.TempdirFactory]: +def tmp_path_factory( + request: pytest.FixtureRequest, tmp_path_factory: pytest.TempPathFactory +) -> Iterator[pytest.TempPathFactory]: """Modified `tmpdir_factory` session fixture that will automatically cleanup after itself. """ - yield tmpdir_factory + yield tmp_path_factory if not request.config.getoption("--keep-tmpdir"): shutil.rmtree( - tmpdir_factory.getbasetemp(), + tmp_path_factory.getbasetemp(), ignore_errors=True, ) @pytest.fixture -def tmpdir(request: pytest.FixtureRequest, tmpdir: py.path.local) -> Iterator[Path]: +def tmp_path( + request: pytest.FixtureRequest, + tmp_path: pathlib.Path, +) -> Iterator[pathlib.Path]: """ Return a temporary directory path object which is unique to each test function invocation, created as a sub directory of the base temporary - directory. The returned object is a ``tests.lib.path.Path`` object. + directory. The returned object is a ``pathlib.Path`` object. - This uses the built-in tmpdir fixture from pytest itself but modified - to return our typical path object instead of py.path.local as well as - deleting the temporary directories at the end of each test case. + This uses the built-in tmp_path fixture from pytest itself, but deletes the + temporary directories at the end of each test case. """ - assert tmpdir.isdir() - yield Path(str(tmpdir)) + assert tmp_path.is_dir() + yield tmp_path # Clear out the temporary directory after the test has finished using it. # This should prevent us from needing a multiple gigabyte temporary # directory while running the tests. if not request.config.getoption("--keep-tmpdir"): - tmpdir.remove(ignore_errors=True) + shutil.rmtree(tmp_path, ignore_errors=True) @pytest.fixture(autouse=True) -def isolate(tmpdir: Path, monkeypatch: pytest.MonkeyPatch) -> None: +def isolate(tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch) -> None: """ Isolate our tests so that things like global configuration files and the like do not affect our test results. @@ -194,11 +204,11 @@ def isolate(tmpdir: Path, monkeypatch: pytest.MonkeyPatch) -> None: # as well as user level configuration files. # Create a directory to use as our home location. - home_dir = os.path.join(str(tmpdir), "home") + home_dir = os.path.join(tmp_path, "home") os.makedirs(home_dir) # Create a directory to use as a fake root - fake_root = os.path.join(str(tmpdir), "fake-root") + fake_root = os.path.join(tmp_path, "fake-root") os.makedirs(fake_root) if sys.platform == "win32": @@ -296,7 +306,7 @@ def scoped_global_tempdir_manager(request: pytest.FixtureRequest) -> Iterator[No @pytest.fixture(scope="session") -def pip_src(tmpdir_factory: pytest.TempdirFactory) -> Path: +def pip_src(tmp_path_factory: pytest.TempPathFactory) -> pathlib.Path: def not_code_files_and_folders(path: str, names: List[str]) -> Iterable[str]: # In the root directory... if path == SRC_DIR: @@ -317,7 +327,7 @@ def not_code_files_and_folders(path: str, names: List[str]) -> Iterable[str]: ignored.update(fnmatch.filter(names, pattern)) return ignored - pip_src = Path(str(tmpdir_factory.mktemp("pip_src"))).joinpath("pip_src") + pip_src = tmp_path_factory.mktemp("pip_src").joinpath("pip_src") # Copy over our source tree so that each use is self contained shutil.copytree( SRC_DIR, @@ -328,11 +338,11 @@ def not_code_files_and_folders(path: str, names: List[str]) -> Iterable[str]: def _common_wheel_editable_install( - tmpdir_factory: pytest.TempdirFactory, common_wheels: Path, package: str -) -> Path: + tmp_path_factory: pytest.TempPathFactory, common_wheels: pathlib.Path, package: str +) -> pathlib.Path: wheel_candidates = list(common_wheels.glob(f"{package}-*.whl")) assert len(wheel_candidates) == 1, wheel_candidates - install_dir = Path(str(tmpdir_factory.mktemp(package))) / "install" + install_dir = tmp_path_factory.mktemp(package) / "install" Wheel(wheel_candidates[0]).install_as_egg(install_dir) (install_dir / "EGG-INFO").rename(install_dir / f"{package}.egg-info") assert compileall.compile_dir(str(install_dir), quiet=1) @@ -341,25 +351,28 @@ def _common_wheel_editable_install( @pytest.fixture(scope="session") def setuptools_install( - tmpdir_factory: pytest.TempdirFactory, common_wheels: Path -) -> Path: - return _common_wheel_editable_install(tmpdir_factory, common_wheels, "setuptools") + tmp_path_factory: pytest.TempPathFactory, common_wheels: pathlib.Path +) -> pathlib.Path: + return _common_wheel_editable_install(tmp_path_factory, common_wheels, "setuptools") @pytest.fixture(scope="session") -def wheel_install(tmpdir_factory: pytest.TempdirFactory, common_wheels: Path) -> Path: - return _common_wheel_editable_install(tmpdir_factory, common_wheels, "wheel") +def wheel_install( + tmp_path_factory: pytest.TempPathFactory, + common_wheels: pathlib.Path, +) -> pathlib.Path: + return _common_wheel_editable_install(tmp_path_factory, common_wheels, "wheel") @pytest.fixture(scope="session") def coverage_install( - tmpdir_factory: pytest.TempdirFactory, common_wheels: Path -) -> Path: - return _common_wheel_editable_install(tmpdir_factory, common_wheels, "coverage") + tmp_path_factory: pytest.TempPathFactory, common_wheels: pathlib.Path +) -> pathlib.Path: + return _common_wheel_editable_install(tmp_path_factory, common_wheels, "coverage") def install_egg_link( - venv: VirtualEnvironment, project_name: str, egg_info_dir: Path + venv: VirtualEnvironment, project_name: str, egg_info_dir: pathlib.Path ) -> None: with open(venv.site / "easy-install.pth", "a") as fp: fp.write(str(egg_info_dir.resolve()) + "\n") @@ -370,10 +383,10 @@ def install_egg_link( @pytest.fixture(scope="session") def virtualenv_template( request: pytest.FixtureRequest, - tmpdir_factory: pytest.TempdirFactory, - pip_src: Path, - setuptools_install: Path, - coverage_install: Path, + tmp_path_factory: pytest.TempPathFactory, + pip_src: pathlib.Path, + setuptools_install: pathlib.Path, + coverage_install: pathlib.Path, ) -> Iterator[VirtualEnvironment]: venv_type: VirtualEnvironmentType @@ -383,12 +396,12 @@ def virtualenv_template( venv_type = "virtualenv" # Create the virtual environment - tmpdir = Path(str(tmpdir_factory.mktemp("virtualenv"))) - venv = VirtualEnvironment(tmpdir.joinpath("venv_orig"), venv_type=venv_type) + tmp_path = tmp_path_factory.mktemp("virtualenv") + venv = VirtualEnvironment(tmp_path.joinpath("venv_orig"), venv_type=venv_type) # Install setuptools and pip. install_egg_link(venv, "setuptools", setuptools_install) - pip_editable = Path(str(tmpdir_factory.mktemp("pip"))) / "pip" + pip_editable = tmp_path_factory.mktemp("pip") / "pip" shutil.copytree(pip_src, pip_editable, symlinks=True) # noxfile.py is Python 3 only assert compileall.compile_dir( @@ -420,7 +433,7 @@ def virtualenv_template( # Rename original virtualenv directory to make sure # it's not reused by mistake from one of the copies. - venv_template = tmpdir / "venv_template" + venv_template = tmp_path / "venv_template" venv.move(venv_template) yield venv @@ -428,16 +441,17 @@ def virtualenv_template( @pytest.fixture(scope="session") def virtualenv_factory( virtualenv_template: VirtualEnvironment, -) -> Callable[[Path], VirtualEnvironment]: - def factory(tmpdir: Path) -> VirtualEnvironment: - return VirtualEnvironment(tmpdir, virtualenv_template) +) -> Callable[[pathlib.Path], VirtualEnvironment]: + def factory(tmp_path: pathlib.Path) -> VirtualEnvironment: + return VirtualEnvironment(tmp_path, virtualenv_template) return factory @pytest.fixture def virtualenv( - virtualenv_factory: Callable[[Path], VirtualEnvironment], tmpdir: Path + virtualenv_factory: Callable[[pathlib.Path], VirtualEnvironment], + tmp_path: pathlib.Path, ) -> Iterator[VirtualEnvironment]: """ Return a virtual environment which is unique to each test function @@ -445,33 +459,34 @@ def virtualenv( temporary directory. The returned object is a ``tests.lib.venv.VirtualEnvironment`` object. """ - yield virtualenv_factory(tmpdir.joinpath("workspace", "venv")) + yield virtualenv_factory(tmp_path.joinpath("workspace", "venv")) @pytest.fixture -def with_wheel(virtualenv: VirtualEnvironment, wheel_install: Path) -> None: +def with_wheel(virtualenv: VirtualEnvironment, wheel_install: pathlib.Path) -> None: install_egg_link(virtualenv, "wheel", wheel_install) class ScriptFactory(Protocol): def __call__( - self, tmpdir: Path, virtualenv: Optional[VirtualEnvironment] = None + self, tmp_path: pathlib.Path, virtualenv: Optional[VirtualEnvironment] = None ) -> PipTestEnvironment: ... @pytest.fixture(scope="session") def script_factory( - virtualenv_factory: Callable[[Path], VirtualEnvironment], deprecated_python: bool + virtualenv_factory: Callable[[pathlib.Path], VirtualEnvironment], + deprecated_python: bool, ) -> ScriptFactory: def factory( - tmpdir: Path, virtualenv: Optional[VirtualEnvironment] = None + tmp_path: pathlib.Path, virtualenv: Optional[VirtualEnvironment] = None ) -> PipTestEnvironment: if virtualenv is None: - virtualenv = virtualenv_factory(tmpdir.joinpath("venv")) + virtualenv = virtualenv_factory(tmp_path.joinpath("venv")) return PipTestEnvironment( # The base location for our test environment - tmpdir, + tmp_path, # Tell the Test Environment where our virtualenv is located virtualenv=virtualenv, # Do not ignore hidden files, they need to be checked as well @@ -491,9 +506,9 @@ def factory( @pytest.fixture def script( - tmpdir: Path, + tmp_path: pathlib.Path, virtualenv: VirtualEnvironment, - script_factory: Callable[[Path, Optional[VirtualEnvironment]], PipTestEnvironment], + script_factory: ScriptFactory, ) -> PipTestEnvironment: """ Return a PipTestEnvironment which is unique to each test function and @@ -501,23 +516,23 @@ def script( test function. The returned object is a ``tests.lib.PipTestEnvironment``. """ - return script_factory(tmpdir.joinpath("workspace"), virtualenv) + return script_factory(tmp_path.joinpath("workspace"), virtualenv) @pytest.fixture(scope="session") -def common_wheels() -> Path: +def common_wheels() -> pathlib.Path: """Provide a directory with latest setuptools and wheel wheels""" return DATA_DIR.joinpath("common_wheels") @pytest.fixture(scope="session") -def shared_data(tmpdir_factory: pytest.TempdirFactory) -> TestData: - return TestData.copy(Path(str(tmpdir_factory.mktemp("data")))) +def shared_data(tmp_path_factory: pytest.TempPathFactory) -> TestData: + return TestData.copy(tmp_path_factory.mktemp("data")) @pytest.fixture -def data(tmpdir: Path) -> TestData: - return TestData.copy(tmpdir.joinpath("data")) +def data(tmp_path: pathlib.Path) -> TestData: + return TestData.copy(tmp_path.joinpath("data")) class InMemoryPipResult: @@ -527,12 +542,12 @@ def __init__(self, returncode: int, stdout: str) -> None: class InMemoryPip: - def pip(self, *args: str) -> InMemoryPipResult: + def pip(self, *args: Union[str, pathlib.Path]) -> InMemoryPipResult: orig_stdout = sys.stdout stdout = io.StringIO() sys.stdout = stdout try: - returncode = pip_entry_point(list(args)) + returncode = pip_entry_point([os.fspath(a) for a in args]) except SystemExit as e: returncode = e.code or 0 finally: @@ -555,7 +570,7 @@ def deprecated_python() -> bool: @pytest.fixture(scope="session") -def cert_factory(tmpdir_factory: pytest.TempdirFactory) -> CertFactory: +def cert_factory(tmp_path_factory: pytest.TempPathFactory) -> CertFactory: # Delay the import requiring cryptography in order to make it possible # to deselect relevant tests on systems where cryptography cannot # be installed. @@ -563,7 +578,7 @@ def cert_factory(tmpdir_factory: pytest.TempdirFactory) -> CertFactory: def factory() -> str: """Returns path to cert/key file.""" - output_path = Path(str(tmpdir_factory.mktemp("certs"))) / "cert.pem" + output_path = tmp_path_factory.mktemp("certs") / "cert.pem" # Must be Text on PY2. cert, key = make_tls_cert("localhost") with open(str(output_path), "wb") as f: diff --git a/tests/functional/test_broken_stdout.py b/tests/functional/test_broken_stdout.py index e7313244379..22bcc06f29c 100644 --- a/tests/functional/test_broken_stdout.py +++ b/tests/functional/test_broken_stdout.py @@ -1,9 +1,8 @@ import os +import pathlib import subprocess from typing import List, Tuple -from tests.lib.path import Path - _BROKEN_STDOUT_RETURN_CODE = 120 @@ -47,11 +46,14 @@ def test_broken_stdout_pipe(deprecated_python: bool) -> None: assert returncode == _BROKEN_STDOUT_RETURN_CODE -def test_broken_stdout_pipe__log_option(deprecated_python: bool, tmpdir: Path) -> None: +def test_broken_stdout_pipe__log_option( + deprecated_python: bool, + tmp_path: pathlib.Path, +) -> None: """ Test a broken pipe to stdout when --log is passed. """ - log_path = os.path.join(str(tmpdir), "log.txt") + log_path = os.path.join(tmp_path, "log.txt") stderr, returncode = setup_broken_stdout_test( ["pip", "--log", log_path, "list"], deprecated_python=deprecated_python, diff --git a/tests/functional/test_build_env.py b/tests/functional/test_build_env.py index 1b9f42d94c0..d2ab79681ed 100644 --- a/tests/functional/test_build_env.py +++ b/tests/functional/test_build_env.py @@ -1,3 +1,4 @@ +import os from textwrap import dedent from typing import Optional @@ -69,11 +70,11 @@ def run_with_build_env( " ", ) ) - args = ["python", build_env_script] + args = ["python", os.fspath(build_env_script)] if test_script_contents is not None: test_script = script.scratch_path / "test.py" test_script.write_text(dedent(test_script_contents)) - args.append(test_script) + args.append(os.fspath(test_script)) return script.run(*args) @@ -89,7 +90,7 @@ def test_build_env_allow_empty_requirements_install() -> None: def test_build_env_allow_only_one_install(script: PipTestEnvironment) -> None: create_basic_wheel_for_package(script, "foo", "1.0") create_basic_wheel_for_package(script, "bar", "1.0") - finder = make_test_finder(find_links=[script.scratch_path]) + finder = make_test_finder(find_links=[os.fspath(script.scratch_path)]) build_env = BuildEnvironment() for prefix in ("normal", "overlay"): build_env.install_requirements( diff --git a/tests/functional/test_completion.py b/tests/functional/test_completion.py index ba302a69b18..d849007a595 100644 --- a/tests/functional/test_completion.py +++ b/tests/functional/test_completion.py @@ -1,12 +1,12 @@ import os +import pathlib import sys -from typing import TYPE_CHECKING, Optional, Tuple +from typing import TYPE_CHECKING, Tuple, Union import pytest from tests.conftest import ScriptFactory from tests.lib import PipTestEnvironment, TestData, TestPipResult -from tests.lib.path import Path if TYPE_CHECKING: from typing import Protocol @@ -83,12 +83,12 @@ @pytest.fixture(scope="session") def script_with_launchers( - tmpdir_factory: pytest.TempdirFactory, + tmp_path_factory: pytest.TempPathFactory, script_factory: ScriptFactory, - common_wheels: Path, - pip_src: Path, + common_wheels: pathlib.Path, + pip_src: pathlib.Path, ) -> PipTestEnvironment: - tmpdir = Path(str(tmpdir_factory.mktemp("script_with_launchers"))) + tmpdir = tmp_path_factory.mktemp("script_with_launchers") script = script_factory(tmpdir.joinpath("workspace")) # Re-install pip so we get the launchers. script.pip_install_local("-f", common_wheels, pip_src) @@ -112,15 +112,15 @@ def test_completion_for_supported_shells( @pytest.fixture(scope="session") def autocomplete_script( - tmpdir_factory: pytest.TempdirFactory, script_factory: ScriptFactory + tmp_path_factory: pytest.TempPathFactory, script_factory: ScriptFactory ) -> PipTestEnvironment: - tmpdir = Path(str(tmpdir_factory.mktemp("autocomplete_script"))) + tmpdir = tmp_path_factory.mktemp("autocomplete_script") return script_factory(tmpdir.joinpath("workspace")) class DoAutocomplete(Protocol): def __call__( - self, words: str, cword: str, cwd: Optional[str] = None + self, words: str, cword: str, cwd: Union[pathlib.Path, str, None] = None ) -> Tuple[TestPipResult, PipTestEnvironment]: ... @@ -133,7 +133,7 @@ def autocomplete( autocomplete_script.environ["PIP_AUTO_COMPLETE"] = "1" def do_autocomplete( - words: str, cword: str, cwd: Optional[str] = None + words: str, cword: str, cwd: Union[pathlib.Path, str, None] = None ) -> Tuple[TestPipResult, PipTestEnvironment]: autocomplete_script.environ["COMP_WORDS"] = words autocomplete_script.environ["COMP_CWORD"] = cword diff --git a/tests/functional/test_config_settings.py b/tests/functional/test_config_settings.py index 76c667cb91d..b914f8a25d2 100644 --- a/tests/functional/test_config_settings.py +++ b/tests/functional/test_config_settings.py @@ -1,9 +1,9 @@ import json +import pathlib from typing import Tuple from zipfile import ZipFile from tests.lib import PipTestEnvironment -from tests.lib.path import Path PYPROJECT_TOML = """\ [build-system] @@ -85,7 +85,7 @@ def build_wheel( ''' -def make_project(path: Path) -> Tuple[str, str, Path]: +def make_project(path: pathlib.Path) -> Tuple[str, str, pathlib.Path]: name = "foo" version = "1.0" project_dir = path / name diff --git a/tests/functional/test_download.py b/tests/functional/test_download.py index ace2ff74c5b..7284c2bcf30 100644 --- a/tests/functional/test_download.py +++ b/tests/functional/test_download.py @@ -1,4 +1,5 @@ import os.path +import pathlib import shutil import textwrap from hashlib import sha256 @@ -7,10 +8,8 @@ import pytest from pip._internal.cli.status_codes import ERROR -from pip._internal.utils.urls import path_to_url from tests.conftest import MockServer, ScriptFactory from tests.lib import PipTestEnvironment, TestData, create_really_basic_wheel -from tests.lib.path import Path from tests.lib.server import file_response @@ -27,7 +26,7 @@ def test_download_if_requested(script: PipTestEnvironment) -> None: It should download (in the scratch path) and not install if requested. """ result = script.pip("download", "-d", "pip_downloads", "INITools==0.1") - result.did_create(Path("scratch") / "pip_downloads" / "INITools-0.1.tar.gz") + result.did_create("scratch/pip_downloads/INITools-0.1.tar.gz") result.did_not_create(script.site_packages / "initools") @@ -37,7 +36,7 @@ def test_basic_download_setuptools(script: PipTestEnvironment) -> None: It should download (in the scratch path) and not install if requested. """ result = script.pip("download", "setuptools") - setuptools_prefix = str(Path("scratch") / "setuptools") + setuptools_prefix = os.path.join("scratch", "setuptools") assert any(path.startswith(setuptools_prefix) for path in result.files_created) @@ -48,7 +47,7 @@ def test_download_wheel(script: PipTestEnvironment, data: TestData) -> None: result = script.pip( "download", "--no-index", "-f", data.packages, "-d", ".", "meta" ) - result.did_create(Path("scratch") / "meta-1.0-py2.py3-none-any.whl") + result.did_create("scratch/meta-1.0-py2.py3-none-any.whl") result.did_not_create(script.site_packages / "piptestpackage") @@ -72,7 +71,7 @@ def test_single_download_from_requirements_file(script: PipTestEnvironment) -> N "-d", ".", ) - result.did_create(Path("scratch") / "INITools-0.1.tar.gz") + result.did_create("scratch/INITools-0.1.tar.gz") result.did_not_create(script.site_packages / "initools") @@ -84,8 +83,8 @@ def test_basic_download_should_download_dependencies( It should download dependencies (in the scratch path) """ result = script.pip("download", "Paste[openid]==1.7.5.1", "-d", ".") - result.did_create(Path("scratch") / "Paste-1.7.5.1.tar.gz") - openid_tarball_prefix = str(Path("scratch") / "python-openid-") + result.did_create("scratch/Paste-1.7.5.1.tar.gz") + openid_tarball_prefix = os.path.join("scratch, python-openid-") assert any(path.startswith(openid_tarball_prefix) for path in result.files_created) result.did_not_create(script.site_packages / "openid") @@ -97,7 +96,7 @@ def test_download_wheel_archive(script: PipTestEnvironment, data: TestData) -> N wheel_filename = "colander-0.9.9-py2.py3-none-any.whl" wheel_path = "/".join((data.find_links, wheel_filename)) result = script.pip("download", wheel_path, "-d", ".", "--no-deps") - result.did_create(Path("scratch") / wheel_filename) + result.did_create(pathlib.Path("scratch", wheel_filename)) def test_download_should_download_wheel_deps( @@ -112,8 +111,8 @@ def test_download_should_download_wheel_deps( result = script.pip( "download", wheel_path, "-d", ".", "--find-links", data.find_links, "--no-index" ) - result.did_create(Path("scratch") / wheel_filename) - result.did_create(Path("scratch") / dep_filename) + result.did_create(pathlib.Path("scratch", wheel_filename)) + result.did_create(pathlib.Path("scratch", dep_filename)) @pytest.mark.network @@ -136,7 +135,7 @@ def test_download_should_skip_existing_files(script: PipTestEnvironment) -> None "-d", ".", ) - result.did_create(Path("scratch") / "INITools-0.1.tar.gz") + result.did_create("scratch/INITools-0.1.tar.gz") result.did_not_create(script.site_packages / "initools") # adding second package to test-req.txt @@ -157,9 +156,9 @@ def test_download_should_skip_existing_files(script: PipTestEnvironment) -> None "-d", ".", ) - openid_tarball_prefix = str(Path("scratch") / "python-openid-") + openid_tarball_prefix = os.path.join("scratch", "python-openid-") assert any(path.startswith(openid_tarball_prefix) for path in result.files_created) - result.did_not_create(Path("scratch") / "INITools-0.1.tar.gz") + result.did_not_create("scratch/INITools-0.1.tar.gz") result.did_not_create(script.site_packages / "initools") result.did_not_create(script.site_packages / "openid") @@ -172,7 +171,7 @@ def test_download_vcs_link(script: PipTestEnvironment) -> None: result = script.pip( "download", "-d", ".", "git+https://github.com/pypa/pip-test-package.git" ) - result.did_create(Path("scratch") / "pip-test-package-0.1.1.zip") + result.did_create("scratch/pip-test-package-0.1.1.zip") result.did_not_create(script.site_packages / "piptestpackage") @@ -197,7 +196,7 @@ def test_only_binary_set_then_download_specific_platform( "linux_x86_64", "fake", ) - result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl") + result.did_create("scratch/fake-1.0-py2.py3-none-any.whl") def test_no_deps_set_then_download_specific_platform( @@ -221,7 +220,7 @@ def test_no_deps_set_then_download_specific_platform( "linux_x86_64", "fake", ) - result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl") + result.did_create("scratch/fake-1.0-py2.py3-none-any.whl") def test_download_specific_platform_fails( @@ -295,7 +294,7 @@ def test_download_specify_platform(script: PipTestEnvironment, data: TestData) - "linux_x86_64", "fake", ) - result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl") + result.did_create("scratch/fake-1.0-py2.py3-none-any.whl") result = script.pip( "download", @@ -326,7 +325,7 @@ def test_download_specify_platform(script: PipTestEnvironment, data: TestData) - "macosx_10_10_x86_64", "fake", ) - result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-macosx_10_9_x86_64.whl") + result.did_create("scratch/fake-1.0-py2.py3-none-macosx_10_9_x86_64.whl") # OSX platform wheels are not backward-compatible. result = script.pip( @@ -370,7 +369,7 @@ def test_download_specify_platform(script: PipTestEnvironment, data: TestData) - "linux_x86_64", "fake==2", ) - result.did_create(Path("scratch") / "fake-2.0-py2.py3-none-linux_x86_64.whl") + result.did_create("scratch/fake-2.0-py2.py3-none-linux_x86_64.whl") # Test with multiple supported platforms specified. data.reset() @@ -391,7 +390,7 @@ def test_download_specify_platform(script: PipTestEnvironment, data: TestData) - "any", "fake==3", ) - result.did_create(Path("scratch") / "fake-3.0-py2.py3-none-linux_x86_64.whl") + result.did_create("scratch/fake-3.0-py2.py3-none-linux_x86_64.whl") class TestDownloadPlatformManylinuxes: @@ -428,7 +427,7 @@ def test_download_universal( platform, "fake", ) - result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl") + result.did_create("scratch/fake-1.0-py2.py3-none-any.whl") @pytest.mark.parametrize( "wheel_abi,platform", @@ -465,7 +464,7 @@ def test_download_compatible_manylinuxes( platform, "fake", ) - result.did_create(Path("scratch") / wheel) + result.did_create(pathlib.Path("scratch", wheel)) def test_explicit_platform_only( self, data: TestData, script: PipTestEnvironment @@ -508,7 +507,7 @@ def test_download__python_version(script: PipTestEnvironment, data: TestData) -> "2", "fake", ) - result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl") + result.did_create("scratch/fake-1.0-py2.py3-none-any.whl") result = script.pip( "download", @@ -580,7 +579,7 @@ def test_download__python_version(script: PipTestEnvironment, data: TestData) -> "2", "fake", ) - result.did_create(Path("scratch") / "fake-1.0-py2-none-any.whl") + result.did_create("scratch/fake-1.0-py2-none-any.whl") result = script.pip( "download", @@ -607,12 +606,12 @@ def test_download__python_version(script: PipTestEnvironment, data: TestData) -> "3", "fake", ) - result.did_create(Path("scratch") / "fake-2.0-py3-none-any.whl") + result.did_create("scratch/fake-2.0-py3-none-any.whl") def make_wheel_with_python_requires( script: PipTestEnvironment, package_name: str, python_requires: str -) -> Path: +) -> pathlib.Path: """ Create a wheel using the given python_requires. @@ -708,7 +707,7 @@ def test_download_ignore_requires_python_dont_fail_with_wrong_python( ".", "mypackage==1.0", ) - result.did_create(Path("scratch") / "mypackage-1.0-py2.py3-none-any.whl") + result.did_create("scratch/mypackage-1.0-py2.py3-none-any.whl") def test_download_specify_abi(script: PipTestEnvironment, data: TestData) -> None: @@ -731,7 +730,7 @@ def test_download_specify_abi(script: PipTestEnvironment, data: TestData) -> Non "fake_abi", "fake", ) - result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl") + result.did_create("scratch/fake-1.0-py2.py3-none-any.whl") result = script.pip( "download", @@ -781,7 +780,7 @@ def test_download_specify_abi(script: PipTestEnvironment, data: TestData) -> Non "fakeabi", "fake", ) - result.did_create(Path("scratch") / "fake-1.0-fk2-fakeabi-fake_platform.whl") + result.did_create("scratch/fake-1.0-fk2-fakeabi-fake_platform.whl") result = script.pip( "download", @@ -825,7 +824,7 @@ def test_download_specify_abi(script: PipTestEnvironment, data: TestData) -> Non "none", "fake", ) - result.did_create(Path("scratch") / "fake-1.0-fk2-otherabi-fake_platform.whl") + result.did_create("scratch/fake-1.0-fk2-otherabi-fake_platform.whl") def test_download_specify_implementation( @@ -848,7 +847,7 @@ def test_download_specify_implementation( "fk", "fake", ) - result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl") + result.did_create("scratch/fake-1.0-py2.py3-none-any.whl") data.reset() fake_wheel(data, "fake-1.0-fk3-none-any.whl") @@ -866,7 +865,7 @@ def test_download_specify_implementation( "3", "fake", ) - result.did_create(Path("scratch") / "fake-1.0-fk3-none-any.whl") + result.did_create("scratch/fake-1.0-fk3-none-any.whl") result = script.pip( "download", @@ -920,8 +919,8 @@ def test_download_prefer_binary_when_tarball_higher_than_wheel( ".", "source", ) - result.did_create(Path("scratch") / "source-0.8-py2.py3-none-any.whl") - result.did_not_create(Path("scratch") / "source-1.0.tar.gz") + result.did_create("scratch/source-0.8-py2.py3-none-any.whl") + result.did_not_create("scratch/source-1.0.tar.gz") def test_prefer_binary_tarball_higher_than_wheel_req_file( @@ -947,8 +946,8 @@ def test_prefer_binary_tarball_higher_than_wheel_req_file( ".", ) - result.did_create(Path("scratch") / "source-0.8-py2.py3-none-any.whl") - result.did_not_create(Path("scratch") / "source-1.0.tar.gz") + result.did_create("scratch/source-0.8-py2.py3-none-any.whl") + result.did_not_create("scratch/source-1.0.tar.gz") def test_download_prefer_binary_when_wheel_doesnt_satisfy_req( @@ -974,8 +973,8 @@ def test_download_prefer_binary_when_wheel_doesnt_satisfy_req( "-r", script.scratch_path / "test-req.txt", ) - result.did_create(Path("scratch") / "source-1.0.tar.gz") - result.did_not_create(Path("scratch") / "source-0.8-py2.py3-none-any.whl") + result.did_create("scratch/source-1.0.tar.gz") + result.did_not_create("scratch/source-0.8-py2.py3-none-any.whl") def test_prefer_binary_when_wheel_doesnt_satisfy_req_req_file( @@ -1001,8 +1000,8 @@ def test_prefer_binary_when_wheel_doesnt_satisfy_req_req_file( "-r", script.scratch_path / "test-req.txt", ) - result.did_create(Path("scratch") / "source-1.0.tar.gz") - result.did_not_create(Path("scratch") / "source-0.8-py2.py3-none-any.whl") + result.did_create("scratch/source-1.0.tar.gz") + result.did_not_create("scratch/source-0.8-py2.py3-none-any.whl") def test_download_prefer_binary_when_only_tarball_exists( @@ -1018,7 +1017,7 @@ def test_download_prefer_binary_when_only_tarball_exists( ".", "source", ) - result.did_create(Path("scratch") / "source-1.0.tar.gz") + result.did_create("scratch/source-1.0.tar.gz") def test_prefer_binary_when_only_tarball_exists_req_file( @@ -1042,22 +1041,24 @@ def test_prefer_binary_when_only_tarball_exists_req_file( "-r", script.scratch_path / "test-req.txt", ) - result.did_create(Path("scratch") / "source-1.0.tar.gz") + result.did_create("scratch/source-1.0.tar.gz") @pytest.fixture(scope="session") def shared_script( - tmpdir_factory: pytest.TempdirFactory, script_factory: ScriptFactory + tmp_path_factory: pytest.TempPathFactory, script_factory: ScriptFactory ) -> PipTestEnvironment: - tmpdir = Path(str(tmpdir_factory.mktemp("download_shared_script"))) - script = script_factory(tmpdir.joinpath("workspace")) + tmp_path = tmp_path_factory.mktemp("download_shared_script") + script = script_factory(tmp_path.joinpath("workspace")) return script def test_download_file_url( - shared_script: PipTestEnvironment, shared_data: TestData, tmpdir: Path + shared_script: PipTestEnvironment, + shared_data: TestData, + tmp_path: pathlib.Path, ) -> None: - download_dir = tmpdir / "download" + download_dir = tmp_path / "download" download_dir.mkdir() downloaded_path = download_dir / "simple-1.0.tar.gz" @@ -1068,7 +1069,7 @@ def test_download_file_url( "-d", str(download_dir), "--no-index", - path_to_url(str(simple_pkg)), + simple_pkg.as_uri(), ) assert downloaded_path.exists() @@ -1076,18 +1077,19 @@ def test_download_file_url( def test_download_file_url_existing_ok_download( - shared_script: PipTestEnvironment, shared_data: TestData, tmpdir: Path + shared_script: PipTestEnvironment, + shared_data: TestData, + tmp_path: pathlib.Path, ) -> None: - download_dir = tmpdir / "download" + download_dir = tmp_path / "download" download_dir.mkdir() downloaded_path = download_dir / "simple-1.0.tar.gz" fake_existing_package = shared_data.packages / "simple-2.0.tar.gz" shutil.copy(str(fake_existing_package), str(downloaded_path)) downloaded_path_bytes = downloaded_path.read_bytes() - digest = sha256(downloaded_path_bytes).hexdigest() simple_pkg = shared_data.packages / "simple-1.0.tar.gz" - url = "{}#sha256={}".format(path_to_url(simple_pkg), digest) + url = f"{simple_pkg.as_uri()}#sha256={sha256(downloaded_path_bytes).hexdigest()}" shared_script.pip("download", "-d", str(download_dir), url) @@ -1095,9 +1097,11 @@ def test_download_file_url_existing_ok_download( def test_download_file_url_existing_bad_download( - shared_script: PipTestEnvironment, shared_data: TestData, tmpdir: Path + shared_script: PipTestEnvironment, + shared_data: TestData, + tmp_path: pathlib.Path, ) -> None: - download_dir = tmpdir / "download" + download_dir = tmp_path / "download" download_dir.mkdir() downloaded_path = download_dir / "simple-1.0.tar.gz" fake_existing_package = shared_data.packages / "simple-2.0.tar.gz" @@ -1105,8 +1109,7 @@ def test_download_file_url_existing_bad_download( simple_pkg = shared_data.packages / "simple-1.0.tar.gz" simple_pkg_bytes = simple_pkg.read_bytes() - digest = sha256(simple_pkg_bytes).hexdigest() - url = "{}#sha256={}".format(path_to_url(simple_pkg), digest) + url = f"{simple_pkg.as_uri()}#sha256={sha256(simple_pkg_bytes).hexdigest()}" shared_script.pip("download", "-d", str(download_dir), url) @@ -1116,13 +1119,13 @@ def test_download_file_url_existing_bad_download( def test_download_http_url_bad_hash( shared_script: PipTestEnvironment, shared_data: TestData, - tmpdir: Path, + tmp_path: pathlib.Path, mock_server: MockServer, ) -> None: """ If already-downloaded file has bad checksum, re-download. """ - download_dir = tmpdir / "download" + download_dir = tmp_path / "download" download_dir.mkdir() downloaded_path = download_dir / "simple-1.0.tar.gz" fake_existing_package = shared_data.packages / "simple-2.0.tar.gz" @@ -1148,15 +1151,15 @@ def test_download_http_url_bad_hash( def test_download_editable( - script: PipTestEnvironment, data: TestData, tmpdir: Path + script: PipTestEnvironment, data: TestData, tmp_path: pathlib.Path ) -> None: """ Test 'pip download' of editables in requirement file. """ editable_path = str(data.src / "simplewheel-1.0").replace(os.path.sep, "/") - requirements_path = tmpdir / "requirements.txt" + requirements_path = tmp_path / "requirements.txt" requirements_path.write_text("-e " + editable_path + "\n") - download_dir = tmpdir / "download_dir" + download_dir = tmp_path / "download_dir" script.pip( "download", "--no-deps", "-r", str(requirements_path), "-d", str(download_dir) ) diff --git a/tests/functional/test_fast_deps.py b/tests/functional/test_fast_deps.py index 87c070c78c5..0109db825b7 100644 --- a/tests/functional/test_fast_deps.py +++ b/tests/functional/test_fast_deps.py @@ -1,5 +1,6 @@ import fnmatch import json +import os import pathlib from os.path import basename from typing import Iterable @@ -60,7 +61,7 @@ def test_download_from_pypi( @mark.network def test_build_wheel_with_deps(data: TestData, script: PipTestEnvironment) -> None: - result = pip(script, "wheel", data.packages / "requiresPaste") + result = pip(script, "wheel", os.fspath(data.packages / "requiresPaste")) created = [basename(f) for f in result.files_created] assert fnmatch.filter(created, "requirespaste-3.1.4-*.whl") assert fnmatch.filter(created, "Paste-3.4.2-*.whl") diff --git a/tests/functional/test_freeze.py b/tests/functional/test_freeze.py index bae9eadbd30..2897dd54ee8 100644 --- a/tests/functional/test_freeze.py +++ b/tests/functional/test_freeze.py @@ -1,4 +1,5 @@ import os +import pathlib import re import sys import textwrap @@ -19,11 +20,9 @@ need_bzr, need_mercurial, need_svn, - path_to_url, wheel, ) from tests.lib.direct_url import get_created_direct_url_path -from tests.lib.path import Path from tests.lib.venv import VirtualEnvironment distribute_re = re.compile("^distribute==[0-9.]+\n", re.MULTILINE) @@ -94,9 +93,12 @@ def test_freeze_with_pip(script: PipTestEnvironment) -> None: assert "pip==" in result.stdout -def test_exclude_and_normalization(script: PipTestEnvironment, tmpdir: Path) -> None: +def test_exclude_and_normalization( + script: PipTestEnvironment, + tmp_path: pathlib.Path, +) -> None: req_path = wheel.make_wheel(name="Normalizable_Name", version="1.0").save_to_dir( - tmpdir + tmp_path, ) script.pip("install", "--no-index", req_path) result = script.pip("freeze") @@ -150,7 +152,7 @@ def fake_install(pkgname: str, dest: str) -> None: "trailingdot.", ) for pkgname in valid_pkgnames + invalid_pkgnames: - fake_install(pkgname, script.site_packages_path) + fake_install(pkgname, os.fspath(script.site_packages_path)) result = script.pip("freeze", expect_stderr=True) @@ -256,7 +258,7 @@ def test_freeze_exclude_editable(script: PipTestEnvironment) -> None: result = script.run( "git", "clone", - pkg_version, + os.fspath(pkg_version), "pip-test-package", expect_stderr=True, ) @@ -289,7 +291,7 @@ def test_freeze_git_clone(script: PipTestEnvironment) -> None: result = script.run( "git", "clone", - pkg_version, + os.fspath(pkg_version), "pip-test-package", expect_stderr=True, ) @@ -349,7 +351,7 @@ def test_freeze_git_clone_srcdir(script: PipTestEnvironment) -> None: result = script.run( "git", "clone", - pkg_version, + os.fspath(pkg_version), "pip-test-package", expect_stderr=True, ) @@ -381,7 +383,7 @@ def test_freeze_mercurial_clone_srcdir(script: PipTestEnvironment) -> None: # Returns path to a generated package called "version_pkg" pkg_version = _create_test_package_with_srcdir(script, vcs="hg") - result = script.run("hg", "clone", pkg_version, "pip-test-package") + result = script.run("hg", "clone", os.fspath(pkg_version), "pip-test-package") repo_dir = script.scratch_path / "pip-test-package" result = script.run("python", "setup.py", "develop", cwd=repo_dir / "subdir") result = script.pip("freeze") @@ -405,7 +407,7 @@ def test_freeze_git_remote(script: PipTestEnvironment) -> None: result = script.run( "git", "clone", - pkg_version, + os.fspath(pkg_version), "pip-test-package", expect_stderr=True, ) @@ -427,7 +429,7 @@ def test_freeze_git_remote(script: PipTestEnvironment) -> None: ... """ ) - .format(remote=path_to_url(origin_remote)) + .format(remote=origin_remote.as_uri()) .strip() ) _check_output(result.stdout, expected) @@ -441,13 +443,13 @@ def test_freeze_git_remote(script: PipTestEnvironment) -> None: ... """ ) - .format(remote=path_to_url(origin_remote)) + .format(remote=origin_remote.as_uri()) .strip() ) _check_output(result.stdout, expected) # When the remote is a local path, it must exist. # If it doesn't, it gets flagged as invalid. - other_remote = pkg_version + "-other" + other_remote = f"{pkg_version}-other" script.run("git", "remote", "set-url", "other", other_remote, cwd=repo_dir) result = script.pip("freeze", expect_stderr=True) expected = os.path.normcase( @@ -462,7 +464,7 @@ def test_freeze_git_remote(script: PipTestEnvironment) -> None: _check_output(os.path.normcase(result.stdout), expected) # when there are more than one origin, priority is given to the # remote named origin - script.run("git", "remote", "add", "origin", origin_remote, cwd=repo_dir) + script.run("git", "remote", "add", "origin", os.fspath(origin_remote), cwd=repo_dir) result = script.pip("freeze", expect_stderr=True) expected = ( textwrap.dedent( @@ -471,7 +473,7 @@ def test_freeze_git_remote(script: PipTestEnvironment) -> None: ... """ ) - .format(remote=path_to_url(origin_remote)) + .format(remote=origin_remote.as_uri()) .strip() ) _check_output(result.stdout, expected) @@ -489,7 +491,7 @@ def test_freeze_mercurial_clone(script: PipTestEnvironment) -> None: result = script.run( "hg", "clone", - pkg_version, + os.fspath(pkg_version), "pip-test-package", expect_stderr=True, ) @@ -522,7 +524,7 @@ def test_freeze_bazaar_clone(script: PipTestEnvironment) -> None: except OSError as e: pytest.fail(f"Invoking `bzr` failed: {e}") - result = script.run("bzr", "checkout", checkout_path, "bzr-package") + result = script.run("bzr", "checkout", os.fspath(checkout_path), "bzr-package") result = script.run( "python", "setup.py", @@ -562,7 +564,13 @@ def test_freeze_nested_vcs( # Clone Python package into inner directory and install it. src_path = root_path.joinpath("src") src_path.mkdir() - script.run(inner_vcs, "clone", pkg_path, src_path, expect_stderr=True) + script.run( + inner_vcs, + "clone", + os.fspath(pkg_path), + os.fspath(src_path), + expect_stderr=True, + ) script.pip("install", "-e", src_path, expect_stderr=True) # Check the freeze output recognizes the inner VCS. @@ -600,7 +608,7 @@ def test_freeze_with_requirement_option_file_url_egg_not_installed( is not installed. """ - url = path_to_url("my-package.tar.gz") + "#egg=Does.Not-Exist" + url = pathlib.Path("my-package.tar.gz").resolve().as_uri() + "#egg=Does.Not-Exist" requirements_path = script.scratch_path.joinpath("requirements.txt") requirements_path.write_text(url + "\n") @@ -878,14 +886,18 @@ def test_freeze_user( @pytest.mark.network -def test_freeze_path(tmpdir: Path, script: PipTestEnvironment, data: TestData) -> None: +def test_freeze_path( + tmp_path: pathlib.Path, + script: PipTestEnvironment, + data: TestData, +) -> None: """ Test freeze with --path. """ script.pip( - "install", "--find-links", data.find_links, "--target", tmpdir, "simple==2.0" + "install", "--find-links", data.find_links, "--target", tmp_path, "simple==2.0" ) - result = script.pip("freeze", "--path", tmpdir) + result = script.pip("freeze", "--path", tmp_path) expected = textwrap.dedent( """\ simple==2.0 @@ -897,7 +909,7 @@ def test_freeze_path(tmpdir: Path, script: PipTestEnvironment, data: TestData) - @pytest.mark.network @pytest.mark.incompatible_with_test_venv def test_freeze_path_exclude_user( - tmpdir: Path, script: PipTestEnvironment, data: TestData + tmp_path: pathlib.Path, script: PipTestEnvironment, data: TestData ) -> None: """ Test freeze with --path and make sure packages from --user are not picked @@ -905,7 +917,7 @@ def test_freeze_path_exclude_user( """ script.pip_install_local("--find-links", data.find_links, "--user", "simple2") script.pip( - "install", "--find-links", data.find_links, "--target", tmpdir, "simple==1.0" + "install", "--find-links", data.find_links, "--target", tmp_path, "simple==1.0" ) result = script.pip("freeze", "--user") expected = textwrap.dedent( @@ -914,7 +926,7 @@ def test_freeze_path_exclude_user( """ ) _check_output(result.stdout, expected) - result = script.pip("freeze", "--path", tmpdir) + result = script.pip("freeze", "--path", tmp_path) expected = textwrap.dedent( """\ simple==1.0 @@ -925,14 +937,14 @@ def test_freeze_path_exclude_user( @pytest.mark.network def test_freeze_path_multiple( - tmpdir: Path, script: PipTestEnvironment, data: TestData + tmp_path: pathlib.Path, script: PipTestEnvironment, data: TestData ) -> None: """ Test freeze with multiple --path arguments. """ - path1 = tmpdir / "path1" + path1 = tmp_path / "path1" os.mkdir(path1) - path2 = tmpdir / "path2" + path2 = tmp_path / "path2" os.mkdir(path2) script.pip( "install", "--find-links", data.find_links, "--target", path1, "simple==2.0" @@ -961,8 +973,7 @@ def test_freeze_path_multiple( def test_freeze_direct_url_archive( script: PipTestEnvironment, shared_data: TestData ) -> None: - req = "simple @ " + path_to_url(shared_data.packages / "simple-2.0.tar.gz") - assert req.startswith("simple @ file://") + req = "simple @ " + shared_data.packages.joinpath("simple-2.0.tar.gz").as_uri() script.pip("install", req) result = script.pip("freeze") assert req in result.stdout diff --git a/tests/functional/test_hash.py b/tests/functional/test_hash.py index 7734ce58bb1..ee40adec591 100644 --- a/tests/functional/test_hash.py +++ b/tests/functional/test_hash.py @@ -1,39 +1,44 @@ """Tests for the ``pip hash`` command""" +import pathlib + from tests.lib import PipTestEnvironment -from tests.lib.path import Path -def test_basic_hash(script: PipTestEnvironment, tmpdir: Path) -> None: +def test_basic_hash(script: PipTestEnvironment, tmp_path: pathlib.Path) -> None: """Run 'pip hash' through its default behavior.""" expected = ( "--hash=sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425" "e73043362938b9824" ) - result = script.pip("hash", _hello_file(tmpdir)) + result = script.pip("hash", _hello_file(tmp_path)) assert expected in str(result) -def test_good_algo_option(script: PipTestEnvironment, tmpdir: Path) -> None: +def test_good_algo_option(script: PipTestEnvironment, tmp_path: pathlib.Path) -> None: """Make sure the -a option works.""" expected = ( "--hash=sha512:9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caad" "ae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e" "5c3adef46f73bcdec043" ) - result = script.pip("hash", "-a", "sha512", _hello_file(tmpdir)) + result = script.pip("hash", "-a", "sha512", _hello_file(tmp_path)) assert expected in str(result) -def test_bad_algo_option(script: PipTestEnvironment, tmpdir: Path) -> None: +def test_bad_algo_option(script: PipTestEnvironment, tmp_path: pathlib.Path) -> None: """Make sure the -a option raises an error when given a bad operand.""" result = script.pip( - "hash", "-a", "invalidname", _hello_file(tmpdir), expect_error=True + "hash", + "-a", + "invalidname", + _hello_file(tmp_path), + expect_error=True, ) assert "invalid choice: 'invalidname'" in str(result) -def _hello_file(tmpdir: Path) -> Path: +def _hello_file(tmp_path: pathlib.Path) -> pathlib.Path: """Return a temp file to hash containing "hello".""" - file = tmpdir / "hashable" + file = tmp_path / "hashable" file.write_text("hello") return file diff --git a/tests/functional/test_install.py b/tests/functional/test_install.py index 3bf2579ed4b..186a3787cef 100644 --- a/tests/functional/test_install.py +++ b/tests/functional/test_install.py @@ -1,6 +1,6 @@ import distutils -import glob import os +import pathlib import re import ssl import sys @@ -25,12 +25,10 @@ need_bzr, need_mercurial, need_svn, - path_to_url, pyversion, requirements_file, ) from tests.lib.local_repos import local_checkout -from tests.lib.path import Path from tests.lib.server import ( file_response, make_mock_server, @@ -44,7 +42,7 @@ def test_pep518_uses_build_env( script: PipTestEnvironment, data: TestData, - common_wheels: Path, + common_wheels: pathlib.Path, command: str, variant: str, ) -> None: @@ -70,8 +68,8 @@ def test_pep518_uses_build_env( def test_pep518_build_env_uses_same_pip( script: PipTestEnvironment, data: TestData, - pip_src: Path, - common_wheels: Path, + pip_src: pathlib.Path, + common_wheels: pathlib.Path, deprecated_python: bool, ) -> None: """Ensure the subprocess call to pip for installing the @@ -81,14 +79,14 @@ def test_pep518_build_env_uses_same_pip( fp.write("raise ImportError") script.run( "python", - pip_src / "src/pip", + os.fspath(pip_src / "src/pip"), "install", "--no-index", "-f", - common_wheels, + os.fspath(common_wheels), "-f", - data.packages, - data.src.joinpath("pep518-3.0"), + os.fspath(data.packages), + os.fspath(data.src.joinpath("pep518-3.0")), expect_stderr=deprecated_python, ) @@ -108,14 +106,14 @@ def test_pep518_refuses_conflicting_requires( "Some build dependencies for {url} conflict " "with PEP 517/518 supported " "requirements: setuptools==1.0 is incompatible with " - "setuptools>=40.8.0.".format(url=path_to_url(project_dir)) + "setuptools>=40.8.0.".format(url=project_dir.as_uri()) ) in result.stderr ), str(result) def test_pep518_refuses_invalid_requires( - script: PipTestEnvironment, data: TestData, common_wheels: Path + script: PipTestEnvironment, data: TestData, common_wheels: pathlib.Path ) -> None: result = script.pip( "install", @@ -134,7 +132,7 @@ def test_pep518_refuses_invalid_requires( def test_pep518_refuses_invalid_build_system( - script: PipTestEnvironment, data: TestData, common_wheels: Path + script: PipTestEnvironment, data: TestData, common_wheels: pathlib.Path ) -> None: result = script.pip( "install", @@ -153,7 +151,7 @@ def test_pep518_refuses_invalid_build_system( def test_pep518_allows_missing_requires( - script: PipTestEnvironment, data: TestData, common_wheels: Path + script: PipTestEnvironment, data: TestData, common_wheels: pathlib.Path ) -> None: result = script.pip( "install", @@ -174,7 +172,10 @@ def test_pep518_allows_missing_requires( @pytest.mark.incompatible_with_test_venv def test_pep518_with_user_pip( - script: PipTestEnvironment, pip_src: Path, data: TestData, common_wheels: Path + script: PipTestEnvironment, + pip_src: pathlib.Path, + data: TestData, + common_wheels: pathlib.Path, ) -> None: """ Check that build dependencies are installed into the build @@ -203,7 +204,7 @@ def test_pep518_with_user_pip( def test_pep518_with_extra_and_markers( - script: PipTestEnvironment, data: TestData, common_wheels: Path + script: PipTestEnvironment, data: TestData, common_wheels: pathlib.Path ) -> None: script.pip( "wheel", @@ -217,7 +218,7 @@ def test_pep518_with_extra_and_markers( def test_pep518_with_namespace_package( - script: PipTestEnvironment, data: TestData, common_wheels: Path + script: PipTestEnvironment, data: TestData, common_wheels: pathlib.Path ) -> None: script.pip( "wheel", @@ -239,7 +240,7 @@ def test_pep518_with_namespace_package( def test_pep518_forkbombs( script: PipTestEnvironment, data: TestData, - common_wheels: Path, + common_wheels: pathlib.Path, command: str, package: str, ) -> None: @@ -258,7 +259,7 @@ def test_pep518_forkbombs( assert ( "{1} is already being built: {0} from {1}".format( package, - path_to_url(package_source), + package_source.as_uri(), ) in result.stderr ), str(result) @@ -268,9 +269,9 @@ def test_pep518_forkbombs( @pytest.mark.usefixtures("with_wheel") def test_pip_second_command_line_interface_works( script: PipTestEnvironment, - pip_src: Path, + pip_src: pathlib.Path, data: TestData, - common_wheels: Path, + common_wheels: pathlib.Path, deprecated_python: bool, ) -> None: """ @@ -280,7 +281,7 @@ def test_pip_second_command_line_interface_works( script.pip_install_local("-f", common_wheels, pip_src) args = [f"pip{pyversion}"] args.extend(["install", "INITools==0.2"]) - args.extend(["-f", data.packages]) + args.extend(["-f", os.fspath(data.packages)]) result = script.run(*args) dist_info_folder = script.site_packages / "INITools-0.2.dist-info" initools_folder = script.site_packages / "initools" @@ -359,7 +360,7 @@ def _test_install_editable_from_git(script: PipTestEnvironment) -> None: args = [ "install", "-e", - "git+{url}#egg=testpackage".format(url=path_to_url(pkg_path)), + f"git+{pkg_path.as_uri()}#egg=testpackage", ] result = script.pip(*args) result.assert_installed("testpackage", with_files=[".git"]) @@ -376,7 +377,7 @@ def test_install_editable_from_git_autobuild_wheel(script: PipTestEnvironment) - @pytest.mark.network def test_install_editable_uninstalls_existing( - data: TestData, script: PipTestEnvironment, tmpdir: Path + data: TestData, script: PipTestEnvironment, tmp_path: pathlib.Path ) -> None: """ Test that installing an editable uninstalls a previously installed @@ -395,7 +396,7 @@ def test_install_editable_uninstalls_existing( "{dir}#egg=pip-test-package".format( dir=local_checkout( "git+https://github.com/pypa/pip-test-package.git", - tmpdir, + tmp_path, ) ), ) @@ -436,7 +437,7 @@ def test_install_editable_uninstalls_existing_from_path( def test_basic_install_editable_from_hg(script: PipTestEnvironment) -> None: """Test cloning and hg+file install from Mercurial.""" pkg_path = _create_test_package(script, name="testpackage", vcs="hg") - url = "hg+{}#egg=testpackage".format(path_to_url(pkg_path)) + url = f"hg+{pkg_path.as_uri()}#egg=testpackage" assert url.startswith("hg+file") args = ["install", "-e", url] result = script.pip(*args) @@ -452,7 +453,7 @@ def test_vcs_url_final_slash_normalization(script: PipTestEnvironment) -> None: args = [ "install", "-e", - "hg+{url}/#egg=testpackage".format(url=path_to_url(pkg_path)), + f"hg+{pkg_path.as_uri()}/#egg=testpackage", ] result = script.pip(*args) result.assert_installed("testpackage", with_files=[".hg"]) @@ -465,7 +466,7 @@ def test_install_editable_from_bazaar(script: PipTestEnvironment) -> None: args = [ "install", "-e", - "bzr+{url}/#egg=testpackage".format(url=path_to_url(pkg_path)), + f"bzr+{pkg_path.as_uri()}/#egg=testpackage", ] result = script.pip(*args) result.assert_installed("testpackage", with_files=[".bzr"]) @@ -474,7 +475,7 @@ def test_install_editable_from_bazaar(script: PipTestEnvironment) -> None: @pytest.mark.network @need_bzr def test_vcs_url_urlquote_normalization( - script: PipTestEnvironment, tmpdir: Path + script: PipTestEnvironment, tmp_path: pathlib.Path ) -> None: """ Test that urlquoted characters are normalized for repo URL comparison. @@ -487,7 +488,7 @@ def test_vcs_url_urlquote_normalization( "bzr+http://bazaar.launchpad.net/" "%7Edjango-wikiapp/django-wikiapp" "/release-0.1", - tmpdir, + tmp_path, ) ), ) @@ -504,8 +505,7 @@ def test_basic_install_from_local_directory( args = ["install"] if resolver: args.append(resolver) - to_install = data.packages.joinpath("FSPkg") - args.append(to_install) + args.append(os.fspath(data.packages.joinpath("FSPkg"))) result = script.pip(*args) fspkg_folder = script.site_packages / "fspkg" dist_info_folder = script.site_packages / "FSPkg-0.1.dev0.dist-info" @@ -536,16 +536,14 @@ def test_basic_install_relative_directory( package_folder = script.site_packages / "fspkg" # Compute relative install path to FSPkg from scratch path. - full_rel_path = Path( - os.path.relpath(data.packages.joinpath("FSPkg"), script.scratch_path) - ) - full_rel_url = "file:" + full_rel_path.replace(os.path.sep, "/") + "#egg=FSPkg" + full_rel_path = data.packages.joinpath("FSPkg").relative_to(script.scratch_path) + full_rel_url = f"{full_rel_path.as_uri()}#egg=FSPkg" embedded_rel_path = script.scratch_path.joinpath(full_rel_path) req_path = { - "rel_path": full_rel_path, + "rel_path": os.fspath(full_rel_path), "rel_url": full_rel_url, - "embedded_rel_path": embedded_rel_path, + "embedded_rel_path": os.fspath(embedded_rel_path), }[test_type] # Install as either editable or not. @@ -574,7 +572,7 @@ def test_install_quiet(script: PipTestEnvironment, data: TestData) -> None: def test_hashed_install_success( - script: PipTestEnvironment, data: TestData, tmpdir: Path + script: PipTestEnvironment, data: TestData, tmp_path: pathlib.Path ) -> None: """ Test that installing various sorts of requirements with correct hashes @@ -584,18 +582,20 @@ def test_hashed_install_success( scenes). """ - file_url = path_to_url((data.packages / "simple-1.0.tar.gz").resolve()) + file_url = data.packages.joinpath("simple-1.0.tar.gz").resolve().as_uri() with requirements_file( "simple2==1.0 --hash=sha256:9336af72ca661e6336eb87bc7de3e8844d853e" "3848c2b9bbd2e8bf01db88c2c7\n" "{simple} --hash=sha256:393043e672415891885c9a2a0929b1af95fb866d6c" "a016b42d2e6ce53619b653".format(simple=file_url), - tmpdir, + tmp_path, ) as reqs_file: script.pip_install_local("-r", reqs_file.resolve()) -def test_hashed_install_failure(script: PipTestEnvironment, tmpdir: Path) -> None: +def test_hashed_install_failure( + script: PipTestEnvironment, tmp_path: pathlib.Path +) -> None: """Test that wrong hashes stop installation. This makes sure prepare_files() is called in the course of installation @@ -606,7 +606,7 @@ def test_hashed_install_failure(script: PipTestEnvironment, tmpdir: Path) -> Non with requirements_file( "simple2==1.0 --hash=sha256:9336af72ca661e6336eb87b" "c7de3e8844d853e3848c2b9bbd2e8bf01db88c2c\n", - tmpdir, + tmp_path, ) as reqs_file: result = script.pip_install_local("-r", reqs_file.resolve(), expect_error=True) assert len(result.files_created) == 0 @@ -619,7 +619,7 @@ def assert_re_match(pattern: str, text: str) -> None: @pytest.mark.network @pytest.mark.skip("Fails on new resolver") def test_hashed_install_failure_later_flag( - script: PipTestEnvironment, tmpdir: Path + script: PipTestEnvironment, tmp_path: pathlib.Path ) -> None: with requirements_file( "blessings==1.0\n" @@ -628,7 +628,7 @@ def test_hashed_install_failure_later_flag( "more-itertools-1.0.tar.gz#md5=b21850c3cfa7efbb70fd662ab5413bdd\n" "https://files.pythonhosted.org/" "packages/source/p/peep/peep-3.1.1.tar.gz\n", - tmpdir, + tmp_path, ) as reqs_file: result = script.pip("install", "-r", reqs_file.resolve(), expect_error=True) @@ -654,11 +654,10 @@ def test_install_from_local_directory_with_in_tree_build( Test installing from a local directory with default in tree build. """ to_install = data.packages.joinpath("FSPkg") - args = ["install", to_install] in_tree_build_dir = to_install / "build" assert not in_tree_build_dir.exists() - result = script.pip(*args) + result = script.pip("install", to_install) fspkg_folder = script.site_packages / "fspkg" dist_info_folder = script.site_packages / "FSPkg-0.1.dev0.dist-info" result.did_create(fspkg_folder) @@ -799,14 +798,14 @@ def test_install_with_hacked_egg_info( @pytest.mark.network def test_install_using_install_option_and_editable( - script: PipTestEnvironment, tmpdir: Path + script: PipTestEnvironment, tmp_path: pathlib.Path ) -> None: """ Test installing a tool using -e and --install-option """ folder = "script_folder" script.scratch_path.joinpath(folder).mkdir() - url = local_checkout("git+https://github.com/pypa/pip-test-package", tmpdir) + url = local_checkout("git+https://github.com/pypa/pip-test-package", tmp_path) result = script.pip( "install", "-e", @@ -825,7 +824,7 @@ def test_install_using_install_option_and_editable( @pytest.mark.network @need_mercurial def test_install_global_option_using_editable( - script: PipTestEnvironment, tmpdir: Path + script: PipTestEnvironment, tmp_path: pathlib.Path ) -> None: """ Test using global distutils options, but in an editable installation @@ -835,7 +834,7 @@ def test_install_global_option_using_editable( "install", "--global-option=--version", "-e", - "{url}@0.2.5#egg=anyjson".format(url=local_checkout(url, tmpdir)), + f"{local_checkout(url, tmp_path)}@0.2.5#egg=anyjson", expect_stderr=True, ) assert "Successfully installed anyjson" in result.stdout @@ -896,7 +895,7 @@ def test_install_folder_using_relative_path(script: PipTestEnvironment) -> None: script.scratch_path.joinpath("initools", "mock").mkdir() pkg_path = script.scratch_path / "initools" / "mock" pkg_path.joinpath("setup.py").write_text(mock100_setup_py) - result = script.pip("install", Path("initools") / "mock") + result = script.pip("install", "./initools/mock") dist_info_folder = script.site_packages / "mock-100.1.dist-info" result.did_create(dist_info_folder) @@ -921,7 +920,7 @@ def test_install_package_with_target(script: PipTestEnvironment) -> None: """ target_dir = script.scratch_path / "target" result = script.pip_install_local("-t", target_dir, "simple==1.0") - result.did_create(Path("scratch") / "target" / "simple") + result.did_create("scratch/target/simple") # Test repeated call without --upgrade, no files should have changed result = script.pip_install_local( @@ -930,23 +929,21 @@ def test_install_package_with_target(script: PipTestEnvironment) -> None: "simple==1.0", expect_stderr=True, ) - result.did_not_update(Path("scratch") / "target" / "simple") + result.did_not_update("scratch/target/simple") # Test upgrade call, check that new version is installed result = script.pip_install_local("--upgrade", "-t", target_dir, "simple==2.0") - result.did_update(Path("scratch") / "target" / "simple") - dist_info_folder = Path("scratch") / "target" / "simple-2.0.dist-info" - result.did_create(dist_info_folder) + result.did_update("scratch/target/simple") + result.did_create("scratch/target/simple-2.0.dist-info") # Test install and upgrade of single-module package result = script.pip_install_local("-t", target_dir, "singlemodule==0.0.0") - singlemodule_py = Path("scratch") / "target" / "singlemodule.py" - result.did_create(singlemodule_py) + result.did_create("scratch/target/singlemodule.py") result = script.pip_install_local( "-t", target_dir, "singlemodule==0.0.1", "--upgrade" ) - result.did_update(singlemodule_py) + result.did_update("scratch/target/singlemodule.py") @pytest.mark.parametrize("target_option", ["--target", "-t"]) @@ -988,8 +985,7 @@ def test_install_nonlocal_compatible_wheel( ) assert result.returncode == SUCCESS - distinfo = Path("scratch") / "target" / "simplewheel-2.0-1.dist-info" - result.did_create(distinfo) + result.did_create("scratch/target/simplewheel-2.0-1.dist-info") # Test install without --target result = script.pip( @@ -1024,23 +1020,21 @@ def test_install_nonlocal_compatible_wheel_path( target_dir, "--no-index", "--only-binary=:all:", - Path(data.packages) / "simplewheel-2.0-py3-fakeabi-fakeplat.whl", + data.packages / "simplewheel-2.0-py3-fakeabi-fakeplat.whl", expect_error=(resolver_variant == "2020-resolver"), ) if resolver_variant == "2020-resolver": assert result.returncode == ERROR else: assert result.returncode == SUCCESS - - distinfo = Path("scratch") / "target" / "simplewheel-2.0.dist-info" - result.did_create(distinfo) + result.did_create("scratch/target/simplewheel-2.0.dist-info") # Test a full path requirement (without --target) result = script.pip( "install", "--no-index", "--only-binary=:all:", - Path(data.packages) / "simplewheel-2.0-py3-fakeabi-fakeplat.whl", + data.packages / "simplewheel-2.0-py3-fakeabi-fakeplat.whl", expect_error=True, ) assert result.returncode == ERROR @@ -1399,7 +1393,7 @@ def test_compiles_pyc(script: PipTestEnvironment) -> None: # any of them exists = [ os.path.exists(script.site_packages_path / "initools/__init__.pyc"), - *glob.glob(script.site_packages_path / "initools/__pycache__/__init__*.pyc"), + *script.site_packages_path.glob("initools/__pycache__/__init__*.pyc"), ] assert any(exists) @@ -1417,7 +1411,7 @@ def test_no_compiles_pyc(script: PipTestEnvironment) -> None: # any of them exists = [ os.path.exists(script.site_packages_path / "initools/__init__.pyc"), - *glob.glob(script.site_packages_path / "initools/__pycache__/__init__*.pyc"), + *script.site_packages_path.glob("initools/__pycache__/__init__*.pyc"), ] assert not any(exists) @@ -1461,7 +1455,7 @@ def test_install_upgrade_editable_depending_on_other_editable( def test_install_subprocess_output_handling( script: PipTestEnvironment, data: TestData ) -> None: - args = ["install", data.src.joinpath("chattymodule")] + args = ["install", os.fspath(data.src.joinpath("chattymodule"))] # Regular install should not show output from the chatty setup.py result = script.pip(*args) @@ -1486,11 +1480,14 @@ def test_install_subprocess_output_handling( assert 1 == result.stderr.count("I DIE, I DIE") -def test_install_log(script: PipTestEnvironment, data: TestData, tmpdir: Path) -> None: +def test_install_log( + script: PipTestEnvironment, + data: TestData, + tmp_path: pathlib.Path, +) -> None: # test that verbose logs go to "--log" file - f = tmpdir.joinpath("log.txt") - args = [f"--log={f}", "install", data.src.joinpath("chattymodule")] - result = script.pip(*args) + f = tmp_path.joinpath("log.txt") + result = script.pip(f"--log={f}", "install", data.src.joinpath("chattymodule")) assert 0 == result.stdout.count("HELLO FROM CHATTYMODULE") with open(f) as fp: # one from egg_info, one from install @@ -1498,11 +1495,10 @@ def test_install_log(script: PipTestEnvironment, data: TestData, tmpdir: Path) - def test_install_topological_sort(script: PipTestEnvironment, data: TestData) -> None: - args = ["install", "TopoRequires4", "--no-index", "-f", data.packages] - res = str(script.pip(*args)) + res = script.pip("install", "TopoRequires4", "--no-index", "-f", data.packages) order1 = "TopoRequires, TopoRequires2, TopoRequires3, TopoRequires4" order2 = "TopoRequires, TopoRequires3, TopoRequires2, TopoRequires4" - assert order1 in res or order2 in res, res + assert order1 in res.stdout or order2 in res.stdout, str(res) @pytest.mark.usefixtures("with_wheel") @@ -1624,10 +1620,10 @@ def test_install_no_binary_builds_pep_517_wheel( @pytest.mark.network @pytest.mark.usefixtures("with_wheel") def test_install_no_binary_uses_local_backend( - script: PipTestEnvironment, data: TestData, tmpdir: Path + script: PipTestEnvironment, data: TestData, tmp_path: pathlib.Path ) -> None: to_install = data.packages.joinpath("pep517_wrapper_buildsys") - script.environ["PIP_TEST_MARKER_FILE"] = marker = str(tmpdir / "marker") + script.environ["PIP_TEST_MARKER_FILE"] = marker = str(tmp_path / "marker") res = script.pip("install", "--no-binary=:all:", "-f", data.find_links, to_install) expected = "Successfully installed pep517-wrapper-buildsys" # Must have installed the package @@ -1916,15 +1912,18 @@ def test_installed_files_recorded_in_deterministic_order( """ to_install = data.packages.joinpath("FSPkg") result = script.pip("install", to_install) - fspkg_folder = script.site_packages / "fspkg" + fspkg_folder = script.site_packages_path / "fspkg" egg_info = f"FSPkg-0.1.dev0-py{pyversion}.egg-info" - installed_files_path = script.site_packages / egg_info / "installed-files.txt" + installed_files_path = script.site_packages_path.joinpath( + egg_info, + "installed-files.txt", + ) result.did_create(fspkg_folder) result.did_create(installed_files_path) installed_files_path = result.files_created[installed_files_path].full installed_files_lines = [ - p for p in Path(installed_files_path).read_text().split("\n") if p + p for p in installed_files_path.read_text().split("\n") if p ] assert installed_files_lines == sorted(installed_files_lines) @@ -1987,8 +1986,7 @@ def test_target_install_ignores_distutils_config_install_prefix( script: PipTestEnvironment, ) -> None: prefix = script.scratch_path / "prefix" - distutils_config = Path( - os.path.expanduser("~"), + distutils_config = pathlib.Path.home().joinpath( "pydistutils.cfg" if sys.platform == "win32" else ".pydistutils.cfg", ) distutils_config.write_text( @@ -2164,7 +2162,7 @@ def test_install_sends_client_cert( "simple-3.0.tar.gz": "/files/simple-3.0.tar.gz", } ), - file_response(str(data.packages / "simple-3.0.tar.gz")), + file_response(data.packages / "simple-3.0.tar.gz"), ] url = f"https://{server.host}:{server.port}/simple" diff --git a/tests/functional/test_install_cleanup.py b/tests/functional/test_install_cleanup.py index c0ea5a425b9..dbe11497400 100644 --- a/tests/functional/test_install_cleanup.py +++ b/tests/functional/test_install_cleanup.py @@ -1,5 +1,3 @@ -from os.path import exists - import pytest from tests.lib import PipTestEnvironment, TestData @@ -27,7 +25,7 @@ def test_no_clean_option_blocks_cleaning_after_install( # remove it when removing support for --build allow_stderr_warning=True, ) - assert exists(build) + assert build.exists() @pytest.mark.network @@ -36,7 +34,13 @@ def test_pep517_no_legacy_cleanup(script: PipTestEnvironment, data: TestData) -> """Test a PEP 517 failed build does not attempt a legacy cleanup""" to_install = data.packages.joinpath("pep517_wrapper_buildsys") script.environ["PIP_TEST_FAIL_BUILD_WHEEL"] = "1" - res = script.pip("install", "-f", data.find_links, to_install, expect_error=True) + res = script.pip( + "install", + "-f", + data.find_links, + to_install, + expect_error=True, + ) # Must not have built the package expected = "Failed building wheel for pep517-wrapper-buildsys" assert expected in str(res) diff --git a/tests/functional/test_install_config.py b/tests/functional/test_install_config.py index 2e4bb742785..26eab3df946 100644 --- a/tests/functional/test_install_config.py +++ b/tests/functional/test_install_config.py @@ -284,12 +284,8 @@ def test_prompt_for_authentication( server = make_mock_server(ssl_context=ctx) server.mock.side_effect = [ - package_page( - { - "simple-3.0.tar.gz": "/files/simple-3.0.tar.gz", - } - ), - authorization_response(str(data.packages / "simple-3.0.tar.gz")), + package_page({"simple-3.0.tar.gz": "/files/simple-3.0.tar.gz"}), + authorization_response(data.packages / "simple-3.0.tar.gz"), ] url = f"https://{server.host}:{server.port}/simple" @@ -325,12 +321,8 @@ def test_do_not_prompt_for_authentication( server = make_mock_server(ssl_context=ctx) server.mock.side_effect = [ - package_page( - { - "simple-3.0.tar.gz": "/files/simple-3.0.tar.gz", - } - ), - authorization_response(str(data.packages / "simple-3.0.tar.gz")), + package_page({"simple-3.0.tar.gz": "/files/simple-3.0.tar.gz"}), + authorization_response(data.packages / "simple-3.0.tar.gz"), ] url = f"https://{server.host}:{server.port}/simple" @@ -372,13 +364,9 @@ def test_prompt_for_keyring_if_needed( server = make_mock_server(ssl_context=ctx) server.mock.side_effect = [ - package_page( - { - "simple-3.0.tar.gz": "/files/simple-3.0.tar.gz", - } - ), - response(str(data.packages / "simple-3.0.tar.gz")), - response(str(data.packages / "simple-3.0.tar.gz")), + package_page({"simple-3.0.tar.gz": "/files/simple-3.0.tar.gz"}), + response(data.packages / "simple-3.0.tar.gz"), + response(data.packages / "simple-3.0.tar.gz"), ] url = f"https://{server.host}:{server.port}/simple" diff --git a/tests/functional/test_install_direct_url.py b/tests/functional/test_install_direct_url.py index 9d5e0612ea9..1749917cf5a 100644 --- a/tests/functional/test_install_direct_url.py +++ b/tests/functional/test_install_direct_url.py @@ -1,7 +1,7 @@ import pytest from pip._internal.models.direct_url import VcsInfo -from tests.lib import PipTestEnvironment, TestData, _create_test_package, path_to_url +from tests.lib import PipTestEnvironment, TestData, _create_test_package from tests.lib.direct_url import get_created_direct_url @@ -14,8 +14,7 @@ def test_install_find_links_no_direct_url(script: PipTestEnvironment) -> None: @pytest.mark.usefixtures("with_wheel") def test_install_vcs_editable_no_direct_url(script: PipTestEnvironment) -> None: pkg_path = _create_test_package(script, name="testpkg") - args = ["install", "-e", "git+%s#egg=testpkg" % path_to_url(pkg_path)] - result = script.pip(*args) + result = script.pip("install", "-e", f"git+{pkg_path.as_uri()}#egg=testpkg") # legacy editable installs do not generate .dist-info, # hence no direct_url.json assert not get_created_direct_url(result, "testpkg") @@ -24,9 +23,8 @@ def test_install_vcs_editable_no_direct_url(script: PipTestEnvironment) -> None: @pytest.mark.usefixtures("with_wheel") def test_install_vcs_non_editable_direct_url(script: PipTestEnvironment) -> None: pkg_path = _create_test_package(script, name="testpkg") - url = path_to_url(pkg_path) - args = ["install", f"git+{url}#egg=testpkg"] - result = script.pip(*args) + url = pkg_path.as_uri() + result = script.pip("install", f"git+{url}#egg=testpkg") direct_url = get_created_direct_url(result, "testpkg") assert direct_url assert direct_url.url == url @@ -36,9 +34,8 @@ def test_install_vcs_non_editable_direct_url(script: PipTestEnvironment) -> None @pytest.mark.usefixtures("with_wheel") def test_install_archive_direct_url(script: PipTestEnvironment, data: TestData) -> None: - req = "simple @ " + path_to_url(data.packages / "simple-2.0.tar.gz") - assert req.startswith("simple @ file://") - result = script.pip("install", req) + pkg_path = data.packages.joinpath("simple-2.0.tar.gz") + result = script.pip("install", f"simple @ {pkg_path.as_uri()}") assert get_created_direct_url(result, "simple") @@ -58,8 +55,7 @@ def test_install_vcs_constraint_direct_url(script: PipTestEnvironment) -> None: @pytest.mark.usefixtures("with_wheel") def test_install_vcs_constraint_direct_file_url(script: PipTestEnvironment) -> None: pkg_path = _create_test_package(script, name="testpkg") - url = path_to_url(pkg_path) constraints_file = script.scratch_path / "constraints.txt" - constraints_file.write_text(f"git+{url}#egg=testpkg") + constraints_file.write_text(f"git+{pkg_path.as_uri()}#egg=testpkg") result = script.pip("install", "testpkg", "-c", constraints_file) assert get_created_direct_url(result, "testpkg") diff --git a/tests/functional/test_install_extras.py b/tests/functional/test_install_extras.py index c6cef00fa9c..de912545041 100644 --- a/tests/functional/test_install_extras.py +++ b/tests/functional/test_install_extras.py @@ -79,7 +79,7 @@ def test_nonexistent_extra_warns_user_no_wheel( "install", "--no-binary=:all:", "--no-index", - "--find-links=" + data.find_links, + f"--find-links={data.find_links}", "simple[nonexistent]", expect_stderr=True, ) @@ -100,7 +100,7 @@ def test_nonexistent_extra_warns_user_with_wheel( result = script.pip( "install", "--no-index", - "--find-links=" + data.find_links, + f"--find-links={data.find_links}", "simplewheel[nonexistent]", expect_stderr=True, ) @@ -116,7 +116,7 @@ def test_nonexistent_options_listed_in_order( result = script.pip( "install", "--no-index", - "--find-links=" + data.find_links, + f"--find-links={data.find_links}", "simplewheel[nonexistent, nope]", expect_stderr=True, ) @@ -142,7 +142,7 @@ def test_install_fails_if_extra_at_end( result = script.pip( "install", "--no-index", - "--find-links=" + data.find_links, + f"--find-links={data.find_links}", "-r", script.scratch_path / "requirements.txt", expect_error=True, diff --git a/tests/functional/test_install_index.py b/tests/functional/test_install_index.py index a492863b542..6c3c901a443 100644 --- a/tests/functional/test_install_index.py +++ b/tests/functional/test_install_index.py @@ -1,4 +1,3 @@ -import os import shutil import textwrap import urllib.parse @@ -47,13 +46,11 @@ def test_find_links_requirements_file_relative_path( """Test find-links as a relative path to a reqs file.""" script.scratch_path.joinpath("test-req.txt").write_text( textwrap.dedent( - """ + f""" --no-index - --find-links={} + --find-links={data.packages.as_posix()} parent==0.1 - """.format( - data.packages.replace(os.path.sep, "/") - ) + """ ) ) result = script.pip( diff --git a/tests/functional/test_install_reqs.py b/tests/functional/test_install_reqs.py index a7f2f46be94..1bce55141ad 100644 --- a/tests/functional/test_install_reqs.py +++ b/tests/functional/test_install_reqs.py @@ -1,5 +1,6 @@ import json import os +import pathlib import textwrap from typing import Any, Callable @@ -13,15 +14,13 @@ create_basic_sdist_for_package, create_basic_wheel_for_package, need_svn, - path_to_url, requirements_file, ) from tests.lib.local_repos import local_checkout -from tests.lib.path import Path class ArgRecordingSdist: - def __init__(self, sdist_path: Path, args_path: Path) -> None: + def __init__(self, sdist_path: pathlib.Path, args_path: pathlib.Path) -> None: self.sdist_path = sdist_path self._args_path = args_path @@ -100,7 +99,12 @@ def test_schema_check_in_requirements_file(script: PipTestEnvironment) -> None: ) with pytest.raises(AssertionError): - script.pip("install", "-vvv", "-r", script.scratch_path / "file-egg-req.txt") + script.pip( + "install", + "-vvv", + "-r", + script.scratch_path / "file-egg-req.txt", + ) @pytest.mark.parametrize( @@ -128,19 +132,16 @@ def test_relative_requirements_file( package_folder = script.site_packages / "fspkg" # Compute relative install path to FSPkg from scratch path. - full_rel_path = os.path.relpath( - data.packages.joinpath("FSPkg"), script.scratch_path - ) - full_rel_url = "file:" + full_rel_path + "#egg=FSPkg" + full_rel_path = data.packages.joinpath("FSPkg").relative_to(script.scratch_path) + full_rel_url = f"{full_rel_path.as_uri()}#egg=FSPkg" embedded_rel_path = script.scratch_path.joinpath(full_rel_path) req_path = { - "rel_path": full_rel_path, + "rel_path": full_rel_path.as_posix(), "rel_url": full_rel_url, - "embedded_rel_path": embedded_rel_path, + "embedded_rel_path": embedded_rel_path.as_posix(), }[test_type] - req_path = req_path.replace(os.path.sep, "/") # Install as either editable or not. if not editable: with requirements_file(req_path + "\n", script.scratch_path) as reqs_file: @@ -163,7 +164,10 @@ def test_relative_requirements_file( @pytest.mark.network @need_svn @pytest.mark.usefixtures("with_wheel") -def test_multiple_requirements_files(script: PipTestEnvironment, tmpdir: Path) -> None: +def test_multiple_requirements_files( + script: PipTestEnvironment, + tmp_path: pathlib.Path, +) -> None: """ Test installing from multiple nested requirements files. @@ -176,7 +180,7 @@ def test_multiple_requirements_files(script: PipTestEnvironment, tmpdir: Path) - -r {}-req.txt """ ).format( - local_checkout("svn+http://svn.colorstudy.com/INITools", tmpdir), + local_checkout("svn+http://svn.colorstudy.com/INITools", tmp_path), other_lib_name, ), ) @@ -264,7 +268,9 @@ def test_install_local_editable_with_extras( ) -> None: to_install = data.packages.joinpath("LocalExtras") res = script.pip_install_local( - "-e", to_install + "[bar]", allow_stderr_warning=True + "-e", + f"{to_install}[bar]", + allow_stderr_warning=True, ) res.did_update(script.site_packages / "easy-install.pth") res.did_create(script.site_packages / "LocalExtras.egg-link") @@ -281,13 +287,11 @@ def test_install_collected_dependencies_first(script: PipTestEnvironment) -> Non @pytest.mark.network def test_install_local_editable_with_subdirectory(script: PipTestEnvironment) -> None: - version_pkg_path = _create_test_package_with_subdirectory(script, "version_subdir") + uri = _create_test_package_with_subdirectory(script, "version_subdir").as_uri() result = script.pip( "install", "-e", - "{uri}#egg=version_subpkg&subdirectory=version_subdir".format( - uri="git+" + path_to_url(version_pkg_path), - ), + f"git+{uri}#egg=version_subpkg&subdirectory=version_subdir", ) result.assert_installed("version-subpkg", sub_dir="version_subdir") @@ -295,12 +299,10 @@ def test_install_local_editable_with_subdirectory(script: PipTestEnvironment) -> @pytest.mark.network def test_install_local_with_subdirectory(script: PipTestEnvironment) -> None: - version_pkg_path = _create_test_package_with_subdirectory(script, "version_subdir") + uri = _create_test_package_with_subdirectory(script, "version_subdir").as_uri() result = script.pip( "install", - "{uri}#egg=version_subpkg&subdirectory=version_subdir".format( - uri="git+" + path_to_url(version_pkg_path), - ), + f"git+{uri}#egg=version_subpkg&subdirectory=version_subdir", ) result.assert_installed("version_subpkg.py", editable=False) @@ -347,9 +349,9 @@ def test_install_option_in_requirements_file_overrides_cli( "install", "--no-index", "-f", - str(simple_sdist.sdist_path.parent), + simple_sdist.sdist_path.parent, "-r", - str(reqs_file), + reqs_file, "--install-option=-O1", allow_stderr_warning=True, ) @@ -456,7 +458,7 @@ def test_constraints_constrain_to_local_editable( ) -> None: to_install = data.src.joinpath("singlemodule") script.scratch_path.joinpath("constraints.txt").write_text( - "-e {url}#egg=singlemodule".format(url=path_to_url(to_install)) + f"-e {to_install.as_uri()}#egg=singlemodule" ) result = script.pip( "install", @@ -480,7 +482,7 @@ def test_constraints_constrain_to_local( ) -> None: to_install = data.src.joinpath("singlemodule") script.scratch_path.joinpath("constraints.txt").write_text( - "{url}#egg=singlemodule".format(url=path_to_url(to_install)) + f"{to_install.as_uri()}#egg=singlemodule" ) result = script.pip( "install", @@ -499,7 +501,7 @@ def test_constrained_to_url_install_same_url( script: PipTestEnvironment, data: TestData ) -> None: to_install = data.src.joinpath("singlemodule") - constraints = path_to_url(to_install) + "#egg=singlemodule" + constraints = f"{to_install.as_uri()}#egg=singlemodule" script.scratch_path.joinpath("constraints.txt").write_text(constraints) result = script.pip( "install", @@ -516,7 +518,7 @@ def test_constrained_to_url_install_same_url( @pytest.mark.usefixtures("with_wheel") def test_double_install_spurious_hash_mismatch( - script: PipTestEnvironment, tmpdir: Path, data: TestData + script: PipTestEnvironment, tmp_path: pathlib.Path, data: TestData ) -> None: """Make sure installing the same hashed sdist twice doesn't throw hash mismatch errors. @@ -531,7 +533,7 @@ def test_double_install_spurious_hash_mismatch( with requirements_file( "simple==1.0 --hash=sha256:393043e672415891885c9a2a" "0929b1af95fb866d6ca016b42d2e6ce53619b653", - tmpdir, + tmp_path, ) as reqs_file: # Install a package (and build its wheel): result = script.pip_install_local( @@ -561,7 +563,7 @@ def test_install_with_extras_from_constraints( ) -> None: to_install = data.packages.joinpath("LocalExtras") script.scratch_path.joinpath("constraints.txt").write_text( - "{url}#egg=LocalExtras[bar]".format(url=path_to_url(to_install)) + f"{to_install.as_uri()}#egg=LocalExtras[bar]" ) result = script.pip_install_local( "-c", @@ -599,7 +601,7 @@ def test_install_with_extras_joined( ) -> None: to_install = data.packages.joinpath("LocalExtras") script.scratch_path.joinpath("constraints.txt").write_text( - "{url}#egg=LocalExtras[bar]".format(url=path_to_url(to_install)) + f"{to_install.as_uri()}#egg=LocalExtras[bar]" ) result = script.pip_install_local( "-c", @@ -620,7 +622,7 @@ def test_install_with_extras_editable_joined( ) -> None: to_install = data.packages.joinpath("LocalExtras") script.scratch_path.joinpath("constraints.txt").write_text( - "-e {url}#egg=LocalExtras[bar]".format(url=path_to_url(to_install)) + f"-e {to_install.as_uri()}#egg=LocalExtras[bar]" ) result = script.pip_install_local( "-c", @@ -641,7 +643,7 @@ def test_install_distribution_full_union( ) -> None: to_install = data.packages.joinpath("LocalExtras") result = script.pip_install_local( - to_install, to_install + "[bar]", to_install + "[baz]" + to_install, f"{to_install}[bar]", f"{to_install}[baz]" ) assert "Running setup.py install for LocalExtras" in result.stdout result.did_create(script.site_packages / "simple") @@ -652,7 +654,7 @@ def test_install_distribution_duplicate_extras( script: PipTestEnvironment, data: TestData ) -> None: to_install = data.packages.joinpath("LocalExtras") - package_name = to_install + "[bar]" + package_name = f"{to_install}[bar]" with pytest.raises(AssertionError): result = script.pip_install_local(package_name, package_name) expected = f"Double requirement given: {package_name}" @@ -669,7 +671,7 @@ def test_install_distribution_union_with_constraints( result = script.pip_install_local( "-c", script.scratch_path / "constraints.txt", - to_install + "[baz]", + f"{to_install}[baz]", allow_stderr_warning=True, expect_error=(resolver_variant == "2020-resolver"), ) @@ -689,8 +691,8 @@ def test_install_distribution_union_with_versions( to_install_001 = data.packages.joinpath("LocalExtras") to_install_002 = data.packages.joinpath("LocalExtras-0.0.2") result = script.pip_install_local( - to_install_001 + "[bar]", - to_install_002 + "[baz]", + f"{to_install_001}[bar]", + f"{to_install_002}[baz]", expect_error=(resolver_variant == "2020-resolver"), ) if resolver_variant == "2020-resolver": @@ -713,7 +715,7 @@ def test_install_distribution_union_conflicting_extras( # detected. to_install = data.packages.joinpath("LocalExtras-0.0.2") result = script.pip_install_local( - to_install, to_install + "[bar]", expect_error=True + to_install, f"{to_install}[bar]", expect_error=True ) assert "installed" not in result.stdout assert "Conflict" in result.stderr @@ -745,7 +747,7 @@ def test_install_unsupported_wheel_file( # Trying to install a local wheel with an incompatible version/type # should fail. path = data.packages.joinpath("simple.dist-0.1-py1-none-invalid.whl") - script.scratch_path.joinpath("wheel-file.txt").write_text(path + "\n") + script.scratch_path.joinpath("wheel-file.txt").write_text(f"{path}\n") result = script.pip( "install", "-r", @@ -788,7 +790,7 @@ def test_install_options_local_to_package( "install", "--no-index", "-f", - str(simple1_sdist.sdist_path.parent), + simple1_sdist.sdist_path.parent, "-r", reqs_file, allow_stderr_warning=True, @@ -810,7 +812,7 @@ def test_location_related_install_option_fails(script: PipTestEnvironment) -> No "install", "--no-index", "-f", - str(simple_sdist.parent), + simple_sdist.parent, "-r", reqs_file, expect_error=True, diff --git a/tests/functional/test_install_upgrade.py b/tests/functional/test_install_upgrade.py index 3dab9161e80..73f9ebcf850 100644 --- a/tests/functional/test_install_upgrade.py +++ b/tests/functional/test_install_upgrade.py @@ -1,5 +1,6 @@ import itertools import os +import pathlib import sys import textwrap @@ -8,7 +9,6 @@ from tests.lib import pyversion # noqa: F401 from tests.lib import PipTestEnvironment, ResolverVariant, TestData, assert_all_changes from tests.lib.local_repos import local_checkout -from tests.lib.path import Path from tests.lib.wheel import make_wheel @@ -262,7 +262,11 @@ def test_upgrade_from_reqs_file(script: PipTestEnvironment) -> None: """ ) ) - install_result = script.pip("install", "-r", script.scratch_path / "test-req.txt") + install_result = script.pip( + "install", + "-r", + str(script.scratch_path / "test-req.txt"), + ) script.scratch_path.joinpath("test-req.txt").write_text( textwrap.dedent( """\ @@ -272,7 +276,7 @@ def test_upgrade_from_reqs_file(script: PipTestEnvironment) -> None: """ ) ) - script.pip("install", "--upgrade", "-r", script.scratch_path / "test-req.txt") + script.pip("install", "--upgrade", "-r", str(script.scratch_path / "test-req.txt")) uninstall_result = script.pip( "uninstall", "-r", script.scratch_path / "test-req.txt", "-y" ) @@ -341,13 +345,14 @@ def test_install_with_ignoreinstalled_requested(script: PipTestEnvironment) -> N @pytest.mark.network def test_upgrade_vcs_req_with_no_dists_found( - script: PipTestEnvironment, tmpdir: Path + script: PipTestEnvironment, + tmp_path: pathlib.Path, ) -> None: """It can upgrade a VCS requirement that has no distributions otherwise.""" req = "{checkout}#egg=pip-test-package".format( checkout=local_checkout( "git+https://github.com/pypa/pip-test-package.git", - tmpdir, + tmp_path, ) ) script.pip("install", req) diff --git a/tests/functional/test_install_user.py b/tests/functional/test_install_user.py index 8657bc3ef2f..1d33bf52da5 100644 --- a/tests/functional/test_install_user.py +++ b/tests/functional/test_install_user.py @@ -1,6 +1,7 @@ """ tests specific to "pip install --user" """ +import pathlib import textwrap from os.path import curdir, isdir, isfile @@ -9,7 +10,6 @@ from tests.lib import pyversion # noqa: F401 from tests.lib import PipTestEnvironment, TestData, need_svn from tests.lib.local_repos import local_checkout -from tests.lib.path import Path from tests.lib.venv import VirtualEnvironment @@ -53,21 +53,20 @@ def test_reset_env_system_site_packages_usersite( @need_svn @pytest.mark.incompatible_with_test_venv def test_install_subversion_usersite_editable_with_distribute( - self, script: PipTestEnvironment, tmpdir: Path + self, + script: PipTestEnvironment, + tmp_path: pathlib.Path, ) -> None: """ Test installing current directory ('.') into usersite after installing distribute """ + checkout = local_checkout("svn+http://svn.colorstudy.com/INITools", tmp_path) result = script.pip( "install", "--user", "-e", - "{checkout}#egg=initools".format( - checkout=local_checkout( - "svn+http://svn.colorstudy.com/INITools", tmpdir - ) - ), + f"{checkout}#egg=initools", ) result.assert_installed("INITools", use_user_site=True) diff --git a/tests/functional/test_install_vcs_git.py b/tests/functional/test_install_vcs_git.py index 04413c86d4b..cb5bd5e2b35 100644 --- a/tests/functional/test_install_vcs_git.py +++ b/tests/functional/test_install_vcs_git.py @@ -1,25 +1,26 @@ +import pathlib from typing import Optional import pytest -from pip._internal.utils.urls import path_to_url from tests.lib import pyversion # noqa: F401 from tests.lib import ( PipTestEnvironment, _change_test_package_version, _create_test_package, - _test_path_to_file_url, ) from tests.lib.git_submodule_helpers import ( - _change_test_package_submodule, - _create_test_package_with_submodule, - _pull_in_submodule_changes_to_module, + change_test_package_submodule, + create_test_package_with_submodule, + pull_in_submodule_changes_to_module, ) from tests.lib.local_repos import local_checkout -from tests.lib.path import Path -def _get_editable_repo_dir(script: PipTestEnvironment, package_name: str) -> Path: +def _get_editable_repo_dir( + script: PipTestEnvironment, + package_name: str, +) -> pathlib.Path: """ Return the repository directory for an editable install. """ @@ -46,7 +47,7 @@ def _get_branch_remote( def _github_checkout( url_path: str, - temp_dir: Path, + temp_path: pathlib.Path, rev: Optional[str] = None, egg: Optional[str] = None, scheme: Optional[str] = None, @@ -65,7 +66,7 @@ def _github_checkout( if scheme is None: scheme = "https" url = f"git+{scheme}://github.com/{url_path}" - local_url = local_checkout(url, temp_dir) + local_url = local_checkout(url, temp_path) if rev is not None: local_url += f"@{rev}" if egg is not None: @@ -75,7 +76,7 @@ def _github_checkout( def _make_version_pkg_url( - path: Path, rev: Optional[str] = None, name: str = "version_pkg" + path: pathlib.Path, rev: Optional[str] = None, name: str = "version_pkg" ) -> str: """ Return a "git+file://" URL to the version_pkg test package. @@ -85,16 +86,13 @@ def _make_version_pkg_url( containing the version_pkg package. rev: an optional revision to install like a branch name, tag, or SHA. """ - file_url = _test_path_to_file_url(path) url_rev = "" if rev is None else f"@{rev}" - url = f"git+{file_url}{url_rev}#egg={name}" - - return url + return f"git+{path.as_uri()}{url_rev}#egg={name}" def _install_version_pkg_only( script: PipTestEnvironment, - path: Path, + path: pathlib.Path, rev: Optional[str] = None, expect_stderr: bool = False, ) -> None: @@ -113,7 +111,7 @@ def _install_version_pkg_only( def _install_version_pkg( script: PipTestEnvironment, - path: Path, + path: pathlib.Path, rev: Optional[str] = None, expect_stderr: bool = False, ) -> str: @@ -174,13 +172,13 @@ def test_git_install_branch_again_after_branch_changes( @pytest.mark.network def test_install_editable_from_git_with_https( - script: PipTestEnvironment, tmpdir: Path + script: PipTestEnvironment, tmp_path: pathlib.Path ) -> None: """ Test cloning from Git with https. """ url_path = "pypa/pip-test-package.git" - local_url = _github_checkout(url_path, tmpdir, egg="pip-test-package") + local_url = _github_checkout(url_path, tmp_path, egg="pip-test-package") result = script.pip("install", "-e", local_url) result.assert_installed("pip-test-package", with_files=[".git"]) @@ -256,7 +254,7 @@ def test_git_with_tag_name_as_revision(script: PipTestEnvironment) -> None: assert "0.1" == version -def _add_ref(script: PipTestEnvironment, path: Path, ref: str) -> None: +def _add_ref(script: PipTestEnvironment, path: pathlib.Path, ref: str) -> None: """ Add a new ref to a repository at the given path. """ @@ -316,13 +314,16 @@ def test_git_install_then_install_ref(script: PipTestEnvironment) -> None: ], ) def test_install_git_logs_commit_sha( - script: PipTestEnvironment, rev: str, expected_sha: str, tmpdir: Path + script: PipTestEnvironment, + rev: str, + expected_sha: str, + tmp_path: pathlib.Path, ) -> None: """ Test installing from a git repository logs a commit SHA. """ url_path = "pypa/pip-test-package.git" - base_local_url = _github_checkout(url_path, tmpdir) + base_local_url = _github_checkout(url_path, tmp_path) local_url = f"{base_local_url}{rev}#egg=pip-test-package" result = script.pip("install", local_url) # `[4:]` removes a 'git+' prefix @@ -330,12 +331,15 @@ def test_install_git_logs_commit_sha( @pytest.mark.network -def test_git_with_tag_name_and_update(script: PipTestEnvironment, tmpdir: Path) -> None: +def test_git_with_tag_name_and_update( + script: PipTestEnvironment, + tmp_path: pathlib.Path, +) -> None: """ Test cloning a git repository and updating to a different version. """ url_path = "pypa/pip-test-package.git" - base_local_url = _github_checkout(url_path, tmpdir) + base_local_url = _github_checkout(url_path, tmp_path) local_url = f"{base_local_url}#egg=pip-test-package" result = script.pip("install", "-e", local_url) @@ -354,14 +358,14 @@ def test_git_with_tag_name_and_update(script: PipTestEnvironment, tmpdir: Path) @pytest.mark.network def test_git_branch_should_not_be_changed( - script: PipTestEnvironment, tmpdir: Path + script: PipTestEnvironment, tmp_path: pathlib.Path ) -> None: """ Editable installations should not change branch related to issue #32 and #161 """ url_path = "pypa/pip-test-package.git" - local_url = _github_checkout(url_path, tmpdir, egg="pip-test-package") + local_url = _github_checkout(url_path, tmp_path, egg="pip-test-package") script.pip("install", "-e", local_url) branch = _get_editable_branch(script, "pip-test-package") assert "master" == branch @@ -369,7 +373,7 @@ def test_git_branch_should_not_be_changed( @pytest.mark.network def test_git_with_non_editable_unpacking( - script: PipTestEnvironment, tmpdir: Path + script: PipTestEnvironment, tmp_path: pathlib.Path ) -> None: """ Test cloning a git repository from a non-editable URL with a given tag. @@ -377,7 +381,7 @@ def test_git_with_non_editable_unpacking( url_path = "pypa/pip-test-package.git" local_url = _github_checkout( url_path, - tmpdir, + tmp_path, rev="0.1.2", egg="pip-test-package", ) @@ -392,7 +396,7 @@ def test_git_with_non_editable_unpacking( @pytest.mark.network def test_git_with_editable_where_egg_contains_dev_string( - script: PipTestEnvironment, tmpdir: Path + script: PipTestEnvironment, tmp_path: pathlib.Path ) -> None: """ Test cloning a git repository from an editable url which contains "dev" @@ -401,7 +405,7 @@ def test_git_with_editable_where_egg_contains_dev_string( url_path = "dcramer/django-devserver.git" local_url = _github_checkout( url_path, - tmpdir, + tmp_path, egg="django-devserver", scheme="https", ) @@ -411,7 +415,7 @@ def test_git_with_editable_where_egg_contains_dev_string( @pytest.mark.network def test_git_with_non_editable_where_egg_contains_dev_string( - script: PipTestEnvironment, tmpdir: Path + script: PipTestEnvironment, tmp_path: pathlib.Path ) -> None: """ Test cloning a git repository from a non-editable url which contains "dev" @@ -420,7 +424,7 @@ def test_git_with_non_editable_where_egg_contains_dev_string( url_path = "dcramer/django-devserver.git" local_url = _github_checkout( url_path, - tmpdir, + tmp_path, egg="django-devserver", scheme="https", ) @@ -538,17 +542,17 @@ def test_check_submodule_addition(script: PipTestEnvironment) -> None: """ Submodules are pulled in on install and updated on upgrade. """ - module_path, submodule_path = _create_test_package_with_submodule( + module_path, submodule_path = create_test_package_with_submodule( script, rel_path="testpkg/static" ) install_result = script.pip( - "install", "-e", "git+" + path_to_url(module_path) + "#egg=version_pkg" + "install", "-e", f"git+{module_path.as_uri()}#egg=version_pkg" ) install_result.did_create(script.venv / "src/version-pkg/testpkg/static/testfile") - _change_test_package_submodule(script, submodule_path) - _pull_in_submodule_changes_to_module( + change_test_package_submodule(script, submodule_path) + pull_in_submodule_changes_to_module( script, module_path, rel_path="testpkg/static", @@ -558,7 +562,7 @@ def test_check_submodule_addition(script: PipTestEnvironment) -> None: update_result = script.pip( "install", "-e", - "git+" + path_to_url(module_path) + "#egg=version_pkg", + f"git+{module_path.as_uri()}#egg=version_pkg", "--upgrade", ) diff --git a/tests/functional/test_install_wheel.py b/tests/functional/test_install_wheel.py index 86c5e5fbeb2..db89126e461 100644 --- a/tests/functional/test_install_wheel.py +++ b/tests/functional/test_install_wheel.py @@ -1,14 +1,13 @@ import csv import distutils -import glob import os +import pathlib import shutil from typing import Any import pytest from tests.lib import PipTestEnvironment, TestData, create_basic_wheel_for_package -from tests.lib.path import Path from tests.lib.wheel import WheelBuilder, make_wheel @@ -20,7 +19,7 @@ def make_wheel_with_file(name: str, version: str, **kwargs: Any) -> WheelBuilder def test_install_from_future_wheel_version( - script: PipTestEnvironment, tmpdir: Path + script: PipTestEnvironment, tmp_path: pathlib.Path ) -> None: """ Test installing a wheel with a WHEEL metadata version that is: @@ -33,7 +32,7 @@ def test_install_from_future_wheel_version( name="futurewheel", version="3.0", wheel_metadata_updates={"Wheel-Version": "3.0"}, - ).save_to_dir(tmpdir) + ).save_to_dir(tmp_path) result = script.pip("install", package, "--no-index", expect_error=True) with pytest.raises(TestFailure): @@ -43,7 +42,7 @@ def test_install_from_future_wheel_version( name="futurewheel", version="1.9", wheel_metadata_updates={"Wheel-Version": "1.9"}, - ).save_to_dir(tmpdir) + ).save_to_dir(tmp_path) result = script.pip("install", package, "--no-index", expect_stderr=True) result.assert_installed("futurewheel", without_egg_link=True, editable=False) @@ -70,18 +69,18 @@ def test_install_from_broken_wheel( def test_basic_install_from_wheel( - script: PipTestEnvironment, shared_data: TestData, tmpdir: Path + script: PipTestEnvironment, shared_data: TestData, tmp_path: pathlib.Path ) -> None: """ Test installing from a wheel (that has a script) """ - shutil.copy(shared_data.packages / "has.script-1.0-py2.py3-none-any.whl", tmpdir) + shutil.copy(shared_data.packages / "has.script-1.0-py2.py3-none-any.whl", tmp_path) result = script.pip( "install", "has.script==1.0", "--no-index", "--find-links", - tmpdir, + tmp_path, ) dist_info_folder = script.site_packages / "has.script-1.0.dist-info" result.did_create(dist_info_folder) @@ -90,19 +89,22 @@ def test_basic_install_from_wheel( def test_basic_install_from_wheel_with_extras( - script: PipTestEnvironment, shared_data: TestData, tmpdir: Path + script: PipTestEnvironment, shared_data: TestData, tmp_path: pathlib.Path ) -> None: """ Test installing from a wheel with extras. """ - shutil.copy(shared_data.packages / "complex_dist-0.1-py2.py3-none-any.whl", tmpdir) - shutil.copy(shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmpdir) + shutil.copy( + shared_data.packages / "complex_dist-0.1-py2.py3-none-any.whl", + tmp_path, + ) + shutil.copy(shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmp_path) result = script.pip( "install", "complex-dist[simple]", "--no-index", "--find-links", - tmpdir, + tmp_path, ) dist_info_folder = script.site_packages / "complex_dist-0.1.dist-info" result.did_create(dist_info_folder) @@ -165,14 +167,14 @@ def test_basic_install_from_unicode_wheel( def get_header_scheme_path_for_script( script: PipTestEnvironment, dist_name: str -) -> Path: +) -> pathlib.Path: command = ( - "from pip._internal.locations import get_scheme;" - "scheme = get_scheme({!r});" - "print(scheme.headers);" - ).format(dist_name) + f"from pip._internal.locations import get_scheme;" + f"scheme = get_scheme({dist_name!r});" + f"print(scheme.headers);" + ) result = script.run("python", "-c", command).stdout - return Path(result.strip()) + return pathlib.Path(result.strip()) def test_install_from_wheel_with_headers(script: PipTestEnvironment) -> None: @@ -196,12 +198,12 @@ def test_install_from_wheel_with_headers(script: PipTestEnvironment) -> None: @pytest.mark.usefixtures("with_wheel") def test_install_wheel_with_target( - script: PipTestEnvironment, shared_data: TestData, tmpdir: Path + script: PipTestEnvironment, shared_data: TestData, tmp_path: pathlib.Path ) -> None: """ Test installing a wheel using pip install --target """ - shutil.copy(shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmpdir) + shutil.copy(shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmp_path) target_dir = script.scratch_path / "target" result = script.pip( "install", @@ -210,9 +212,9 @@ def test_install_wheel_with_target( target_dir, "--no-index", "--find-links", - tmpdir, + tmp_path, ) - result.did_create(Path("scratch") / "target" / "simpledist") + result.did_create("scratch/target/simpledist") @pytest.mark.usefixtures("with_wheel") @@ -240,20 +242,20 @@ def test_install_wheel_with_target_and_data_files( target_dir = script.scratch_path / "prjwithdatafile" package = data.packages.joinpath("prjwithdatafile-1.0-py2.py3-none-any.whl") result = script.pip("install", package, "-t", target_dir, "--no-index") - project_path = Path("scratch") / "prjwithdatafile" + project_path = pathlib.Path("scratch", "prjwithdatafile") result.did_create(project_path / "packages1" / "README.txt") result.did_create(project_path / "packages2" / "README.txt") result.did_not_create(project_path / "lib" / "python") def test_install_wheel_with_root( - script: PipTestEnvironment, shared_data: TestData, tmpdir: Path + script: PipTestEnvironment, shared_data: TestData, tmp_path: pathlib.Path ) -> None: """ Test installing a wheel using pip install --root """ root_dir = script.scratch_path / "root" - shutil.copy(shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmpdir) + shutil.copy(shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmp_path) result = script.pip( "install", "simple.dist==0.1", @@ -261,19 +263,19 @@ def test_install_wheel_with_root( root_dir, "--no-index", "--find-links", - tmpdir, + tmp_path, ) - result.did_create(Path("scratch") / "root") + result.did_create("scratch/root") def test_install_wheel_with_prefix( - script: PipTestEnvironment, shared_data: TestData, tmpdir: Path + script: PipTestEnvironment, shared_data: TestData, tmp_path: pathlib.Path ) -> None: """ Test installing a wheel using pip install --prefix """ prefix_dir = script.scratch_path / "prefix" - shutil.copy(shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmpdir) + shutil.copy(shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmp_path) result = script.pip( "install", "simple.dist==0.1", @@ -281,45 +283,45 @@ def test_install_wheel_with_prefix( prefix_dir, "--no-index", "--find-links", - tmpdir, + tmp_path, ) - lib = distutils.sysconfig.get_python_lib(prefix=Path("scratch") / "prefix") + lib = distutils.sysconfig.get_python_lib(prefix="scratch/prefix") result.did_create(lib) def test_install_from_wheel_installs_deps( - script: PipTestEnvironment, data: TestData, tmpdir: Path + script: PipTestEnvironment, data: TestData, tmp_path: pathlib.Path ) -> None: """ Test can install dependencies of wheels """ # 'requires_source' depends on the 'source' project package = data.packages.joinpath("requires_source-1.0-py2.py3-none-any.whl") - shutil.copy(data.packages / "source-1.0.tar.gz", tmpdir) + shutil.copy(data.packages / "source-1.0.tar.gz", tmp_path) result = script.pip( "install", "--no-index", "--find-links", - tmpdir, + tmp_path, package, ) result.assert_installed("source", editable=False) def test_install_from_wheel_no_deps( - script: PipTestEnvironment, data: TestData, tmpdir: Path + script: PipTestEnvironment, data: TestData, tmp_path: pathlib.Path ) -> None: """ Test --no-deps works with wheel installs """ # 'requires_source' depends on the 'source' project package = data.packages.joinpath("requires_source-1.0-py2.py3-none-any.whl") - shutil.copy(data.packages / "source-1.0.tar.gz", tmpdir) + shutil.copy(data.packages / "source-1.0.tar.gz", tmp_path) result = script.pip( "install", "--no-index", "--find-links", - tmpdir, + tmp_path, "--no-deps", package, ) @@ -340,7 +342,7 @@ def test_wheel_record_lines_in_deterministic_order( result.did_create(record_path) record_path = result.files_created[record_path].full - record_lines = [p for p in Path(record_path).read_text().split("\n") if p] + record_lines = [p for p in pathlib.Path(record_path).read_text().split("\n") if p] assert record_lines == sorted(record_lines) @@ -368,19 +370,19 @@ def test_wheel_record_lines_have_hash_for_data_files( @pytest.mark.incompatible_with_test_venv @pytest.mark.usefixtures("with_wheel") def test_install_user_wheel( - script: PipTestEnvironment, shared_data: TestData, tmpdir: Path + script: PipTestEnvironment, shared_data: TestData, tmp_path: pathlib.Path ) -> None: """ Test user install from wheel (that has a script) """ - shutil.copy(shared_data.packages / "has.script-1.0-py2.py3-none-any.whl", tmpdir) + shutil.copy(shared_data.packages / "has.script-1.0-py2.py3-none-any.whl", tmp_path) result = script.pip( "install", "has.script==1.0", "--user", "--no-index", "--find-links", - tmpdir, + tmp_path, ) dist_info_folder = script.user_site / "has.script-1.0.dist-info" result.did_create(dist_info_folder) @@ -389,21 +391,21 @@ def test_install_user_wheel( def test_install_from_wheel_gen_entrypoint( - script: PipTestEnvironment, shared_data: TestData, tmpdir: Path + script: PipTestEnvironment, shared_data: TestData, tmp_path: pathlib.Path ) -> None: """ Test installing scripts (entry points are generated) """ shutil.copy( shared_data.packages / "script.wheel1a-0.1-py2.py3-none-any.whl", - tmpdir, + tmp_path, ) result = script.pip( "install", "script.wheel1a==0.1", "--no-index", "--find-links", - tmpdir, + tmp_path, ) if os.name == "nt": wrapper_file = script.bin / "t1.exe" @@ -416,21 +418,21 @@ def test_install_from_wheel_gen_entrypoint( def test_install_from_wheel_gen_uppercase_entrypoint( - script: PipTestEnvironment, shared_data: TestData, tmpdir: Path + script: PipTestEnvironment, shared_data: TestData, tmp_path: pathlib.Path ) -> None: """ Test installing scripts with uppercase letters in entry point names """ shutil.copy( shared_data.packages / "console_scripts_uppercase-1.0-py2.py3-none-any.whl", - tmpdir, + tmp_path, ) result = script.pip( "install", "console-scripts-uppercase==1.0", "--no-index", "--find-links", - tmpdir, + tmp_path, ) if os.name == "nt": # Case probably doesn't make any difference on NT @@ -464,21 +466,21 @@ def test_install_from_wheel_gen_unicode_entrypoint(script: PipTestEnvironment) - def test_install_from_wheel_with_legacy( - script: PipTestEnvironment, shared_data: TestData, tmpdir: Path + script: PipTestEnvironment, shared_data: TestData, tmp_path: pathlib.Path ) -> None: """ Test installing scripts (legacy scripts are preserved) """ shutil.copy( shared_data.packages / "script.wheel2a-0.1-py2.py3-none-any.whl", - tmpdir, + tmp_path, ) result = script.pip( "install", "script.wheel2a==0.1", "--no-index", "--find-links", - tmpdir, + tmp_path, ) legacy_file1 = script.bin / "testscript1.bat" @@ -489,19 +491,22 @@ def test_install_from_wheel_with_legacy( def test_install_from_wheel_no_setuptools_entrypoint( - script: PipTestEnvironment, shared_data: TestData, tmpdir: Path + script: PipTestEnvironment, shared_data: TestData, tmp_path: pathlib.Path ) -> None: """ Test that when we generate scripts, any existing setuptools wrappers in the wheel are skipped. """ - shutil.copy(shared_data.packages / "script.wheel1-0.1-py2.py3-none-any.whl", tmpdir) + shutil.copy( + shared_data.packages / "script.wheel1-0.1-py2.py3-none-any.whl", + tmp_path, + ) result = script.pip( "install", "script.wheel1==0.1", "--no-index", "--find-links", - tmpdir, + tmp_path, ) if os.name == "nt": wrapper_file = script.bin / "t1.exe" @@ -519,19 +524,22 @@ def test_install_from_wheel_no_setuptools_entrypoint( def test_skipping_setuptools_doesnt_skip_legacy( - script: PipTestEnvironment, shared_data: TestData, tmpdir: Path + script: PipTestEnvironment, shared_data: TestData, tmp_path: pathlib.Path ) -> None: """ Test installing scripts (legacy scripts are preserved even when we skip setuptools wrappers) """ - shutil.copy(shared_data.packages / "script.wheel2-0.1-py2.py3-none-any.whl", tmpdir) + shutil.copy( + shared_data.packages / "script.wheel2-0.1-py2.py3-none-any.whl", + tmp_path, + ) result = script.pip( "install", "script.wheel2==0.1", "--no-index", "--find-links", - tmpdir, + tmp_path, ) legacy_file1 = script.bin / "testscript1.bat" @@ -544,18 +552,21 @@ def test_skipping_setuptools_doesnt_skip_legacy( def test_install_from_wheel_gui_entrypoint( - script: PipTestEnvironment, shared_data: TestData, tmpdir: Path + script: PipTestEnvironment, shared_data: TestData, tmp_path: pathlib.Path ) -> None: """ Test installing scripts (gui entry points are generated) """ - shutil.copy(shared_data.packages / "script.wheel3-0.1-py2.py3-none-any.whl", tmpdir) + shutil.copy( + shared_data.packages / "script.wheel3-0.1-py2.py3-none-any.whl", + tmp_path, + ) result = script.pip( "install", "script.wheel3==0.1", "--no-index", "--find-links", - tmpdir, + tmp_path, ) if os.name == "nt": wrapper_file = script.bin / "t1.exe" @@ -565,49 +576,49 @@ def test_install_from_wheel_gui_entrypoint( def test_wheel_compiles_pyc( - script: PipTestEnvironment, shared_data: TestData, tmpdir: Path + script: PipTestEnvironment, shared_data: TestData, tmp_path: pathlib.Path ) -> None: """ Test installing from wheel with --compile on """ - shutil.copy(shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmpdir) + shutil.copy(shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmp_path) script.pip( "install", "--compile", "simple.dist==0.1", "--no-index", "--find-links", - tmpdir, + tmp_path, ) # There are many locations for the __init__.pyc file so attempt to find # any of them exists = [ os.path.exists(script.site_packages_path / "simpledist/__init__.pyc"), - *glob.glob(script.site_packages_path / "simpledist/__pycache__/__init__*.pyc"), + *script.site_packages_path.glob("simpledist/__pycache__/__init__*.pyc"), ] assert any(exists) def test_wheel_no_compiles_pyc( - script: PipTestEnvironment, shared_data: TestData, tmpdir: Path + script: PipTestEnvironment, shared_data: TestData, tmp_path: pathlib.Path ) -> None: """ Test installing from wheel with --compile on """ - shutil.copy(shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmpdir) + shutil.copy(shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmp_path) script.pip( "install", "--no-compile", "simple.dist==0.1", "--no-index", "--find-links", - tmpdir, + tmp_path, ) # There are many locations for the __init__.pyc file so attempt to find # any of them exists = [ os.path.exists(script.site_packages_path / "simpledist/__init__.pyc"), - *glob.glob(script.site_packages_path / "simpledist/__pycache__/__init__*.pyc"), + *script.site_packages_path.glob("simpledist/__pycache__/__init__*.pyc"), ] assert not any(exists) @@ -739,7 +750,7 @@ def test_correct_package_name_while_creating_wheel_bug( @pytest.mark.parametrize("name", ["purelib", "abc"]) def test_wheel_with_file_in_data_dir_has_reasonable_error( - script: PipTestEnvironment, tmpdir: Path, name: str + script: PipTestEnvironment, tmp_path: pathlib.Path, name: str ) -> None: """Normally we expect entities in the .data directory to be in a subdirectory, but if they are not then we should show a reasonable error @@ -747,18 +758,18 @@ def test_wheel_with_file_in_data_dir_has_reasonable_error( """ wheel_path = make_wheel( "simple", "0.1.0", extra_data_files={name: "hello world"} - ).save_to_dir(tmpdir) + ).save_to_dir(tmp_path) - result = script.pip("install", "--no-index", str(wheel_path), expect_error=True) + result = script.pip("install", "--no-index", wheel_path, expect_error=True) assert f"simple-0.1.0.data/{name}" in result.stderr def test_wheel_with_unknown_subdir_in_data_dir_has_reasonable_error( - script: PipTestEnvironment, tmpdir: Path + script: PipTestEnvironment, tmp_path: pathlib.Path ) -> None: wheel_path = make_wheel( "simple", "0.1.0", extra_data_files={"unknown/hello.txt": "hello world"} - ).save_to_dir(tmpdir) + ).save_to_dir(tmp_path) - result = script.pip("install", "--no-index", str(wheel_path), expect_error=True) + result = script.pip("install", "--no-index", wheel_path, expect_error=True) assert "simple-0.1.0.data/unknown/hello.txt" in result.stderr diff --git a/tests/functional/test_list.py b/tests/functional/test_list.py index b9d0f0fa340..66e98f07d2c 100644 --- a/tests/functional/test_list.py +++ b/tests/functional/test_list.py @@ -1,5 +1,6 @@ import json import os +import pathlib import pytest @@ -13,17 +14,16 @@ wheel, ) from tests.lib.direct_url import get_created_direct_url_path -from tests.lib.path import Path @pytest.fixture(scope="session") def simple_script( - tmpdir_factory: pytest.TempdirFactory, + tmp_path_factory: pytest.TempPathFactory, script_factory: ScriptFactory, shared_data: TestData, ) -> PipTestEnvironment: - tmpdir = Path(str(tmpdir_factory.mktemp("pip_test_package"))) - script = script_factory(tmpdir.joinpath("workspace")) + tmp_path = tmp_path_factory.mktemp("pip_test_package") + script = script_factory(tmp_path.joinpath("workspace")) script.pip( "install", "-f", @@ -113,10 +113,10 @@ def test_local_columns_flag(simple_script: PipTestEnvironment) -> None: def test_multiple_exclude_and_normalization( - script: PipTestEnvironment, tmpdir: Path + script: PipTestEnvironment, tmp_path: pathlib.Path ) -> None: req_path = wheel.make_wheel(name="Normalizable_Name", version="1.0").save_to_dir( - tmpdir + tmp_path ) script.pip("install", "--no-index", req_path) result = script.pip("list") @@ -336,11 +336,11 @@ def test_outdated_columns_flag(script: PipTestEnvironment, data: TestData) -> No @pytest.fixture(scope="session") def pip_test_package_script( - tmpdir_factory: pytest.TempdirFactory, + tmp_path_factory: pytest.TempPathFactory, script_factory: ScriptFactory, shared_data: TestData, ) -> PipTestEnvironment: - tmpdir = Path(str(tmpdir_factory.mktemp("pip_test_package"))) + tmpdir = tmp_path_factory.mktemp("pip_test_package") script = script_factory(tmpdir.joinpath("workspace")) script.pip("install", "-f", shared_data.find_links, "--no-index", "simple==1.0") script.pip( @@ -638,50 +638,51 @@ def test_list_json(simple_script: PipTestEnvironment) -> None: assert {"name": "simple2", "version": "3.0"} in data -def test_list_path(tmpdir: Path, script: PipTestEnvironment, data: TestData) -> None: +@pytest.mark.usefixtures("data") +def test_list_path(tmp_path: pathlib.Path, script: PipTestEnvironment) -> None: """ Test list with --path. """ - result = script.pip("list", "--path", tmpdir, "--format=json") + result = script.pip("list", "--path", tmp_path, "--format=json") json_result = json.loads(result.stdout) assert {"name": "simple", "version": "2.0"} not in json_result - script.pip_install_local("--target", tmpdir, "simple==2.0") - result = script.pip("list", "--path", tmpdir, "--format=json") + script.pip_install_local("--target", tmp_path, "simple==2.0") + result = script.pip("list", "--path", tmp_path, "--format=json") json_result = json.loads(result.stdout) assert {"name": "simple", "version": "2.0"} in json_result @pytest.mark.incompatible_with_test_venv def test_list_path_exclude_user( - tmpdir: Path, script: PipTestEnvironment, data: TestData + tmp_path: pathlib.Path, script: PipTestEnvironment, data: TestData ) -> None: """ Test list with --path and make sure packages from --user are not picked up. """ script.pip_install_local("--user", "simple2") - script.pip_install_local("--target", tmpdir, "simple==1.0") + script.pip_install_local("--target", tmp_path, "simple==1.0") result = script.pip("list", "--user", "--format=json") json_result = json.loads(result.stdout) assert {"name": "simple2", "version": "3.0"} in json_result - result = script.pip("list", "--path", tmpdir, "--format=json") + result = script.pip("list", "--path", tmp_path, "--format=json") json_result = json.loads(result.stdout) assert {"name": "simple", "version": "1.0"} in json_result def test_list_path_multiple( - tmpdir: Path, script: PipTestEnvironment, data: TestData + tmp_path: pathlib.Path, script: PipTestEnvironment, data: TestData ) -> None: """ Test list with multiple --path arguments. """ - path1 = tmpdir / "path1" - os.mkdir(path1) - path2 = tmpdir / "path2" - os.mkdir(path2) + path1 = tmp_path / "path1" + path1.mkdir() + path2 = tmp_path / "path2" + path2.mkdir() script.pip_install_local("--target", path1, "simple==2.0") script.pip_install_local("--target", path2, "simple2==3.0") @@ -690,7 +691,14 @@ def test_list_path_multiple( json_result = json.loads(result.stdout) assert {"name": "simple", "version": "2.0"} in json_result - result = script.pip("list", "--path", path1, "--path", path2, "--format=json") + result = script.pip( + "list", + "--path", + path1, + "--path", + path2, + "--format=json", + ) json_result = json.loads(result.stdout) assert {"name": "simple", "version": "2.0"} in json_result assert {"name": "simple2", "version": "3.0"} in json_result @@ -741,12 +749,10 @@ def test_list_pep610_editable(script: PipTestEnvironment) -> None: direct_url_path = get_created_direct_url_path(result, "testpkg") assert direct_url_path # patch direct_url.json to simulate an editable install - with open(direct_url_path) as f: - direct_url = DirectUrl.from_json(f.read()) + direct_url = DirectUrl.from_json(direct_url_path.read_text()) assert isinstance(direct_url.info, DirInfo) direct_url.info.editable = True - with open(direct_url_path, "w") as f: - f.write(direct_url.to_json()) + direct_url_path.write_text(direct_url.to_json()) result = script.pip("list", "--format=json") for item in json.loads(result.stdout): if item["name"] == "testpkg": diff --git a/tests/functional/test_new_resolver.py b/tests/functional/test_new_resolver.py index 7f35406f75f..9a8b78e68ae 100644 --- a/tests/functional/test_new_resolver.py +++ b/tests/functional/test_new_resolver.py @@ -11,15 +11,15 @@ create_basic_sdist_for_package, create_basic_wheel_for_package, create_test_package_with_setup, - path_to_url, ) from tests.lib.direct_url import get_created_direct_url -from tests.lib.path import Path from tests.lib.wheel import make_wheel if TYPE_CHECKING: from typing import Protocol +MakeFakeWheel = Callable[[str, str, str], pathlib.Path] + def assert_editable(script: PipTestEnvironment, *args: str) -> None: # This simply checks whether all of the listed packages have a @@ -32,8 +32,8 @@ def assert_editable(script: PipTestEnvironment, *args: str) -> None: @pytest.fixture() -def make_fake_wheel(script: PipTestEnvironment) -> Callable[[str, str, str], Path]: - def _make_fake_wheel(name: str, version: str, wheel_tag: str) -> Path: +def make_fake_wheel(script: PipTestEnvironment) -> MakeFakeWheel: + def _make_fake_wheel(name: str, version: str, wheel_tag: str) -> pathlib.Path: wheel_house = script.scratch_path.joinpath("wheelhouse") wheel_house.mkdir() wheel_builder = make_wheel( @@ -221,9 +221,9 @@ def test_new_resolver_ignore_dependencies(script: PipTestEnvironment) -> None: ], ) def test_new_resolver_installs_extras( - tmpdir: Path, script: PipTestEnvironment, root_dep: str + tmp_path: pathlib.Path, script: PipTestEnvironment, root_dep: str ) -> None: - req_file = tmpdir.joinpath("requirements.txt") + req_file = tmp_path.joinpath("requirements.txt") req_file.write_text(root_dep) create_basic_wheel_for_package( @@ -379,7 +379,7 @@ def test_new_resolver_requires_python( "--no-cache-dir", "--no-index", "--find-links", - script.scratch_path, + os.fspath(script.scratch_path), ] if ignore_requires_python: args.append("--ignore-requires-python") @@ -783,7 +783,7 @@ def test_new_resolver_constraint_on_path_empty( "--no-index", "-c", constraints_txt, - str(script.scratch_path), + script.scratch_path, expect_error=expect_error, ) @@ -938,13 +938,14 @@ def _local_with_setup( extras: Dict[str, List[str]], ) -> str: """Create the package as a local source directory to install from path.""" - return create_test_package_with_setup( + path = create_test_package_with_setup( script, name=name, version=version, install_requires=requires, extras_require=extras, ) + return str(path) def _direct_wheel( @@ -955,13 +956,14 @@ def _direct_wheel( extras: Dict[str, List[str]], ) -> str: """Create the package as a wheel to install from path directly.""" - return create_basic_wheel_for_package( + path = create_basic_wheel_for_package( script, name=name, version=version, depends=requires, extras=extras, ) + return str(path) def _wheel_from_index( @@ -1020,7 +1022,7 @@ def test_new_resolver_extra_merge_in_package( "--no-index", "--find-links", script.scratch_path, - requirement + "[dev]", + f"{requirement}[dev]", ) script.assert_installed(pkg="1.0.0", dep="1.0.0", depdev="1.0.0") @@ -1181,7 +1183,7 @@ def test_new_resolver_presents_messages_when_backtracking_a_lot( for index in range(1, N + 1): A_version = f"{index}.0.0" B_version = f"{index}.0.0" - C_version = "{index_minus_one}.0.0".format(index_minus_one=index - 1) + C_version = f"{index - 1}.0.0" depends = ["B == " + B_version] if index != 1: @@ -1458,7 +1460,7 @@ def test_new_resolver_does_not_install_unneeded_packages_with_url_constraint( ) constraints_file = script.scratch_path / "constraints.txt" - constraints_file.write_text("not_installed @ " + path_to_url(not_installed_path)) + constraints_file.write_text(f"not_installed @ {not_installed_path.as_uri()}") (script.scratch_path / "index").mkdir() archive_path.rename(script.scratch_path / "index" / archive_path.name) @@ -1488,10 +1490,15 @@ def test_new_resolver_installs_packages_with_url_constraint( ) constraints_file = script.scratch_path / "constraints.txt" - constraints_file.write_text("installed @ " + path_to_url(installed_path)) + constraints_file.write_text(f"installed @ {installed_path.as_uri()}") script.pip( - "install", "--no-cache-dir", "--no-index", "-c", constraints_file, "installed" + "install", + "--no-cache-dir", + "--no-index", + "-c", + constraints_file, + "installed", ) script.assert_installed(installed="0.1.0") @@ -1507,7 +1514,7 @@ def test_new_resolver_reinstall_link_requirement_with_constraint( ) cr_file = script.scratch_path / "constraints.txt" - cr_file.write_text("installed @ " + path_to_url(installed_path)) + cr_file.write_text(f"installed @ {installed_path.as_uri()}") script.pip( "install", @@ -1545,7 +1552,7 @@ def test_new_resolver_prefers_url_constraint(script: PipTestEnvironment) -> None ) constraints_file = script.scratch_path / "constraints.txt" - constraints_file.write_text("test_pkg @ " + path_to_url(installed_path)) + constraints_file.write_text(f"test_pkg @ {installed_path.as_uri()}") (script.scratch_path / "index").mkdir() not_installed_path.rename(script.scratch_path / "index" / not_installed_path.name) @@ -1579,7 +1586,7 @@ def test_new_resolver_prefers_url_constraint_on_update( ) constraints_file = script.scratch_path / "constraints.txt" - constraints_file.write_text("test_pkg @ " + path_to_url(installed_path)) + constraints_file.write_text(f"test_pkg @ {installed_path.as_uri()}") (script.scratch_path / "index").mkdir() not_installed_path.rename(script.scratch_path / "index" / not_installed_path.name) @@ -1626,7 +1633,7 @@ def test_new_resolver_fails_with_url_constraint_and_incompatible_version( ) url_constraint = script.scratch_path / "constraints.txt" - url_constraint.write_text("test_pkg @ " + path_to_url(not_installed_path)) + url_constraint.write_text(f"test_pkg @ {not_installed_path.as_uri()}") version_req = script.scratch_path / "requirements.txt" version_req.write_text("test_pkg<0.2.0") @@ -1685,8 +1692,8 @@ def test_new_resolver_ignores_unneeded_conflicting_constraints( ) constraints = [ - "test_pkg @ " + path_to_url(version_1), - "test_pkg @ " + path_to_url(version_2), + f"test_pkg @ {version_1.as_uri()}", + f"test_pkg @ {version_2.as_uri()}", ] constraints_file = script.scratch_path / "constraints.txt" @@ -1722,8 +1729,8 @@ def test_new_resolver_fails_on_needed_conflicting_constraints( ) constraints = [ - "test_pkg @ " + path_to_url(version_1), - "test_pkg @ " + path_to_url(version_2), + f"test_pkg @ {version_1.as_uri()}", + f"test_pkg @ {version_2.as_uri()}", ] constraints_file = script.scratch_path / "constraints.txt" @@ -1774,7 +1781,7 @@ def test_new_resolver_fails_on_conflicting_constraint_and_requirement( ) constraints_file = script.scratch_path / "constraints.txt" - constraints_file.write_text("test_pkg @ " + path_to_url(version_1)) + constraints_file.write_text(f"test_pkg @ {version_1.as_uri()}") result = script.pip( "install", @@ -1784,7 +1791,7 @@ def test_new_resolver_fails_on_conflicting_constraint_and_requirement( script.scratch_path, "-c", constraints_file, - "test_pkg @ " + path_to_url(version_2), + f"test_pkg @ {version_2.as_uri()}", expect_error=True, ) @@ -1802,7 +1809,7 @@ def test_new_resolver_fails_on_conflicting_constraint_and_requirement( "--no-index", "--find-links", script.scratch_path, - "test_pkg @ " + path_to_url(version_2), + f"test_pkg @ {version_2.as_uri()}", ) @@ -1821,14 +1828,14 @@ def test_new_resolver_succeeds_on_matching_constraint_and_requirement( "0.1.0", ) - req_line = "test_pkg @ " + path_to_url(source_dir) + req_line = f"test_pkg @ {source_dir.as_uri()}" constraints_file = script.scratch_path / "constraints.txt" constraints_file.write_text(req_line) last_args: Tuple[str, ...] if editable: - last_args = ("-e", source_dir) + last_args = ("-e", str(source_dir)) else: last_args = (req_line,) @@ -1865,7 +1872,7 @@ def test_new_resolver_applies_url_constraint_to_dep(script: PipTestEnvironment) version_2.rename(script.scratch_path / "index" / version_2.name) constraints_file = script.scratch_path / "constraints.txt" - constraints_file.write_text("dep @ " + path_to_url(version_1)) + constraints_file.write_text(f"dep @ {version_1.as_uri()}") script.pip( "install", @@ -1882,7 +1889,7 @@ def test_new_resolver_applies_url_constraint_to_dep(script: PipTestEnvironment) def test_new_resolver_handles_compatible_wheel_tags_in_constraint_url( - script: PipTestEnvironment, make_fake_wheel: Callable[[str, str, str], Path] + script: PipTestEnvironment, make_fake_wheel: MakeFakeWheel ) -> None: initial_path = make_fake_wheel("base", "0.1.0", "fakepy1-fakeabi-fakeplat") @@ -1894,7 +1901,7 @@ def test_new_resolver_handles_compatible_wheel_tags_in_constraint_url( initial_path.rename(final_path) constraints_file = script.scratch_path / "constraints.txt" - constraints_file.write_text("base @ " + path_to_url(final_path)) + constraints_file.write_text(f"base @ {final_path.as_uri()}") result = script.pip( "install", @@ -1916,12 +1923,11 @@ def test_new_resolver_handles_compatible_wheel_tags_in_constraint_url( "base", ) - dist_info = Path("scratch", "target", "base-0.1.0.dist-info") - result.did_create(dist_info) + result.did_create("scratch/target/base-0.1.0.dist-info") def test_new_resolver_handles_incompatible_wheel_tags_in_constraint_url( - script: PipTestEnvironment, make_fake_wheel: Callable[[str, str, str], Path] + script: PipTestEnvironment, make_fake_wheel: MakeFakeWheel ) -> None: initial_path = make_fake_wheel("base", "0.1.0", "fakepy1-fakeabi-fakeplat") @@ -1933,7 +1939,7 @@ def test_new_resolver_handles_incompatible_wheel_tags_in_constraint_url( initial_path.rename(final_path) constraints_file = script.scratch_path / "constraints.txt" - constraints_file.write_text("base @ " + path_to_url(final_path)) + constraints_file.write_text(f"base @ {final_path.as_uri()}") result = script.pip( "install", @@ -1954,7 +1960,7 @@ def test_new_resolver_handles_incompatible_wheel_tags_in_constraint_url( def test_new_resolver_avoids_incompatible_wheel_tags_in_constraint_url( - script: PipTestEnvironment, make_fake_wheel: Callable[[str, str, str], Path] + script: PipTestEnvironment, make_fake_wheel: MakeFakeWheel ) -> None: initial_path = make_fake_wheel("dep", "0.1.0", "fakepy1-fakeabi-fakeplat") @@ -1966,7 +1972,7 @@ def test_new_resolver_avoids_incompatible_wheel_tags_in_constraint_url( initial_path.rename(final_path) constraints_file = script.scratch_path / "constraints.txt" - constraints_file.write_text("dep @ " + path_to_url(final_path)) + constraints_file.write_text(f"dep @ {final_path.as_uri()}") index = script.scratch_path / "index" index.mkdir() @@ -2060,7 +2066,7 @@ def test_new_resolver_direct_url_equivalent( script, name="pkgb", version="1", - depends=[f"pkga@{path_to_url(pkga)}{depend_suffix}"], + depends=[f"pkga@{pkga.as_uri()}{depend_suffix}"], ) # Make pkgb visible via --find-links, but not pkga. @@ -2076,8 +2082,8 @@ def test_new_resolver_direct_url_equivalent( "--no-cache-dir", "--no-index", "--find-links", - str(find_links), - f"{path_to_url(pkga)}{request_suffix}", + find_links, + f"{pkga.as_uri()}{request_suffix}", "pkgb", expect_error=(not suffixes_equivalent), ) @@ -2120,7 +2126,7 @@ def test_new_resolver_direct_url_with_extras( "--no-cache-dir", "--no-index", "--find-links", - str(find_links), + find_links, pkg2, "pkg3", ) @@ -2200,35 +2206,30 @@ def test_new_resolver_transitively_depends_on_unnamed_local( ) -def _to_uri(path: str) -> str: - # Something like file:///path/to/package - return pathlib.Path(path).as_uri() - - -def _to_localhost_uri(path: str) -> str: +def _to_localhost_uri(path: pathlib.Path) -> str: # Something like file://localhost/path/to/package - return pathlib.Path(path).as_uri().replace("///", "//localhost/") + return path.as_uri().replace("///", "//localhost/") @pytest.mark.parametrize( "format_dep", [ - pytest.param(_to_uri, id="emptyhost"), + pytest.param(pathlib.Path.as_uri, id="emptyhost"), pytest.param(_to_localhost_uri, id="localhost"), ], ) @pytest.mark.parametrize( "format_input", [ - pytest.param(lambda path: path, id="path"), - pytest.param(_to_uri, id="emptyhost"), + pytest.param(pathlib.Path, id="path"), + pytest.param(pathlib.Path.as_uri, id="emptyhost"), pytest.param(_to_localhost_uri, id="localhost"), ], ) def test_new_resolver_file_url_normalize( script: PipTestEnvironment, - format_dep: Callable[[str], str], - format_input: Callable[[str], str], + format_dep: Callable[[pathlib.Path], str], + format_input: Callable[[pathlib.Path], str], ) -> None: lib_a = create_test_package_with_setup( script, diff --git a/tests/functional/test_new_resolver_errors.py b/tests/functional/test_new_resolver_errors.py index 1278bc3edde..11ac6a29f58 100644 --- a/tests/functional/test_new_resolver_errors.py +++ b/tests/functional/test_new_resolver_errors.py @@ -6,11 +6,10 @@ create_basic_wheel_for_package, create_test_package_with_setup, ) -from tests.lib.path import Path def test_new_resolver_conflict_requirements_file( - tmpdir: Path, script: PipTestEnvironment + tmp_path: pathlib.Path, script: PipTestEnvironment ) -> None: create_basic_wheel_for_package(script, "base", "1.0") create_basic_wheel_for_package(script, "base", "2.0") @@ -27,7 +26,7 @@ def test_new_resolver_conflict_requirements_file( depends=["base==2.0"], ) - req_file = tmpdir.joinpath("requirements.txt") + req_file = tmp_path.joinpath("requirements.txt") req_file.write_text("pkga\npkgb") result = script.pip( @@ -46,11 +45,11 @@ def test_new_resolver_conflict_requirements_file( def test_new_resolver_conflict_constraints_file( - tmpdir: Path, script: PipTestEnvironment + tmp_path: pathlib.Path, script: PipTestEnvironment ) -> None: create_basic_wheel_for_package(script, "pkg", "1.0") - constraints_file = tmpdir.joinpath("constraints.txt") + constraints_file = tmp_path.joinpath("constraints.txt") constraints_file.write_text("pkg!=1.0") result = script.pip( @@ -89,7 +88,13 @@ def test_new_resolver_requires_python_error(script: PipTestEnvironment) -> None: ) # This always fails because pkgb can never be satisfied. - result = script.pip("install", "--no-index", pkga, pkgb, expect_error=True) + result = script.pip( + "install", + "--no-index", + pkga, + pkgb, + expect_error=True, + ) # The error message should mention the Requires-Python: value causing the # conflict, not the compatible one. diff --git a/tests/functional/test_new_resolver_hashes.py b/tests/functional/test_new_resolver_hashes.py index 80ed86219d4..c443853c128 100644 --- a/tests/functional/test_new_resolver_hashes.py +++ b/tests/functional/test_new_resolver_hashes.py @@ -1,19 +1,20 @@ -import collections import hashlib +import pathlib +from typing import NamedTuple import pytest -from pip._internal.utils.urls import path_to_url from tests.lib import ( PipTestEnvironment, create_basic_sdist_for_package, create_basic_wheel_for_package, ) -_FindLinks = collections.namedtuple( - "_FindLinks", - "index_html sdist_hash wheel_hash", -) + +class _FindLinks(NamedTuple): + index_html: pathlib.Path + sdist_hash: str + wheel_hash: str def _create_find_links(script: PipTestEnvironment) -> _FindLinks: @@ -30,10 +31,10 @@ def _create_find_links(script: PipTestEnvironment) -> _FindLinks: {sdist_path.stem} {wheel_path.stem} """.format( - sdist_url=path_to_url(sdist_path), + sdist_url=sdist_path.as_uri(), sdist_hash=sdist_hash, sdist_path=sdist_path, - wheel_url=path_to_url(wheel_path), + wheel_url=wheel_path.as_uri(), wheel_hash=wheel_hash, wheel_path=wheel_path, ).strip() @@ -249,7 +250,7 @@ def test_new_resolver_hash_requirement_and_url_constraint_can_succeed( ) constraints_txt = script.scratch_path / "constraints.txt" - constraint_text = "base @ {wheel_url}\n".format(wheel_url=path_to_url(wheel_path)) + constraint_text = "base @ {wheel_url}\n".format(wheel_url=wheel_path.as_uri()) if constrain_by_hash: constraint_text += "base==0.1.0 --hash=sha256:{wheel_hash}\n".format( wheel_hash=wheel_hash, @@ -289,7 +290,7 @@ def test_new_resolver_hash_requirement_and_url_constraint_can_fail( ) constraints_txt = script.scratch_path / "constraints.txt" - constraint_text = "base @ {wheel_url}\n".format(wheel_url=path_to_url(wheel_path)) + constraint_text = "base @ {wheel_url}\n".format(wheel_url=wheel_path.as_uri()) if constrain_by_hash: constraint_text += "base==0.1.0 --hash=sha256:{other_hash}\n".format( other_hash=other_hash, diff --git a/tests/functional/test_new_resolver_target.py b/tests/functional/test_new_resolver_target.py index 398695b5a83..15e688f6a64 100644 --- a/tests/functional/test_new_resolver_target.py +++ b/tests/functional/test_new_resolver_target.py @@ -1,18 +1,18 @@ +import pathlib from typing import Callable, Optional import pytest from pip._internal.cli.status_codes import ERROR, SUCCESS from tests.lib import PipTestEnvironment -from tests.lib.path import Path from tests.lib.wheel import make_wheel -MakeFakeWheel = Callable[[str], Path] +MakeFakeWheel = Callable[[str], pathlib.Path] @pytest.fixture() def make_fake_wheel(script: PipTestEnvironment) -> MakeFakeWheel: - def _make_fake_wheel(wheel_tag: str) -> Path: + def _make_fake_wheel(wheel_tag: str) -> pathlib.Path: wheel_house = script.scratch_path.joinpath("wheelhouse") wheel_house.mkdir() wheel_builder = make_wheel( @@ -47,7 +47,7 @@ def test_new_resolver_target_checks_compatibility_failure( "--no-index", "--target", str(script.scratch_path.joinpath("target")), - make_fake_wheel(fake_wheel_tag), + str(make_fake_wheel(fake_wheel_tag)), ] if implementation: args += ["--implementation", implementation] @@ -68,7 +68,7 @@ def test_new_resolver_target_checks_compatibility_failure( result = script.pip(*args, expect_error=(not wheel_tag_matches)) - dist_info = Path("scratch", "target", "fake-1.0.dist-info") + dist_info = pathlib.Path("scratch", "target", "fake-1.0.dist-info") if wheel_tag_matches: assert result.returncode == SUCCESS result.did_create(dist_info) diff --git a/tests/functional/test_new_resolver_user.py b/tests/functional/test_new_resolver_user.py index acdae71c9cf..4a667d3f324 100644 --- a/tests/functional/test_new_resolver_user.py +++ b/tests/functional/test_new_resolver_user.py @@ -173,7 +173,7 @@ def test_new_resolver_install_user_reinstall_global_site( result.did_create(script.user_site / "base") - site_packages_content = set(os.listdir(script.site_packages_path)) + site_packages_content = {p.name for p in script.site_packages_path.iterdir()} assert "base" in site_packages_content @@ -211,7 +211,7 @@ def test_new_resolver_install_user_conflict_in_global_site( base_2_dist_info = script.user_site / "base-2.0.0.dist-info" result.did_create(base_2_dist_info) - site_packages_content = set(os.listdir(script.site_packages_path)) + site_packages_content = {p.name for p in script.site_packages_path.iterdir()} assert "base-1.0.0.dist-info" in site_packages_content @@ -262,5 +262,5 @@ def test_new_resolver_install_user_conflict_in_global_and_user_sites( result.did_create(base_1_dist_info) assert base_2_dist_info in result.files_deleted, str(result) - site_packages_content = set(os.listdir(script.site_packages_path)) + site_packages_content = {p.name for p in script.site_packages_path.iterdir()} assert "base-2.0.0.dist-info" in site_packages_content diff --git a/tests/functional/test_pep517.py b/tests/functional/test_pep517.py index 7f913c21584..bbae63f5afb 100644 --- a/tests/functional/test_pep517.py +++ b/tests/functional/test_pep517.py @@ -1,3 +1,4 @@ +import pathlib from typing import Any, Dict, List, Optional, Tuple import pytest @@ -10,19 +11,17 @@ TestData, create_basic_wheel_for_package, make_test_finder, - path_to_url, ) -from tests.lib.path import Path def make_project( - tmpdir: Path, + tmp_path: pathlib.Path, requires: Optional[List[str]] = None, backend: Optional[str] = None, backend_path: Optional[List[str]] = None, -) -> Path: +) -> pathlib.Path: requires = requires or [] - project_dir = tmpdir / "project" + project_dir = tmp_path / "project" project_dir.mkdir() buildsys: Dict[str, Any] = {"requires": requires} if backend: @@ -34,11 +33,11 @@ def make_project( return project_dir -def test_backend(tmpdir: Path, data: TestData) -> None: +def test_backend(tmp_path: pathlib.Path, data: TestData) -> None: """Check we can call a requirement's backend successfully""" - project_dir = make_project(tmpdir, backend="dummy_backend") + project_dir = make_project(tmp_path, backend="dummy_backend") req = InstallRequirement(None, None) - req.source_dir = project_dir # make req believe it has been unpacked + req.source_dir = str(project_dir) # make req believe it has been unpacked req.load_pyproject_toml() env = BuildEnvironment() finder = make_test_finder(find_links=[data.backends]) @@ -61,12 +60,13 @@ def build_wheel( """ -def test_backend_path(tmpdir: Path, data: TestData) -> None: +@pytest.mark.usefixtures("data") +def test_backend_path(tmp_path: pathlib.Path) -> None: """Check we can call a backend inside the project""" - project_dir = make_project(tmpdir, backend="dummy_backend", backend_path=["."]) + project_dir = make_project(tmp_path, backend="dummy_backend", backend_path=["."]) (project_dir / "dummy_backend.py").write_text(dummy_backend_code) req = InstallRequirement(None, None) - req.source_dir = project_dir # make req believe it has been unpacked + req.source_dir = str(project_dir) # make req believe it has been unpacked req.load_pyproject_toml() env = BuildEnvironment() @@ -76,16 +76,16 @@ def test_backend_path(tmpdir: Path, data: TestData) -> None: assert req.pep517_backend.build_wheel("dir") == "Backend called" -def test_backend_path_and_dep(tmpdir: Path, data: TestData) -> None: +def test_backend_path_and_dep(tmp_path: pathlib.Path, data: TestData) -> None: """Check we can call a requirement's backend successfully""" project_dir = make_project( - tmpdir, backend="dummy_internal_backend", backend_path=["."] + tmp_path, backend="dummy_internal_backend", backend_path=["."] ) (project_dir / "dummy_internal_backend.py").write_text( "from dummy_backend import build_wheel" ) req = InstallRequirement(None, None) - req.source_dir = project_dir # make req believe it has been unpacked + req.source_dir = str(project_dir) # make req believe it has been unpacked req.load_pyproject_toml() env = BuildEnvironment() finder = make_test_finder(find_links=[data.backends]) @@ -98,36 +98,42 @@ def test_backend_path_and_dep(tmpdir: Path, data: TestData) -> None: def test_pep517_install( - script: PipTestEnvironment, tmpdir: Path, data: TestData + script: PipTestEnvironment, tmp_path: pathlib.Path, data: TestData ) -> None: """Check we can build with a custom backend""" project_dir = make_project( - tmpdir, requires=["test_backend"], backend="test_backend" + tmp_path, requires=["test_backend"], backend="test_backend" ) result = script.pip("install", "--no-index", "-f", data.backends, project_dir) result.assert_installed("project", editable=False) def test_pep517_install_with_reqs( - script: PipTestEnvironment, tmpdir: Path, data: TestData + script: PipTestEnvironment, tmp_path: pathlib.Path, data: TestData ) -> None: """Backend generated requirements are installed in the build env""" project_dir = make_project( - tmpdir, requires=["test_backend"], backend="test_backend" + tmp_path, requires=["test_backend"], backend="test_backend" ) project_dir.joinpath("backend_reqs.txt").write_text("simplewheel") result = script.pip( - "install", "--no-index", "-f", data.backends, "-f", data.packages, project_dir + "install", + "--no-index", + "-f", + data.backends, + "-f", + data.packages, + project_dir, ) result.assert_installed("project", editable=False) def test_no_use_pep517_without_setup_py( - script: PipTestEnvironment, tmpdir: Path, data: TestData + script: PipTestEnvironment, tmp_path: pathlib.Path, data: TestData ) -> None: """Using --no-use-pep517 requires setup.py""" project_dir = make_project( - tmpdir, requires=["test_backend"], backend="test_backend" + tmp_path, requires=["test_backend"], backend="test_backend" ) result = script.pip( "install", @@ -142,10 +148,10 @@ def test_no_use_pep517_without_setup_py( def test_conflicting_pep517_backend_requirements( - script: PipTestEnvironment, tmpdir: Path, data: TestData + script: PipTestEnvironment, tmp_path: pathlib.Path, data: TestData ) -> None: project_dir = make_project( - tmpdir, requires=["test_backend", "simplewheel==1.0"], backend="test_backend" + tmp_path, requires=["test_backend", "simplewheel==1.0"], backend="test_backend" ) project_dir.joinpath("backend_reqs.txt").write_text("simplewheel==2.0") result = script.pip( @@ -161,16 +167,16 @@ def test_conflicting_pep517_backend_requirements( msg = ( "Some build dependencies for {url} conflict with the backend " "dependencies: simplewheel==1.0 is incompatible with " - "simplewheel==2.0.".format(url=path_to_url(project_dir)) + "simplewheel==2.0.".format(url=project_dir.as_uri()) ) assert result.returncode != 0 and msg in result.stderr, str(result) def test_no_check_build_deps( - script: PipTestEnvironment, tmpdir: Path, data: TestData + script: PipTestEnvironment, tmp_path: pathlib.Path, data: TestData ) -> None: project_dir = make_project( - tmpdir, requires=["simplewheel==2.0"], backend="test_backend" + tmp_path, requires=["simplewheel==2.0"], backend="test_backend" ) script.pip( "install", @@ -187,10 +193,10 @@ def test_no_check_build_deps( def test_validate_missing_pep517_backend_requirements( - script: PipTestEnvironment, tmpdir: Path, data: TestData + script: PipTestEnvironment, tmp_path: pathlib.Path, data: TestData ) -> None: project_dir = make_project( - tmpdir, requires=["test_backend", "simplewheel==1.0"], backend="test_backend" + tmp_path, requires=["test_backend", "simplewheel==1.0"], backend="test_backend" ) result = script.pip( "install", @@ -206,16 +212,16 @@ def test_validate_missing_pep517_backend_requirements( ) msg = ( "Some build dependencies for {url} are missing: " - "'simplewheel==1.0', 'test_backend'.".format(url=path_to_url(project_dir)) + "'simplewheel==1.0', 'test_backend'.".format(url=project_dir.as_uri()) ) assert result.returncode != 0 and msg in result.stderr, str(result) def test_validate_conflicting_pep517_backend_requirements( - script: PipTestEnvironment, tmpdir: Path, data: TestData + script: PipTestEnvironment, tmp_path: pathlib.Path, data: TestData ) -> None: project_dir = make_project( - tmpdir, requires=["simplewheel==1.0"], backend="test_backend" + tmp_path, requires=["simplewheel==1.0"], backend="test_backend" ) script.pip("install", "simplewheel==2.0", "--no-index", "-f", data.packages) result = script.pip( @@ -233,7 +239,7 @@ def test_validate_conflicting_pep517_backend_requirements( msg = ( "Some build dependencies for {url} conflict with the backend " "dependencies: simplewheel==2.0 is incompatible with " - "simplewheel==1.0.".format(url=path_to_url(project_dir)) + "simplewheel==1.0.".format(url=project_dir.as_uri()) ) assert result.returncode != 0 and msg in result.stderr, str(result) @@ -253,15 +259,20 @@ def test_pep517_backend_requirements_satisfied_by_prerelease( ) project_dir.joinpath("backend_reqs.txt").write_text("myreq") - result = script.pip("install", "--no-index", "--no-build-isolation", project_dir) + result = script.pip( + "install", + "--no-index", + "--no-build-isolation", + project_dir, + ) assert "Installing backend dependencies:" not in result.stdout def test_pep517_backend_requirements_already_satisfied( - script: PipTestEnvironment, tmpdir: Path, data: TestData + script: PipTestEnvironment, tmp_path: pathlib.Path, data: TestData ) -> None: project_dir = make_project( - tmpdir, requires=["test_backend", "simplewheel==1.0"], backend="test_backend" + tmp_path, requires=["test_backend", "simplewheel==1.0"], backend="test_backend" ) project_dir.joinpath("backend_reqs.txt").write_text("simplewheel") result = script.pip( @@ -277,11 +288,11 @@ def test_pep517_backend_requirements_already_satisfied( def test_pep517_install_with_no_cache_dir( - script: PipTestEnvironment, tmpdir: Path, data: TestData + script: PipTestEnvironment, tmp_path: pathlib.Path, data: TestData ) -> None: """Check builds with a custom backends work, even with no cache.""" project_dir = make_project( - tmpdir, requires=["test_backend"], backend="test_backend" + tmp_path, requires=["test_backend"], backend="test_backend" ) result = script.pip( "install", @@ -295,9 +306,9 @@ def test_pep517_install_with_no_cache_dir( def make_pyproject_with_setup( - tmpdir: Path, build_system: bool = True, set_backend: bool = True -) -> Tuple[Path, str]: - project_dir = tmpdir / "project" + tmp_path: pathlib.Path, build_system: bool = True, set_backend: bool = True +) -> Tuple[pathlib.Path, str]: + project_dir = tmp_path / "project" project_dir.mkdir() setup_script = "from setuptools import setup\n" expect_script_dir_on_path = True @@ -334,11 +345,14 @@ def make_pyproject_with_setup( return project_dir, "pep517_test" +@pytest.mark.usefixtures("data") def test_no_build_system_section( - script: PipTestEnvironment, tmpdir: Path, data: TestData, common_wheels: Path + script: PipTestEnvironment, + tmp_path: pathlib.Path, + common_wheels: pathlib.Path, ) -> None: """Check builds with setup.py, pyproject.toml, but no build-system section.""" - project_dir, name = make_pyproject_with_setup(tmpdir, build_system=False) + project_dir, name = make_pyproject_with_setup(tmp_path, build_system=False) result = script.pip( "install", "--no-cache-dir", @@ -350,11 +364,14 @@ def test_no_build_system_section( result.assert_installed(name, editable=False) +@pytest.mark.usefixtures("data") def test_no_build_backend_entry( - script: PipTestEnvironment, tmpdir: Path, data: TestData, common_wheels: Path + script: PipTestEnvironment, + tmp_path: pathlib.Path, + common_wheels: pathlib.Path, ) -> None: """Check builds with setup.py, pyproject.toml, but no build-backend entry.""" - project_dir, name = make_pyproject_with_setup(tmpdir, set_backend=False) + project_dir, name = make_pyproject_with_setup(tmp_path, set_backend=False) result = script.pip( "install", "--no-cache-dir", @@ -366,11 +383,14 @@ def test_no_build_backend_entry( result.assert_installed(name, editable=False) +@pytest.mark.usefixtures("data") def test_explicit_setuptools_backend( - script: PipTestEnvironment, tmpdir: Path, data: TestData, common_wheels: Path + script: PipTestEnvironment, + tmp_path: pathlib.Path, + common_wheels: pathlib.Path, ) -> None: """Check builds with setup.py, pyproject.toml, and a build-backend entry.""" - project_dir, name = make_pyproject_with_setup(tmpdir) + project_dir, name = make_pyproject_with_setup(tmp_path) result = script.pip( "install", "--no-cache-dir", @@ -383,15 +403,18 @@ def test_explicit_setuptools_backend( @pytest.mark.network +@pytest.mark.usefixtures("data") def test_pep517_and_build_options( - script: PipTestEnvironment, tmpdir: Path, data: TestData, common_wheels: Path + script: PipTestEnvironment, + tmp_path: pathlib.Path, + common_wheels: pathlib.Path, ) -> None: """Backend generated requirements are installed in the build env""" - project_dir, name = make_pyproject_with_setup(tmpdir) + project_dir, _ = make_pyproject_with_setup(tmp_path) result = script.pip( "wheel", "--wheel-dir", - tmpdir, + tmp_path, "--build-option", "foo", "-f", @@ -404,15 +427,18 @@ def test_pep517_and_build_options( @pytest.mark.network +@pytest.mark.usefixtures("data") def test_pep517_and_global_options( - script: PipTestEnvironment, tmpdir: Path, data: TestData, common_wheels: Path + script: PipTestEnvironment, + tmp_path: pathlib.Path, + common_wheels: pathlib.Path, ) -> None: """Backend generated requirements are installed in the build env""" - project_dir, name = make_pyproject_with_setup(tmpdir) + project_dir, _ = make_pyproject_with_setup(tmp_path) result = script.pip( "wheel", "--wheel-dir", - tmpdir, + tmp_path, "--global-option", "foo", "-f", diff --git a/tests/functional/test_pep660.py b/tests/functional/test_pep660.py index c55fb80d37b..4fe0f2f7819 100644 --- a/tests/functional/test_pep660.py +++ b/tests/functional/test_pep660.py @@ -1,12 +1,11 @@ import os +import pathlib from typing import Any, Dict import pytest import tomli_w -from pip._internal.utils.urls import path_to_url from tests.lib import PipTestEnvironment -from tests.lib.path import Path SETUP_PY = """ from setuptools import setup @@ -64,9 +63,12 @@ def build_editable(wheel_directory, config_settings=None, metadata_directory=Non def _make_project( - tmpdir: Path, backend_code: str, with_setup_py: bool, with_pyproject: bool = True -) -> Path: - project_dir = tmpdir / "project" + tmp_path: pathlib.Path, + backend_code: str, + with_setup_py: bool, + with_pyproject: bool = True, +) -> pathlib.Path: + project_dir = tmp_path / "project" project_dir.mkdir() project_dir.joinpath("setup.cfg").write_text(SETUP_CFG) if with_setup_py: @@ -85,22 +87,25 @@ def _make_project( return project_dir -def _assert_hook_called(project_dir: Path, hook: str) -> None: +def _assert_hook_called(project_dir: pathlib.Path, hook: str) -> None: log = project_dir.joinpath("log.txt").read_text() assert f":{hook} called" in log, f"{hook} has not been called" -def _assert_hook_not_called(project_dir: Path, hook: str) -> None: +def _assert_hook_not_called(project_dir: pathlib.Path, hook: str) -> None: log = project_dir.joinpath("log.txt").read_text() assert f":{hook} called" not in log, f"{hook} should not have been called" @pytest.mark.usefixtures("with_wheel") -def test_install_pep517_basic(tmpdir: Path, script: PipTestEnvironment) -> None: +def test_install_pep517_basic( + tmp_path: pathlib.Path, + script: PipTestEnvironment, +) -> None: """ Check that the test harness we have in this file is sane. """ - project_dir = _make_project(tmpdir, BACKEND_WITHOUT_PEP660, with_setup_py=False) + project_dir = _make_project(tmp_path, BACKEND_WITHOUT_PEP660, with_setup_py=False) script.pip( "install", "--no-index", @@ -112,11 +117,14 @@ def test_install_pep517_basic(tmpdir: Path, script: PipTestEnvironment) -> None: @pytest.mark.usefixtures("with_wheel") -def test_install_pep660_basic(tmpdir: Path, script: PipTestEnvironment) -> None: +def test_install_pep660_basic( + tmp_path: pathlib.Path, + script: PipTestEnvironment, +) -> None: """ Test with backend that supports build_editable. """ - project_dir = _make_project(tmpdir, BACKEND_WITH_PEP660, with_setup_py=False) + project_dir = _make_project(tmp_path, BACKEND_WITH_PEP660, with_setup_py=False) result = script.pip( "install", "--no-index", @@ -134,14 +142,14 @@ def test_install_pep660_basic(tmpdir: Path, script: PipTestEnvironment) -> None: @pytest.mark.usefixtures("with_wheel") def test_install_no_pep660_setup_py_fallback( - tmpdir: Path, script: PipTestEnvironment + tmp_path: pathlib.Path, script: PipTestEnvironment ) -> None: """ Test that we fall back to setuptools develop when using a backend that does not support build_editable. Since there is a pyproject.toml, the prepare_metadata_for_build_wheel hook is called. """ - project_dir = _make_project(tmpdir, BACKEND_WITHOUT_PEP660, with_setup_py=True) + project_dir = _make_project(tmp_path, BACKEND_WITHOUT_PEP660, with_setup_py=True) result = script.pip( "install", "--no-index", @@ -159,14 +167,14 @@ def test_install_no_pep660_setup_py_fallback( @pytest.mark.usefixtures("with_wheel") def test_install_no_pep660_setup_cfg_fallback( - tmpdir: Path, script: PipTestEnvironment + tmp_path: pathlib.Path, script: PipTestEnvironment ) -> None: """ Test that we fall back to setuptools develop when using a backend that does not support build_editable. Since there is a pyproject.toml, the prepare_metadata_for_build_wheel hook is called. """ - project_dir = _make_project(tmpdir, BACKEND_WITHOUT_PEP660, with_setup_py=False) + project_dir = _make_project(tmp_path, BACKEND_WITHOUT_PEP660, with_setup_py=False) result = script.pip( "install", "--no-index", @@ -184,13 +192,15 @@ def test_install_no_pep660_setup_cfg_fallback( @pytest.mark.usefixtures("with_wheel") -def test_wheel_editable_pep660_basic(tmpdir: Path, script: PipTestEnvironment) -> None: +def test_wheel_editable_pep660_basic( + tmp_path: pathlib.Path, script: PipTestEnvironment +) -> None: """ Test 'pip wheel' of an editable pep 660 project. It must *not* call prepare_metadata_for_build_editable. """ - project_dir = _make_project(tmpdir, BACKEND_WITH_PEP660, with_setup_py=False) - wheel_dir = tmpdir / "dist" + project_dir = _make_project(tmp_path, BACKEND_WITH_PEP660, with_setup_py=False) + wheel_dir = tmp_path / "dist" script.pip( "wheel", "--no-index", @@ -204,21 +214,21 @@ def test_wheel_editable_pep660_basic(tmpdir: Path, script: PipTestEnvironment) - _assert_hook_not_called(project_dir, "build_editable") _assert_hook_called(project_dir, "prepare_metadata_for_build_wheel") _assert_hook_called(project_dir, "build_wheel") - assert len(os.listdir(str(wheel_dir))) == 1, "a wheel should have been created" + assert len(os.listdir(wheel_dir)) == 1, "a wheel should have been created" @pytest.mark.usefixtures("with_wheel") def test_download_editable_pep660_basic( - tmpdir: Path, script: PipTestEnvironment + tmp_path: pathlib.Path, script: PipTestEnvironment ) -> None: """ Test 'pip download' of an editable pep 660 project. It must *not* call prepare_metadata_for_build_editable. """ - project_dir = _make_project(tmpdir, BACKEND_WITH_PEP660, with_setup_py=False) - reqs_file = tmpdir / "requirements.txt" - reqs_file.write_text(f"-e {path_to_url(project_dir)}\n") - download_dir = tmpdir / "download" + project_dir = _make_project(tmp_path, BACKEND_WITH_PEP660, with_setup_py=False) + reqs_file = tmp_path / "requirements.txt" + reqs_file.write_text(f"-e {project_dir.as_uri()}\n") + download_dir = tmp_path / "download" script.pip( "download", "--no-index", @@ -230,4 +240,4 @@ def test_download_editable_pep660_basic( ) _assert_hook_not_called(project_dir, "prepare_metadata_for_build_editable") _assert_hook_called(project_dir, "prepare_metadata_for_build_wheel") - assert len(os.listdir(str(download_dir))) == 1, "a zip should have been created" + assert len(os.listdir(download_dir)) == 1, "a zip should have been created" diff --git a/tests/functional/test_show.py b/tests/functional/test_show.py index 6b434e51c56..aa4cd5b70ff 100644 --- a/tests/functional/test_show.py +++ b/tests/functional/test_show.py @@ -67,7 +67,7 @@ def test_show_with_files_from_legacy( # 'setup.py install' plus installed-files.txt, which we manually generate. source_dir = tmp_path.joinpath("unpacked-sdist") setuptools_record = tmp_path.joinpath("installed-record.txt") - untar_file(data.packages.joinpath("simple-1.0.tar.gz"), str(source_dir)) + untar_file(str(data.packages.joinpath("simple-1.0.tar.gz")), str(source_dir)) script.run( "python", "setup.py", diff --git a/tests/functional/test_uninstall.py b/tests/functional/test_uninstall.py index 431ea8dd5bf..11b1d587ca3 100644 --- a/tests/functional/test_uninstall.py +++ b/tests/functional/test_uninstall.py @@ -1,5 +1,6 @@ import logging import os +import pathlib import sys import textwrap from os.path import join, normpath @@ -19,7 +20,6 @@ need_svn, ) from tests.lib.local_repos import local_checkout, local_repo -from tests.lib.path import Path @pytest.mark.network @@ -55,7 +55,7 @@ def test_basic_uninstall_distutils(script: PipTestEnvironment) -> None: """ ) ) - result = script.run("python", pkg_path / "setup.py", "install") + result = script.run("python", str(pkg_path / "setup.py"), "install") result = script.pip("list", "--format=json") script.assert_installed(distutils_install="0.1") result = script.pip( @@ -245,7 +245,7 @@ def test_uninstall_entry_point_colon_in_name( ) script_name = script.bin_path.joinpath(console_scripts.split("=")[0].strip()) if sys.platform == "win32": - script_name += ".exe" + script_name = script_name.with_suffix(".exe") script.pip("install", pkg_path) assert script_name.exists() script.assert_installed(ep_install="0.1") @@ -272,7 +272,7 @@ def test_uninstall_gui_scripts(script: PipTestEnvironment) -> None: ) script_name = script.bin_path.joinpath("test_") if sys.platform == "win32": - script_name += ".exe" + script_name = script_name.with_suffix(".exe") script.pip("install", pkg_path) assert script_name.exists() script.pip("uninstall", pkg_name, "-y") @@ -299,7 +299,7 @@ def test_uninstall_console_scripts(script: PipTestEnvironment) -> None: [ script.venv / "build", "cache", - Path("scratch") / "discover" / "discover.egg-info", + "scratch/discover/discover.egg-info", ], ) @@ -353,7 +353,10 @@ def test_uninstall_easy_installed_console_scripts(script: PipTestEnvironment) -> @pytest.mark.xfail @pytest.mark.network @need_svn -def test_uninstall_editable_from_svn(script: PipTestEnvironment, tmpdir: Path) -> None: +def test_uninstall_editable_from_svn( + script: PipTestEnvironment, + tmp_path: pathlib.Path, +) -> None: """ Test uninstalling an editable installation from svn. """ @@ -361,7 +364,7 @@ def test_uninstall_editable_from_svn(script: PipTestEnvironment, tmpdir: Path) - "install", "-e", "{checkout}#egg=initools".format( - checkout=local_checkout("svn+http://svn.colorstudy.com/INITools", tmpdir) + checkout=local_checkout("svn+http://svn.colorstudy.com/INITools", tmp_path) ), ) result.assert_installed("INITools") @@ -380,7 +383,7 @@ def test_uninstall_editable_from_svn(script: PipTestEnvironment, tmpdir: Path) - @pytest.mark.network def test_uninstall_editable_with_source_outside_venv( - script: PipTestEnvironment, tmpdir: Path + script: PipTestEnvironment, tmp_path: pathlib.Path ) -> None: """ Test uninstalling editable install from existing source outside the venv. @@ -390,7 +393,7 @@ def test_uninstall_editable_with_source_outside_venv( temp_pkg_dir = join(temp, "pip-test-package") _test_uninstall_editable_with_source_outside_venv( script, - tmpdir, + tmp_path, temp_pkg_dir, ) finally: @@ -399,13 +402,13 @@ def test_uninstall_editable_with_source_outside_venv( def _test_uninstall_editable_with_source_outside_venv( script: PipTestEnvironment, - tmpdir: Path, + tmp_path: pathlib.Path, temp_pkg_dir: str, ) -> None: result = script.run( "git", "clone", - local_repo("git+https://github.com/pypa/pip-test-package", tmpdir), + local_repo("git+https://github.com/pypa/pip-test-package", tmp_path), temp_pkg_dir, expect_stderr=True, ) @@ -422,14 +425,17 @@ def _test_uninstall_editable_with_source_outside_venv( @pytest.mark.xfail @pytest.mark.network @need_svn -def test_uninstall_from_reqs_file(script: PipTestEnvironment, tmpdir: Path) -> None: +def test_uninstall_from_reqs_file( + script: PipTestEnvironment, + tmp_path: pathlib.Path, +) -> None: """ Test uninstall from a requirements file. """ local_svn_url = local_checkout( "svn+http://svn.colorstudy.com/INITools", - tmpdir, + tmp_path, ) script.scratch_path.joinpath("test-req.txt").write_text( textwrap.dedent( @@ -488,9 +494,11 @@ def test_uninstallpathset_no_paths(caplog: pytest.LogCaptureFixture) -> None: def test_uninstall_non_local_distutils( - caplog: pytest.LogCaptureFixture, monkeypatch: pytest.MonkeyPatch, tmpdir: Path + caplog: pytest.LogCaptureFixture, + monkeypatch: pytest.MonkeyPatch, + tmp_path: pathlib.Path, ) -> None: - einfo = tmpdir.joinpath("thing-1.0.egg-info") + einfo = tmp_path.joinpath("thing-1.0.egg-info") with open(einfo, "wb"): pass @@ -583,7 +591,7 @@ def test_uninstall_without_record_fails( @pytest.mark.skipif("sys.platform == 'win32'") def test_uninstall_with_symlink( - script: PipTestEnvironment, data: TestData, tmpdir: Path + script: PipTestEnvironment, data: TestData, tmp_path: pathlib.Path ) -> None: """ Test uninstalling a wheel, with an additional symlink @@ -591,7 +599,7 @@ def test_uninstall_with_symlink( """ package = data.packages.joinpath("simple.dist-0.1-py2.py3-none-any.whl") script.pip("install", package, "--no-index") - symlink_target = tmpdir / "target" + symlink_target = tmp_path / "target" symlink_target.mkdir() symlink_source = script.site_packages / "symlink" (script.base_path / symlink_source).symlink_to(symlink_target) diff --git a/tests/functional/test_vcs_bazaar.py b/tests/functional/test_vcs_bazaar.py index 06f9cbc8107..e68a637512f 100644 --- a/tests/functional/test_vcs_bazaar.py +++ b/tests/functional/test_vcs_bazaar.py @@ -3,6 +3,7 @@ """ import os +import pathlib import sys import pytest @@ -10,7 +11,6 @@ from pip._internal.vcs.bazaar import Bazaar from pip._internal.vcs.versioncontrol import RemoteNotFoundError from tests.lib import PipTestEnvironment, is_bzr_installed, need_bzr -from tests.lib.path import Path @pytest.mark.skipif( @@ -23,11 +23,14 @@ def test_ensure_bzr_available() -> None: @need_bzr -def test_get_remote_url__no_remote(script: PipTestEnvironment, tmpdir: Path) -> None: - repo_dir = tmpdir / "temp-repo" +def test_get_remote_url__no_remote( + script: PipTestEnvironment, + tmp_path: pathlib.Path, +) -> None: + repo_dir = tmp_path / "temp-repo" repo_dir.mkdir() - script.run("bzr", "init", repo_dir) + script.run("bzr", "init", str(repo_dir)) with pytest.raises(RemoteNotFoundError): - Bazaar().get_remote_url(repo_dir) + Bazaar().get_remote_url(str(repo_dir)) diff --git a/tests/functional/test_vcs_git.py b/tests/functional/test_vcs_git.py index b535d2eab87..c5dc3800ee1 100644 --- a/tests/functional/test_vcs_git.py +++ b/tests/functional/test_vcs_git.py @@ -12,13 +12,7 @@ from pip._internal.utils.misc import HiddenText from pip._internal.vcs import vcs from pip._internal.vcs.git import Git, RemoteNotFoundError -from tests.lib import ( - PipTestEnvironment, - _create_test_package, - _git_commit, - _test_path_to_file_url, -) -from tests.lib.path import Path +from tests.lib import PipTestEnvironment, _create_test_package, _git_commit def test_get_backend_for_scheme() -> None: @@ -66,11 +60,11 @@ def check_rev(repo_dir: str, rev: str, expected: Tuple[Optional[str], bool]) -> assert Git.get_revision_sha(repo_dir, rev) == expected -def test_git_dir_ignored(tmpdir: Path) -> None: +def test_git_dir_ignored(tmp_path: pathlib.Path) -> None: """ Test that a GIT_DIR environment variable is ignored. """ - repo_path = tmpdir / "test-repo" + repo_path = tmp_path / "test-repo" repo_path.mkdir() repo_dir = str(repo_path) @@ -80,11 +74,11 @@ def test_git_dir_ignored(tmpdir: Path) -> None: assert os.listdir(repo_dir) == [".git"] -def test_git_work_tree_ignored(tmpdir: Path) -> None: +def test_git_work_tree_ignored(tmp_path: pathlib.Path) -> None: """ Test that a GIT_WORK_TREE environment variable is ignored. """ - repo_path = tmpdir / "test-repo" + repo_path = tmp_path / "test-repo" repo_path.mkdir() repo_dir = str(repo_path) @@ -96,27 +90,29 @@ def test_git_work_tree_ignored(tmpdir: Path) -> None: Git.run_command(["status", repo_dir], extra_environ=env, cwd=repo_dir) -def test_get_remote_url(script: PipTestEnvironment, tmpdir: Path) -> None: - source_path = tmpdir / "source" +def test_get_remote_url(script: PipTestEnvironment, tmp_path: pathlib.Path) -> None: + source_path = tmp_path / "source" source_path.mkdir() - source_url = _test_path_to_file_url(source_path) + source_url = source_path.as_uri() source_dir = str(source_path) script.run("git", "init", cwd=source_dir) do_commit(script, source_dir) - repo_dir = str(tmpdir / "repo") + repo_dir = str(tmp_path / "repo") script.run("git", "clone", source_url, repo_dir) remote_url = Git.get_remote_url(repo_dir) assert remote_url == source_url -def test_get_remote_url__no_remote(script: PipTestEnvironment, tmpdir: Path) -> None: +def test_get_remote_url__no_remote( + script: PipTestEnvironment, tmp_path: pathlib.Path +) -> None: """ Test a repo with no remote. """ - repo_path = tmpdir / "temp-repo" + repo_path = tmp_path / "temp-repo" repo_path.mkdir() repo_dir = str(repo_path) @@ -145,13 +141,13 @@ def test_get_current_branch(script: PipTestEnvironment) -> None: def test_get_current_branch__branch_and_tag_same_name( - script: PipTestEnvironment, tmpdir: Path + script: PipTestEnvironment, tmp_path: pathlib.Path ) -> None: """ Check calling get_current_branch() from a branch or tag when the branch and tag have the same name. """ - repo_dir = str(tmpdir) + repo_dir = str(tmp_path) script.run("git", "init", cwd=repo_dir) do_commit(script, repo_dir) checkout_new_branch(script, repo_dir, "dev") @@ -229,23 +225,25 @@ def test_is_commit_id_equal(script: PipTestEnvironment) -> None: script.run("git", "branch", "branch0.1", cwd=version_pkg_path) commit = script.run("git", "rev-parse", "HEAD", cwd=version_pkg_path).stdout.strip() - assert Git.is_commit_id_equal(version_pkg_path, commit) - assert not Git.is_commit_id_equal(version_pkg_path, commit[:7]) - assert not Git.is_commit_id_equal(version_pkg_path, "branch0.1") - assert not Git.is_commit_id_equal(version_pkg_path, "abc123") + assert Git.is_commit_id_equal(str(version_pkg_path), commit) + assert not Git.is_commit_id_equal(str(version_pkg_path), commit[:7]) + assert not Git.is_commit_id_equal(str(version_pkg_path), "branch0.1") + assert not Git.is_commit_id_equal(str(version_pkg_path), "abc123") # Also check passing a None value. - assert not Git.is_commit_id_equal(version_pkg_path, None) + assert not Git.is_commit_id_equal(str(version_pkg_path), None) def test_is_immutable_rev_checkout(script: PipTestEnvironment) -> None: version_pkg_path = _create_test_package(script) commit = script.run("git", "rev-parse", "HEAD", cwd=version_pkg_path).stdout.strip() assert Git().is_immutable_rev_checkout( - "git+https://g.c/o/r@" + commit, version_pkg_path + "git+https://g.c/o/r@" + commit, str(version_pkg_path) + ) + assert not Git().is_immutable_rev_checkout( + "git+https://g.c/o/r", str(version_pkg_path) ) - assert not Git().is_immutable_rev_checkout("git+https://g.c/o/r", version_pkg_path) assert not Git().is_immutable_rev_checkout( - "git+https://g.c/o/r@master", version_pkg_path + "git+https://g.c/o/r@master", str(version_pkg_path) ) @@ -254,11 +252,11 @@ def test_get_repository_root(script: PipTestEnvironment) -> None: tests_path = version_pkg_path.joinpath("tests") tests_path.mkdir() - root1 = Git.get_repository_root(version_pkg_path) + root1 = Git.get_repository_root(str(version_pkg_path)) assert root1 is not None assert os.path.normcase(root1) == os.path.normcase(version_pkg_path) - root2 = Git.get_repository_root(version_pkg_path.joinpath("tests")) + root2 = Git.get_repository_root(str(version_pkg_path.joinpath("tests"))) assert root2 is not None assert os.path.normcase(root2) == os.path.normcase(version_pkg_path) diff --git a/tests/functional/test_vcs_mercurial.py b/tests/functional/test_vcs_mercurial.py index 3ac7ac3d1fc..47b26d375c8 100644 --- a/tests/functional/test_vcs_mercurial.py +++ b/tests/functional/test_vcs_mercurial.py @@ -10,10 +10,10 @@ def test_get_repository_root(script: PipTestEnvironment) -> None: tests_path = version_pkg_path.joinpath("tests") tests_path.mkdir() - root1 = Mercurial.get_repository_root(version_pkg_path) + root1 = Mercurial.get_repository_root(str(version_pkg_path)) assert root1 is not None assert os.path.normcase(root1) == os.path.normcase(version_pkg_path) - root2 = Mercurial.get_repository_root(version_pkg_path.joinpath("tests")) + root2 = Mercurial.get_repository_root(str(version_pkg_path.joinpath("tests"))) assert root2 is not None assert os.path.normcase(root2) == os.path.normcase(version_pkg_path) diff --git a/tests/functional/test_vcs_subversion.py b/tests/functional/test_vcs_subversion.py index 91627af8688..06eed0b58d6 100644 --- a/tests/functional/test_vcs_subversion.py +++ b/tests/functional/test_vcs_subversion.py @@ -1,14 +1,18 @@ +import pathlib + import pytest from pip._internal.vcs.subversion import Subversion from pip._internal.vcs.versioncontrol import RemoteNotFoundError from tests.lib import PipTestEnvironment, _create_svn_repo, need_svn -from tests.lib.path import Path @need_svn -def test_get_remote_url__no_remote(script: PipTestEnvironment, tmpdir: Path) -> None: - repo_path = tmpdir / "temp-repo" +def test_get_remote_url__no_remote( + script: PipTestEnvironment, + tmp_path: pathlib.Path, +) -> None: + repo_path = tmp_path / "temp-repo" repo_path.mkdir() repo_dir = str(repo_path) @@ -20,9 +24,9 @@ def test_get_remote_url__no_remote(script: PipTestEnvironment, tmpdir: Path) -> @need_svn def test_get_remote_url__no_remote_with_setup( - script: PipTestEnvironment, tmpdir: Path + script: PipTestEnvironment, tmp_path: pathlib.Path ) -> None: - repo_path = tmpdir / "temp-repo" + repo_path = tmp_path / "temp-repo" repo_path.mkdir() setup = repo_path / "setup.py" setup.touch() diff --git a/tests/functional/test_warning.py b/tests/functional/test_warning.py index a7018944873..e04f98708ff 100644 --- a/tests/functional/test_warning.py +++ b/tests/functional/test_warning.py @@ -1,15 +1,15 @@ +import pathlib import sys import textwrap import pytest from tests.lib import PipTestEnvironment -from tests.lib.path import Path @pytest.fixture -def warnings_demo(tmpdir: Path) -> Path: - demo = tmpdir.joinpath("warnings_demo.py") +def warnings_demo(tmp_path: pathlib.Path) -> pathlib.Path: + demo = tmp_path.joinpath("warnings_demo.py") demo.write_text( textwrap.dedent( """ @@ -27,18 +27,18 @@ def warnings_demo(tmpdir: Path) -> Path: def test_deprecation_warnings_are_correct( - script: PipTestEnvironment, warnings_demo: Path + script: PipTestEnvironment, warnings_demo: pathlib.Path ) -> None: - result = script.run("python", warnings_demo, expect_stderr=True) + result = script.run("python", str(warnings_demo), expect_stderr=True) expected = "WARNING:pip._internal.deprecations:DEPRECATION: deprecated!\n" assert result.stderr == expected def test_deprecation_warnings_can_be_silenced( - script: PipTestEnvironment, warnings_demo: Path + script: PipTestEnvironment, warnings_demo: pathlib.Path ) -> None: script.environ["PYTHONWARNINGS"] = "ignore" - result = script.run("python", warnings_demo) + result = script.run("python", str(warnings_demo)) assert result.stderr == "" diff --git a/tests/functional/test_wheel.py b/tests/functional/test_wheel.py index dedf22ba8cc..66bdd8fe774 100644 --- a/tests/functional/test_wheel.py +++ b/tests/functional/test_wheel.py @@ -1,5 +1,6 @@ """'pip wheel' tests""" import os +import pathlib import re import sys @@ -8,12 +9,11 @@ from pip._internal.cli.status_codes import ERROR from tests.lib import pyversion # noqa: F401 from tests.lib import PipTestEnvironment, TestData -from tests.lib.path import Path pytestmark = pytest.mark.usefixtures("with_wheel") -def add_files_to_dist_directory(folder: Path) -> None: +def add_files_to_dist_directory(folder: pathlib.Path) -> None: (folder / "dist").mkdir(parents=True) (folder / "dist" / "a_name-0.0.1.tar.gz").write_text("hello") # Not adding a wheel file since that confuses setuptools' backend. @@ -154,9 +154,9 @@ def test_pip_wheel_builds_when_no_binary_set( @pytest.mark.skipif("sys.platform == 'win32'") def test_pip_wheel_readonly_cache( - script: PipTestEnvironment, data: TestData, tmpdir: Path + script: PipTestEnvironment, data: TestData, tmp_path: pathlib.Path ) -> None: - cache_dir = tmpdir / "cache" + cache_dir = tmp_path / "cache" cache_dir.mkdir() os.chmod(cache_dir, 0o400) # read-only cache # Check that the wheel package is ignored @@ -204,7 +204,7 @@ def test_pip_wheel_builds_editable(script: PipTestEnvironment, data: TestData) - @pytest.mark.network def test_pip_wheel_git_editable_keeps_clone( - script: PipTestEnvironment, tmpdir: Path + script: PipTestEnvironment, tmp_path: pathlib.Path ) -> None: """ Test that `pip wheel -e giturl` preserves a git clone in src. @@ -215,24 +215,24 @@ def test_pip_wheel_git_editable_keeps_clone( "-e", "git+https://github.com/pypa/pip-test-package#egg=pip-test-package", "--src", - tmpdir / "src", + tmp_path / "src", "--wheel-dir", - tmpdir, + tmp_path, ) - assert (tmpdir / "src" / "pip-test-package").exists() - assert (tmpdir / "src" / "pip-test-package" / ".git").exists() + assert (tmp_path / "src" / "pip-test-package").exists() + assert (tmp_path / "src" / "pip-test-package" / ".git").exists() def test_pip_wheel_builds_editable_does_not_create_zip( - script: PipTestEnvironment, data: TestData, tmpdir: Path + script: PipTestEnvironment, data: TestData, tmp_path: pathlib.Path ) -> None: """ Test 'pip wheel' of editables does not create zip files (regression test for issue #9122) """ - wheel_dir = tmpdir / "wheel_dir" + wheel_dir = tmp_path / "wheel_dir" wheel_dir.mkdir() - editable_path = os.path.join(data.src, "simplewheel-1.0") + editable_path = data.src.joinpath("simplewheel-1.0") script.pip("wheel", "--no-deps", "-e", editable_path, "-w", wheel_dir) wheels = os.listdir(wheel_dir) assert len(wheels) == 1 @@ -289,7 +289,7 @@ def test_wheel_package_with_latin1_setup( def test_pip_wheel_with_pep518_build_reqs( - script: PipTestEnvironment, data: TestData, common_wheels: Path + script: PipTestEnvironment, data: TestData, common_wheels: pathlib.Path ) -> None: result = script.pip( "wheel", @@ -327,13 +327,17 @@ def test_pip_wheel_with_pep518_build_reqs_no_isolation( def test_pip_wheel_with_user_set_in_config( - script: PipTestEnvironment, data: TestData, common_wheels: Path + script: PipTestEnvironment, data: TestData, common_wheels: pathlib.Path ) -> None: config_file = script.scratch_path / "pip.conf" script.environ["PIP_CONFIG_FILE"] = str(config_file) config_file.write_text("[install]\nuser = true") result = script.pip( - "wheel", data.src / "withpyproject", "--no-index", "-f", common_wheels + "wheel", + data.src / "withpyproject", + "--no-index", + "-f", + common_wheels, ) assert "Successfully built withpyproject" in result.stdout, result.stdout @@ -343,7 +347,7 @@ def test_pip_wheel_with_user_set_in_config( reason="The empty extension module does not work on Win", ) def test_pip_wheel_ext_module_with_tmpdir_inside( - script: PipTestEnvironment, data: TestData, common_wheels: Path + script: PipTestEnvironment, data: TestData, common_wheels: pathlib.Path ) -> None: tmpdir = data.src / "extension/tmp" tmpdir.mkdir() @@ -354,7 +358,11 @@ def test_pip_wheel_ext_module_with_tmpdir_inside( script.environ["CC"] = script.environ["LDSHARED"] = "true" result = script.pip( - "wheel", data.src / "extension", "--no-index", "-f", common_wheels + "wheel", + data.src / "extension", + "--no-index", + "-f", + common_wheels, ) assert "Successfully built extension" in result.stdout, result.stdout diff --git a/tests/lib/__init__.py b/tests/lib/__init__.py index c8d68fea9b0..84d97aceb61 100644 --- a/tests/lib/__init__.py +++ b/tests/lib/__init__.py @@ -16,6 +16,7 @@ TYPE_CHECKING, Any, Callable, + Collection, Dict, Iterator, List, @@ -38,7 +39,6 @@ from pip._internal.models.target_python import TargetPython from pip._internal.network.session import PipSession from pip._internal.utils.deprecation import DEPRECATION_MSG_PREFIX -from tests.lib.path import Path, curdir from tests.lib.venv import VirtualEnvironment from tests.lib.wheel import make_wheel @@ -50,8 +50,8 @@ else: ResolverVariant = str -DATA_DIR = Path(__file__).parent.parent.joinpath("data").resolve() -SRC_DIR = Path(__file__).resolve().parent.parent.parent +DATA_DIR = pathlib.Path(__file__).parent.parent.joinpath("data").resolve() +SRC_DIR = pathlib.Path(__file__).resolve().parent.parent.parent pyversion = get_major_minor_version() @@ -65,33 +65,6 @@ def assert_paths_equal(actual: str, expected: str) -> None: assert os.path.normpath(actual) == os.path.normpath(expected) -def path_to_url(path: str) -> str: - """ - Convert a path to URI. The path will be made absolute and - will not have quoted path parts. - (adapted from pip.util) - """ - path = os.path.normpath(os.path.abspath(path)) - drive, path = os.path.splitdrive(path) - filepath = path.split(os.path.sep) - url = "/".join(filepath) - if drive: - # Note: match urllib.request.pathname2url's - # behavior: uppercase the drive letter. - return "file:///" + drive.upper() + url - return "file://" + url - - -def _test_path_to_file_url(path: Path) -> str: - """ - Convert a test Path to a "file://" URL. - - Args: - path: a tests.lib.path.Path object. - """ - return "file://" + path.resolve().replace("\\", "/") - - def create_file(path: str, contents: Optional[str] = None) -> None: """Create a file on the path, with the given contents""" from pip._internal.utils.misc import ensure_dir @@ -178,12 +151,16 @@ class TestData: __test__ = False - def __init__(self, root: str, source: Optional[Path] = None) -> None: + def __init__( + self, + root: pathlib.Path, + source: Optional[pathlib.Path] = None, + ) -> None: self.source = source or DATA_DIR - self.root = Path(root).resolve() + self.root = root.resolve() @classmethod - def copy(cls, root: str) -> "TestData": + def copy(cls, root: pathlib.Path) -> "TestData": obj = cls(root) obj.reset() return obj @@ -196,51 +173,51 @@ def reset(self) -> None: shutil.copytree(self.source, self.root, symlinks=True) @property - def packages(self) -> Path: + def packages(self) -> pathlib.Path: return self.root.joinpath("packages") @property - def packages2(self) -> Path: + def packages2(self) -> pathlib.Path: return self.root.joinpath("packages2") @property - def packages3(self) -> Path: + def packages3(self) -> pathlib.Path: return self.root.joinpath("packages3") @property - def src(self) -> Path: + def src(self) -> pathlib.Path: return self.root.joinpath("src") @property - def indexes(self) -> Path: + def indexes(self) -> pathlib.Path: return self.root.joinpath("indexes") @property - def reqfiles(self) -> Path: + def reqfiles(self) -> pathlib.Path: return self.root.joinpath("reqfiles") @property - def completion_paths(self) -> Path: + def completion_paths(self) -> pathlib.Path: return self.root.joinpath("completion_paths") @property def find_links(self) -> str: - return path_to_url(self.packages) + return self.packages.as_uri() @property def find_links2(self) -> str: - return path_to_url(self.packages2) + return self.packages2.as_uri() @property def find_links3(self) -> str: - return path_to_url(self.packages3) + return self.packages3.as_uri() @property def backends(self) -> str: - return path_to_url(self.root.joinpath("backends")) + return self.root.joinpath("backends").as_uri() def index_url(self, index: str = "simple") -> str: - return path_to_url(self.root.joinpath("indexes", index)) + return self.root.joinpath("indexes", index).as_uri() class TestFailure(AssertionError): @@ -248,7 +225,8 @@ class TestFailure(AssertionError): An "assertion" failed during testing. """ - pass + +StrPath = Union[str, pathlib.Path] class TestPipResult: @@ -355,8 +333,8 @@ def assert_installed( maybe = "" if without_egg_link else "not " raise TestFailure(f"{pth_file} unexpectedly {maybe}updated by install") - if (pkg_dir in self.files_created) == (curdir in without_files): - maybe = "not " if curdir in without_files else "" + if (pkg_dir in self.files_created) == (os.curdir in without_files): + maybe = "not " if os.curdir in without_files else "" files = sorted(self.files_created) raise TestFailure( textwrap.dedent( @@ -382,17 +360,25 @@ def assert_installed( f"Package directory {pkg_dir!r} has unexpected content {f}" ) - def did_create(self, path: str, message: Optional[str] = None) -> None: - assert str(path) in self.files_created, _one_or_both(message, self) + @property + def _paths_created(self) -> Collection[pathlib.Path]: + return {pathlib.Path(s) for s in self.files_created} + + @property + def _paths_updated(self) -> Collection[pathlib.Path]: + return {pathlib.Path(s) for s in self.files_updated} + + def did_create(self, path: StrPath, message: Optional[str] = None) -> None: + assert pathlib.Path(path) in self._paths_created, _one_or_both(message, self) - def did_not_create(self, path: str, message: Optional[str] = None) -> None: - assert str(path) not in self.files_created, _one_or_both(message, self) + def did_not_create(self, p: StrPath, message: Optional[str] = None) -> None: + assert pathlib.Path(p) not in self._paths_created, _one_or_both(message, self) - def did_update(self, path: str, message: Optional[str] = None) -> None: - assert str(path) in self.files_updated, _one_or_both(message, self) + def did_update(self, path: StrPath, message: Optional[str] = None) -> None: + assert pathlib.Path(path) in self._paths_updated, _one_or_both(message, self) - def did_not_update(self, path: str, message: Optional[str] = None) -> None: - assert str(path) not in self.files_updated, _one_or_both(message, self) + def did_not_update(self, p: StrPath, message: Optional[str] = None) -> None: + assert pathlib.Path(p) not in self._paths_updated, _one_or_both(message, self) def _one_or_both(a: Optional[str], b: Any) -> str: @@ -487,15 +473,12 @@ class PipTestEnvironment(TestFileEnvironment): def __init__( self, - base_path: str, + base_path: pathlib.Path, *args: Any, virtualenv: VirtualEnvironment, pip_expect_warning: bool = False, **kwargs: Any, ) -> None: - # Make our base_path a test.lib.path.Path object - base_path = Path(base_path) - # Store paths related to the virtual environment self.venv_path = virtualenv.location self.lib_path = virtualenv.lib @@ -511,7 +494,7 @@ def __init__( site.USER_SITE[len(site.USER_BASE) + 1 :], ) if sys.platform == "win32": - scripts_base = Path(os.path.normpath(self.user_site_path.joinpath(".."))) + scripts_base = self.user_site_path.joinpath("..") self.user_bin_path = scripts_base.joinpath("Scripts") else: self.user_bin_path = self.user_base_path.joinpath( @@ -527,8 +510,8 @@ def __init__( # Setup our environment environ = kwargs.setdefault("environ", os.environ.copy()) - environ["PATH"] = Path.pathsep.join( - [self.bin_path] + [environ.get("PATH", [])], + environ["PATH"] = os.pathsep.join( + [str(self.bin_path), environ.get("PATH", "")], ) environ["PYTHONUSERBASE"] = self.user_base_path # Writing bytecode can mess up updated file detection @@ -556,13 +539,13 @@ def __init__( "scratch", ]: real_name = f"{name}_path" - relative_path = Path( + relative_path = pathlib.Path( os.path.relpath(getattr(self, real_name), self.base_path) ) setattr(self, name, relative_path) # Make sure temp_path is a Path object - self.temp_path: Path = Path(self.temp_path) + self.temp_path: pathlib.Path = pathlib.Path(self.temp_path) # Ensure the tmp dir exists, things break horribly if it doesn't self.temp_path.mkdir() @@ -676,7 +659,12 @@ def run( return TestPipResult(result, verbose=self.verbose) - def pip(self, *args: str, use_module: bool = True, **kwargs: Any) -> TestPipResult: + def pip( + self, + *args: Union[str, pathlib.Path], + use_module: bool = True, + **kwargs: Any, + ) -> TestPipResult: __tracebackhide__ = True if self.pip_expect_warning: kwargs["allow_stderr_warning"] = True @@ -685,14 +673,18 @@ def pip(self, *args: str, use_module: bool = True, **kwargs: Any) -> TestPipResu args = ("-m", "pip") + args else: exe = "pip" - return self.run(exe, *args, **kwargs) + return self.run(exe, *(os.fspath(a) for a in args), **kwargs) - def pip_install_local(self, *args: str, **kwargs: Any) -> TestPipResult: + def pip_install_local( + self, + *args: Union[str, pathlib.Path], + **kwargs: Any, + ) -> TestPipResult: return self.pip( "install", "--no-index", "--find-links", - path_to_url(os.path.join(DATA_DIR, "packages")), + pathlib.Path(DATA_DIR, "packages").as_uri(), *args, **kwargs, ) @@ -813,7 +805,9 @@ def assert_all_changes( def _create_main_file( - dir_path: Path, name: Optional[str] = None, output: Optional[str] = None + dir_path: pathlib.Path, + name: Optional[str] = None, + output: Optional[str] = None, ) -> None: """ Create a module with a main() function that prints the given output. @@ -834,7 +828,7 @@ def main(): def _git_commit( env_or_script: PipTestEnvironment, - repo_dir: str, + repo_dir: Union[str, pathlib.Path], message: Optional[str] = None, allow_empty: bool = False, stage_modified: bool = False, @@ -871,8 +865,10 @@ def _git_commit( def _vcs_add( - script: PipTestEnvironment, version_pkg_path: Path, vcs: str = "git" -) -> Path: + script: PipTestEnvironment, + version_pkg_path: pathlib.Path, + vcs: str = "git", +) -> pathlib.Path: if vcs == "git": script.run("git", "init", cwd=version_pkg_path) script.run("git", "add", ".", cwd=version_pkg_path) @@ -895,10 +891,7 @@ def _vcs_add( script.run( "svn", "checkout", repo_url, "pip-test-package", cwd=script.scratch_path ) - checkout_path: str = script.scratch_path / "pip-test-package" - - # svn internally stores windows drives as uppercase; we'll match that. - checkout_path = Path(checkout_path.replace("c:", "C:")) + checkout_path = script.scratch_path / "pip-test-package" version_pkg_path = checkout_path elif vcs == "bazaar": @@ -924,7 +917,7 @@ def _vcs_add( def _create_test_package_with_subdirectory( script: PipTestEnvironment, subdirectory: str -) -> Path: +) -> pathlib.Path: script.scratch_path.joinpath("version_pkg").mkdir() version_pkg_path = script.scratch_path / "version_pkg" _create_main_file(version_pkg_path, name="version_pkg", output="0.1") @@ -973,7 +966,7 @@ def _create_test_package_with_subdirectory( def _create_test_package_with_srcdir( script: PipTestEnvironment, name: str = "version_pkg", vcs: str = "git" -) -> Path: +) -> pathlib.Path: script.scratch_path.joinpath(name).mkdir() version_pkg_path = script.scratch_path / name subdir_path = version_pkg_path.joinpath("subdir") @@ -1003,7 +996,7 @@ def _create_test_package_with_srcdir( def _create_test_package( script: PipTestEnvironment, name: str = "version_pkg", vcs: str = "git" -) -> Path: +) -> pathlib.Path: script.scratch_path.joinpath(name).mkdir() version_pkg_path = script.scratch_path / name _create_main_file(version_pkg_path, name=name, output="0.1") @@ -1026,13 +1019,16 @@ def _create_test_package( return _vcs_add(script, version_pkg_path, vcs) -def _create_svn_repo(script: PipTestEnvironment, version_pkg_path: str) -> str: - repo_url = path_to_url(script.scratch_path / "pip-test-package-repo" / "trunk") +def _create_svn_repo( + script: PipTestEnvironment, + version_pkg_path: Union[pathlib.Path, str], +) -> str: + repo_url = script.scratch_path.joinpath("pip-test-package-repo", "trunk").as_uri() script.run("svnadmin", "create", "pip-test-package-repo", cwd=script.scratch_path) script.run( "svn", "import", - version_pkg_path, + str(version_pkg_path), repo_url, "-m", "Initial import of pip-test-package", @@ -1042,7 +1038,7 @@ def _create_svn_repo(script: PipTestEnvironment, version_pkg_path: str) -> str: def _change_test_package_version( - script: PipTestEnvironment, version_pkg_path: Path + script: PipTestEnvironment, version_pkg_path: pathlib.Path ) -> None: _create_main_file( version_pkg_path, name="version_pkg", output="some different version" @@ -1052,15 +1048,15 @@ def _change_test_package_version( @contextmanager -def requirements_file(contents: str, tmpdir: Path) -> Iterator[Path]: +def requirements_file(contents: str, tmp_path: pathlib.Path) -> Iterator[pathlib.Path]: """Return a Path to a requirements file of given contents. As long as the context manager is open, the requirements file will exist. - :param tmpdir: A Path to the folder in which to create the file + :param tmp_path: A Path to the folder in which to create the file """ - path = tmpdir / "reqs.txt" + path = tmp_path / "reqs.txt" path.write_text(contents) yield path path.unlink() @@ -1068,7 +1064,7 @@ def requirements_file(contents: str, tmpdir: Path) -> Iterator[Path]: def create_test_package_with_setup( script: PipTestEnvironment, **setup_kwargs: Any -) -> Path: +) -> pathlib.Path: assert "name" in setup_kwargs, setup_kwargs pkg_path = script.scratch_path / setup_kwargs["name"] pkg_path.mkdir() @@ -1128,7 +1124,7 @@ def create_basic_wheel_for_package( extras: Dict[str, List[str]] = None, requires_python: Optional[str] = None, extra_files: Optional[Dict[str, Union[bytes, str]]] = None, -) -> Path: +) -> pathlib.Path: if depends is None: depends = [] if extras is None: @@ -1188,7 +1184,7 @@ def create_basic_sdist_for_package( *, fails_egg_info: bool = False, fails_bdist_wheel: bool = False, -) -> Path: +) -> pathlib.Path: files = { "setup.py": f"""\ import sys @@ -1227,7 +1223,7 @@ def create_basic_sdist_for_package( retval = script.scratch_path / archive_name generated = shutil.make_archive( - retval, + str(retval), "gztar", root_dir=script.temp_path, base_dir=os.curdir, diff --git a/tests/lib/direct_url.py b/tests/lib/direct_url.py index ec0a32b4d66..98d7c61f661 100644 --- a/tests/lib/direct_url.py +++ b/tests/lib/direct_url.py @@ -1,12 +1,15 @@ +import pathlib import re from typing import Optional from pip._internal.models.direct_url import DIRECT_URL_METADATA_NAME, DirectUrl from tests.lib import TestPipResult -from tests.lib.path import Path -def get_created_direct_url_path(result: TestPipResult, pkg: str) -> Optional[Path]: +def get_created_direct_url_path( + result: TestPipResult, + pkg: str, +) -> Optional[pathlib.Path]: direct_url_metadata_re = re.compile( pkg + r"-[\d\.]+\.dist-info." + DIRECT_URL_METADATA_NAME + r"$" ) diff --git a/tests/lib/git_submodule_helpers.py b/tests/lib/git_submodule_helpers.py index 32a3c000287..5f8811f4c12 100644 --- a/tests/lib/git_submodule_helpers.py +++ b/tests/lib/git_submodule_helpers.py @@ -1,11 +1,11 @@ +import pathlib import textwrap from typing import Tuple from tests.lib import PipTestEnvironment, _create_main_file, _git_commit -from tests.lib.path import Path -def _create_test_package_submodule(env: PipTestEnvironment) -> Path: +def _create_test_package_submodule(env: PipTestEnvironment) -> pathlib.Path: env.scratch_path.joinpath("version_pkg_submodule").mkdir() submodule_path = env.scratch_path / "version_pkg_submodule" env.run("touch", "testfile", cwd=submodule_path) @@ -16,8 +16,8 @@ def _create_test_package_submodule(env: PipTestEnvironment) -> Path: return submodule_path -def _change_test_package_submodule( - env: PipTestEnvironment, submodule_path: Path +def change_test_package_submodule( + env: PipTestEnvironment, submodule_path: pathlib.Path ) -> None: submodule_path.joinpath("testfile").write_text("this is a changed file") submodule_path.joinpath("testfile2").write_text("this is an added file") @@ -25,8 +25,8 @@ def _change_test_package_submodule( _git_commit(env, submodule_path, message="submodule change") -def _pull_in_submodule_changes_to_module( - env: PipTestEnvironment, module_path: Path, rel_path: str +def pull_in_submodule_changes_to_module( + env: PipTestEnvironment, module_path: pathlib.Path, rel_path: str ) -> None: """ Args: @@ -38,9 +38,9 @@ def _pull_in_submodule_changes_to_module( _git_commit(env, module_path, message="submodule change", stage_modified=True) -def _create_test_package_with_submodule( +def create_test_package_with_submodule( env: PipTestEnvironment, rel_path: str -) -> Tuple[Path, Path]: +) -> Tuple[pathlib.Path, pathlib.Path]: """ Args: rel_path: the location of the submodule relative to the superproject. @@ -73,7 +73,7 @@ def _create_test_package_with_submodule( "git", "submodule", "add", - submodule_path, + str(submodule_path), rel_path, cwd=version_pkg_path, ) diff --git a/tests/lib/local_repos.py b/tests/lib/local_repos.py index 2ead17aca0b..afcb966d832 100644 --- a/tests/lib/local_repos.py +++ b/tests/lib/local_repos.py @@ -1,18 +1,17 @@ import os +import pathlib import subprocess import urllib.request from pip._internal.utils.misc import hide_url from pip._internal.vcs import vcs -from tests.lib import path_to_url -from tests.lib.path import Path -def _create_svn_initools_repo(initools_dir: str) -> None: +def _create_svn_initools_repo(initools_dir: pathlib.Path) -> None: """ Create the SVN INITools repo. """ - directory = os.path.dirname(initools_dir) + directory = initools_dir.parent subprocess.check_call("svnadmin create INITools".split(), cwd=directory) filename, _ = urllib.request.urlretrieve( @@ -21,7 +20,7 @@ def _create_svn_initools_repo(initools_dir: str) -> None: ) with open(filename) as dump: subprocess.check_call( - ["svnadmin", "load", initools_dir], + ["svnadmin", "load", str(initools_dir)], stdin=dump, stdout=subprocess.DEVNULL, ) @@ -30,7 +29,7 @@ def _create_svn_initools_repo(initools_dir: str) -> None: def local_checkout( remote_repo: str, - temp_path: Path, + temp_path: pathlib.Path, ) -> str: """ :param temp_path: the return value of the tmpdir fixture, which is a @@ -42,23 +41,22 @@ def local_checkout( repository_name = os.path.basename(remote_repo) directory = temp_path.joinpath("cache") - repo_url_path = os.path.join(directory, repository_name) - assert not os.path.exists(repo_url_path) + repo_url_path = directory.joinpath(repository_name) + assert not repo_url_path.exists() - if not os.path.exists(directory): - os.mkdir(directory) + directory.mkdir(exist_ok=True) if vcs_name == "svn": assert repository_name == "INITools" _create_svn_initools_repo(repo_url_path) - repo_url_path = os.path.join(repo_url_path, "trunk") + repo_url_path = repo_url_path.joinpath("trunk") else: vcs_backend = vcs.get_backend(vcs_name) assert vcs_backend is not None - vcs_backend.obtain(repo_url_path, url=hide_url(remote_repo), verbosity=0) + vcs_backend.obtain(str(repo_url_path), url=hide_url(remote_repo), verbosity=0) - return "{}+{}".format(vcs_name, path_to_url(repo_url_path)) + return "{}+{}".format(vcs_name, repo_url_path.as_uri()) -def local_repo(remote_repo: str, temp_path: Path) -> str: +def local_repo(remote_repo: str, temp_path: pathlib.Path) -> str: return local_checkout(remote_repo, temp_path).split("+", 1)[1] diff --git a/tests/lib/path.py b/tests/lib/path.py deleted file mode 100644 index ea8c819ec74..00000000000 --- a/tests/lib/path.py +++ /dev/null @@ -1,190 +0,0 @@ -# Author: Aziz Köksal -import glob -import os -from typing import Iterable, Iterator, Union - - -class Path(str): - """ - Models a path in an object oriented way. - """ - - # File system path separator: '/' or '\'. - sep = os.sep - - # Separator in the PATH environment variable. - pathsep = os.pathsep - - def __new__(cls, *paths: str) -> "Path": - if len(paths): - return super().__new__(cls, os.path.join(*paths)) - return super().__new__(cls) - - def __div__(self, path: str) -> "Path": - """ - Joins this path with another path. - - >>> path_obj / 'bc.d' - >>> path_obj / path_obj2 - """ - return Path(self, path) - - __truediv__ = __div__ - - def __rdiv__(self, path: str) -> "Path": - """ - Joins this path with another path. - - >>> "/home/a" / path_obj - """ - return Path(path, self) - - __rtruediv__ = __rdiv__ - - def __idiv__(self, path: str) -> "Path": - """ - Like __div__ but also assigns to the variable. - - >>> path_obj /= 'bc.d' - """ - return Path(self, path) - - __itruediv__ = __idiv__ - - def __add__(self, path: str) -> "Path": - """ - >>> Path('/home/a') + 'bc.d' - '/home/abc.d' - """ - return Path(str(self) + path) - - def __radd__(self, path: str) -> "Path": - """ - >>> '/home/a' + Path('bc.d') - '/home/abc.d' - """ - return Path(path + str(self)) - - def __repr__(self) -> str: - return "Path({inner})".format(inner=str.__repr__(self)) - - @property - def name(self) -> str: - """ - '/home/a/bc.d' -> 'bc.d' - """ - return os.path.basename(self) - - @property - def stem(self) -> str: - """ - '/home/a/bc.d' -> 'bc' - """ - return Path(os.path.splitext(self)[0]).name - - @property - def suffix(self) -> str: - """ - '/home/a/bc.d' -> '.d' - """ - return Path(os.path.splitext(self)[1]) - - def resolve(self) -> "Path": - """ - Resolves symbolic links. - """ - return Path(os.path.realpath(self)) - - @property - def parent(self) -> "Path": - """ - Returns the parent directory of this path. - - '/home/a/bc.d' -> '/home/a' - '/home/a/' -> '/home/a' - '/home/a' -> '/home' - """ - return Path(os.path.dirname(self)) - - def exists(self) -> bool: - """ - Returns True if the path exists. - """ - return os.path.exists(self) - - def mkdir( - self, - mode: int = 0o777, - exist_ok: bool = False, - parents: bool = False, - ) -> None: - """ - Creates a directory, if it doesn't exist already. - - :param parents: Whether to create parent directories. - """ - - maker_func = os.makedirs if parents else os.mkdir - try: - maker_func(self, mode) - except OSError: - if not exist_ok or not os.path.isdir(self): - raise - - def unlink(self) -> None: - """ - Removes a file. - """ - os.remove(self) - - def rmdir(self) -> None: - """ - Removes a directory. - """ - os.rmdir(self) - - def rename(self, to: str) -> None: - """ - Renames a file or directory. May throw an OSError. - """ - os.rename(self, to) - - def glob(self, pattern: str) -> Iterator["Path"]: - return (Path(i) for i in glob.iglob(self.joinpath(pattern))) - - def joinpath(self, *parts: str) -> "Path": - return Path(self, *parts) - - # TODO: Remove after removing inheritance from str. - def join(self, parts: Iterable[str]) -> str: - raise RuntimeError("Path.join is invalid, use joinpath instead.") - - def read_bytes(self) -> bytes: - with open(self, "rb") as fp: - return fp.read() - - def write_bytes(self, content: bytes) -> None: - with open(self, "wb") as f: - f.write(content) - - def read_text(self) -> str: - with open(self, "r") as fp: - return fp.read() - - def write_text(self, content: str) -> None: - with open(self, "w") as fp: - fp.write(content) - - def touch(self) -> None: - with open(self, "a") as fp: - path: Union[int, str] = fp.fileno() if os.utime in os.supports_fd else self - os.utime(path) - - def symlink_to(self, target: str) -> None: - os.symlink(target, self) - - def stat(self) -> os.stat_result: - return os.stat(self) - - -curdir = Path(os.path.curdir) diff --git a/tests/lib/server.py b/tests/lib/server.py index 95cc6a23e34..4b5add345d3 100644 --- a/tests/lib/server.py +++ b/tests/lib/server.py @@ -1,4 +1,4 @@ -import os +import pathlib import ssl import threading from base64 import b64encode @@ -166,46 +166,34 @@ def link(name: str, value: str) -> str: return text_html_response(html5_page(links)) -def file_response(path: str) -> "WSGIApplication": +def file_response(path: pathlib.Path) -> "WSGIApplication": def responder(environ: "WSGIEnvironment", start_response: "StartResponse") -> Body: - size = os.stat(path).st_size start_response( "200 OK", [ ("Content-Type", "application/octet-stream"), - ("Content-Length", str(size)), + ("Content-Length", str(path.stat().st_size)), ], ) - - with open(path, "rb") as f: - return [f.read()] + return [path.read_bytes()] return responder -def authorization_response(path: str) -> "WSGIApplication": +def authorization_response(path: pathlib.Path) -> "WSGIApplication": correct_auth = "Basic " + b64encode(b"USERNAME:PASSWORD").decode("ascii") def responder(environ: "WSGIEnvironment", start_response: "StartResponse") -> Body: - - if environ.get("HTTP_AUTHORIZATION") == correct_auth: - size = os.stat(path).st_size - start_response( - "200 OK", - [ - ("Content-Type", "application/octet-stream"), - ("Content-Length", str(size)), - ], - ) - else: - start_response( - "401 Unauthorized", - [ - ("WWW-Authenticate", "Basic"), - ], - ) - - with open(path, "rb") as f: - return [f.read()] + if environ.get("HTTP_AUTHORIZATION") != correct_auth: + start_response("401 Unauthorized", [("WWW-Authenticate", "Basic")]) + return () + start_response( + "200 OK", + [ + ("Content-Type", "application/octet-stream"), + ("Content-Length", str(path.stat().st_size)), + ], + ) + return [path.read_bytes()] return responder diff --git a/tests/lib/test_wheel.py b/tests/lib/test_wheel.py index 09c2ee3e610..ba8e7099290 100644 --- a/tests/lib/test_wheel.py +++ b/tests/lib/test_wheel.py @@ -1,12 +1,12 @@ """Tests for wheel helper. """ import csv +import pathlib from email import message_from_string from email.message import Message from functools import partial from zipfile import ZipFile -from tests.lib.path import Path from tests.lib.wheel import ( File, _default, @@ -145,10 +145,10 @@ def test_make_wheel_metadata_file_no_contents() -> None: assert f is None -def test_make_wheel_basics(tmpdir: Path) -> None: - make_wheel(name="simple", version="0.1.0").save_to_dir(tmpdir) +def test_make_wheel_basics(tmp_path: pathlib.Path) -> None: + make_wheel(name="simple", version="0.1.0").save_to_dir(tmp_path) - expected_wheel_path = tmpdir / "simple-0.1.0-py2.py3-none-any.whl" + expected_wheel_path = tmp_path / "simple-0.1.0-py2.py3-none-any.whl" assert expected_wheel_path.exists() with ZipFile(expected_wheel_path) as z: diff --git a/tests/lib/venv.py b/tests/lib/venv.py index a43aead9605..9e1c10e2b53 100644 --- a/tests/lib/venv.py +++ b/tests/lib/venv.py @@ -1,15 +1,14 @@ import compileall +import pathlib import shutil import subprocess import sys import textwrap import venv as _venv -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING, Optional, Union import virtualenv as _virtualenv -from .path import Path - if TYPE_CHECKING: # Literal was introduced in Python 3.8. from typing import Literal @@ -27,11 +26,11 @@ class VirtualEnvironment: def __init__( self, - location: str, + location: pathlib.Path, template: Optional["VirtualEnvironment"] = None, venv_type: Optional[VirtualEnvironmentType] = None, ): - self.location = Path(location) + self.location = location assert template is None or venv_type is None self._venv_type: VirtualEnvironmentType if template is not None: @@ -48,14 +47,14 @@ def __init__( def _update_paths(self) -> None: home, lib, inc, bin = _virtualenv.path_locations(self.location) - self.bin = Path(bin) - self.site = Path(lib) / "site-packages" + self.bin = pathlib.Path(bin) + self.site = pathlib.Path(lib, "site-packages") # Workaround for https://github.com/pypa/virtualenv/issues/306 if hasattr(sys, "pypy_version_info"): version_dir = str(sys.version_info.major) - self.lib = Path(home, "lib-python", version_dir) + self.lib = pathlib.Path(home, "lib-python", version_dir) else: - self.lib = Path(lib) + self.lib = pathlib.Path(lib) def __repr__(self) -> str: return f"" @@ -171,9 +170,9 @@ def _customize_site(self) -> None: def clear(self) -> None: self._create(clear=True) - def move(self, location: str) -> None: + def move(self, location: Union[pathlib.Path, str]) -> None: shutil.move(self.location, location) - self.location = Path(location) + self.location = pathlib.Path(location) self._update_paths() @property diff --git a/tests/lib/wheel.py b/tests/lib/wheel.py index 878364cf792..c2896d7da4c 100644 --- a/tests/lib/wheel.py +++ b/tests/lib/wheel.py @@ -2,6 +2,7 @@ """ import csv import itertools +import pathlib from base64 import urlsafe_b64encode from collections import namedtuple from copy import deepcopy @@ -26,7 +27,6 @@ from pip._vendor.requests.structures import CaseInsensitiveDict from pip._internal.metadata import BaseDistribution, MemoryWheel, get_wheel_distribution -from tests.lib.path import Path # As would be used in metadata HeaderValue = Union[str, List[str]] @@ -252,23 +252,23 @@ def __init__(self, name: str, files: Iterable[File]) -> None: self._name = name self._files = files - def save_to_dir(self, path: Union[Path, str]) -> str: + def save_to_dir(self, path: Union[pathlib.Path, str]) -> str: """Generate wheel file with correct name and save into the provided directory. :returns the wheel file path """ - p = Path(path) / self._name + p = pathlib.Path(path, self._name) p.write_bytes(self.as_bytes()) return str(p) - def save_to(self, path: Union[Path, str]) -> str: + def save_to(self, path: Union[pathlib.Path, str]) -> str: """Generate wheel file, saving to the provided path. Any parent directories must already exist. :returns the wheel file path """ - path = Path(path) + path = pathlib.Path(path) path.write_bytes(self.as_bytes()) return str(path) diff --git a/tests/unit/resolution_resolvelib/test_requirement.py b/tests/unit/resolution_resolvelib/test_requirement.py index 387afbc2304..a3656d4d6bb 100644 --- a/tests/unit/resolution_resolvelib/test_requirement.py +++ b/tests/unit/resolution_resolvelib/test_requirement.py @@ -1,3 +1,4 @@ +import pathlib from typing import Iterator, List, Tuple import pytest @@ -6,9 +7,7 @@ from pip._internal.resolution.resolvelib.base import Candidate, Constraint, Requirement from pip._internal.resolution.resolvelib.factory import Factory from pip._internal.resolution.resolvelib.provider import PipProvider -from pip._internal.utils.urls import path_to_url from tests.lib import TestData -from tests.lib.path import Path # NOTE: All tests are prefixed `test_rlr` (for "test resolvelib resolver"). # This helps select just these tests using pytest's `-k` option, and @@ -25,11 +24,11 @@ @pytest.fixture def test_cases(data: TestData) -> Iterator[List[Tuple[str, str, int]]]: - def data_file(name: str) -> Path: + def data_file(name: str) -> pathlib.Path: return data.packages.joinpath(name) def data_url(name: str) -> str: - return path_to_url(data_file(name)) + return data_file(name).as_uri() test_cases = [ # requirement, name, matches @@ -38,14 +37,14 @@ def data_url(name: str) -> str: ("simple>1.0", "simple", 2), # ("simple[extra]==1.0", "simple[extra]", 1), # Wheels - (data_file("simplewheel-1.0-py2.py3-none-any.whl"), "simplewheel", 1), + (str(data_file("simplewheel-1.0-py2.py3-none-any.whl")), "simplewheel", 1), (data_url("simplewheel-1.0-py2.py3-none-any.whl"), "simplewheel", 1), # Direct URLs # TODO: The following test fails # ("foo @ " + data_url("simple-1.0.tar.gz"), "foo", 1), # SDists # TODO: sdists should have a name - (data_file("simple-1.0.tar.gz"), "simple", 1), + (str(data_file("simple-1.0.tar.gz")), "simple", 1), (data_url("simple-1.0.tar.gz"), "simple", 1), # TODO: directory, editables ] diff --git a/tests/unit/test_base_command.py b/tests/unit/test_base_command.py index 9a61ccc77b4..907e0e8391b 100644 --- a/tests/unit/test_base_command.py +++ b/tests/unit/test_base_command.py @@ -1,5 +1,6 @@ import logging import os +import pathlib from optparse import Values from typing import Callable, Iterator, List, NoReturn, Optional from unittest.mock import Mock, patch @@ -11,7 +12,6 @@ from pip._internal.utils import temp_dir from pip._internal.utils.logging import BrokenStdoutLoggingError from pip._internal.utils.temp_dir import TempDirectory -from tests.lib.path import Path @pytest.fixture @@ -103,40 +103,44 @@ def test_handle_pip_version_check_called(mock_handle_version_check: Mock) -> Non mock_handle_version_check.assert_called_once() -def test_log_command_success(fixed_time: None, tmpdir: Path) -> None: +@pytest.mark.usefixtures("fixed_time") +def test_log_command_success(tmp_path: pathlib.Path) -> None: """Test the --log option logs when command succeeds.""" cmd = FakeCommand() - log_path = tmpdir.joinpath("log") - cmd.main(["fake", "--log", log_path]) + log_path = tmp_path.joinpath("log") + cmd.main(["fake", "--log", str(log_path)]) with open(log_path) as f: assert f.read().rstrip() == "2019-01-17T06:00:37,040 fake" -def test_log_command_error(fixed_time: None, tmpdir: Path) -> None: +@pytest.mark.usefixtures("fixed_time") +def test_log_command_error(tmp_path: pathlib.Path) -> None: """Test the --log option logs when command fails.""" cmd = FakeCommand(error=True) - log_path = tmpdir.joinpath("log") - cmd.main(["fake", "--log", log_path]) + log_path = tmp_path.joinpath("log") + cmd.main(["fake", "--log", str(log_path)]) with open(log_path) as f: assert f.read().startswith("2019-01-17T06:00:37,040 fake") -def test_log_file_command_error(fixed_time: None, tmpdir: Path) -> None: +@pytest.mark.usefixtures("fixed_time") +def test_log_file_command_error(tmp_path: pathlib.Path) -> None: """Test the --log-file option logs (when there's an error).""" cmd = FakeCommand(error=True) - log_file_path = tmpdir.joinpath("log_file") - cmd.main(["fake", "--log-file", log_file_path]) + log_file_path = tmp_path.joinpath("log_file") + cmd.main(["fake", "--log-file", str(log_file_path)]) with open(log_file_path) as f: assert f.read().startswith("2019-01-17T06:00:37,040 fake") -def test_log_unicode_messages(fixed_time: None, tmpdir: Path) -> None: +@pytest.mark.usefixtures("fixed_time") +def test_log_unicode_messages(tmp_path: pathlib.Path) -> None: """Tests that logging bytestrings and unicode objects don't break logging. """ cmd = FakeCommandWithUnicode() - log_path = tmpdir.joinpath("log") - cmd.main(["fake_unicode", "--log", log_path]) + log_path = tmp_path.joinpath("log") + cmd.main(["fake_unicode", "--log", str(log_path)]) @pytest.mark.no_auto_tempdir_manager diff --git a/tests/unit/test_cache.py b/tests/unit/test_cache.py index acb16034186..5eda328979f 100644 --- a/tests/unit/test_cache.py +++ b/tests/unit/test_cache.py @@ -1,4 +1,5 @@ import os +import pathlib from pip._vendor.packaging.tags import Tag @@ -6,7 +7,6 @@ from pip._internal.models.format_control import FormatControl from pip._internal.models.link import Link from pip._internal.utils.misc import ensure_dir -from tests.lib.path import Path def test_falsey_path_none() -> None: @@ -24,12 +24,12 @@ def test_subdirectory_fragment() -> None: assert wc.get_path_for_link(link1) != wc.get_path_for_link(link2) -def test_wheel_name_filter(tmpdir: Path) -> None: +def test_wheel_name_filter(tmp_path: pathlib.Path) -> None: """ Test the wheel cache filters on wheel name when several wheels for different package are stored under the same cache directory. """ - wc = WheelCache(tmpdir, FormatControl()) + wc = WheelCache(str(tmp_path), FormatControl()) link = Link("https://g.c/package.tar.gz") cache_path = wc.get_path_for_link(link) ensure_dir(cache_path) @@ -52,8 +52,8 @@ def test_cache_hash() -> None: assert h == "f83b32dfa27a426dec08c21bf006065dd003d0aac78e7fc493d9014d" -def test_get_cache_entry(tmpdir: Path) -> None: - wc = WheelCache(tmpdir, FormatControl()) +def test_get_cache_entry(tmp_path: pathlib.Path) -> None: + wc = WheelCache(str(tmp_path), FormatControl()) persi_link = Link("https://g.c/o/r/persi") persi_path = wc.get_path_for_link(persi_link) ensure_dir(persi_path) diff --git a/tests/unit/test_collector.py b/tests/unit/test_collector.py index f77794b55b9..8194689e0a5 100644 --- a/tests/unit/test_collector.py +++ b/tests/unit/test_collector.py @@ -1,8 +1,8 @@ import itertools import logging -import os.path +import os +import pathlib import re -import urllib.request import uuid from textwrap import dedent from typing import List, Optional, Tuple @@ -31,7 +31,6 @@ from pip._internal.models.link import Link from pip._internal.network.session import PipSession from tests.lib import TestData, make_test_link_collector -from tests.lib.path import Path @pytest.mark.parametrize( @@ -668,13 +667,11 @@ def make_fake_html_response(url: str) -> mock.Mock: return mock.Mock(content=content, url=url, headers={}) -def test_get_html_page_directory_append_index(tmpdir: Path) -> None: +def test_get_html_page_directory_append_index(tmp_path: pathlib.Path) -> None: """`_get_html_page()` should append "index.html" to a directory URL.""" - dirpath = tmpdir / "something" + dirpath = tmp_path / "something" dirpath.mkdir() - dir_url = "file:///{}".format( - urllib.request.pathname2url(dirpath).lstrip("/"), - ) + dir_url = dirpath.as_uri() expected_url = "{}/index.html".format(dir_url.rstrip("/")) session = mock.Mock(PipSession) @@ -757,7 +754,7 @@ def test_collect_sources__non_existing_path() -> None: index_url="ignored-by-no-index", extra_index_urls=[], no_index=True, - find_links=[os.path.join("this", "doesnt", "exist")], + find_links=["this/doesnt/exist"], ), ) sources = collector.collect_sources( @@ -901,7 +898,7 @@ def test_link_collector_create( @mock.patch("os.path.expanduser") def test_link_collector_create_find_links_expansion( - mock_expanduser: mock.Mock, tmpdir: Path + mock_expanduser: mock.Mock, tmp_path: pathlib.Path ) -> None: """ Test "~" expansion in --find-links paths. @@ -909,7 +906,7 @@ def test_link_collector_create_find_links_expansion( # This is a mock version of expanduser() that expands "~" to the tmpdir. def expand_path(path: str) -> str: if path.startswith("~/"): - path = os.path.join(tmpdir, path[2:]) + path = os.path.join(tmp_path, path[2:]) return path mock_expanduser.side_effect = expand_path @@ -923,8 +920,8 @@ def expand_path(path: str) -> str: ) # Only create temp2 and not temp1 to test that "~" expansion only occurs # when the directory exists. - temp2_dir = os.path.join(tmpdir, "temp2") - os.mkdir(temp2_dir) + temp2_dir = tmp_path.joinpath("temp2") + temp2_dir.mkdir() link_collector = LinkCollector.create(session, options=options) diff --git a/tests/unit/test_compat.py b/tests/unit/test_compat.py index da58cc8d3b3..b984b8c93f5 100644 --- a/tests/unit/test_compat.py +++ b/tests/unit/test_compat.py @@ -1,9 +1,9 @@ import os +import pathlib import pytest from pip._internal.utils.compat import get_path_uid -from tests.lib.path import Path def test_get_path_uid() -> None: @@ -21,11 +21,11 @@ def test_get_path_uid_without_NOFOLLOW(monkeypatch: pytest.MonkeyPatch) -> None: # Skip unconditionally on Windows, as symlinks need admin privs there @pytest.mark.skipif("sys.platform == 'win32'") @pytest.mark.skipif("not hasattr(os, 'symlink')") -def test_get_path_uid_symlink(tmpdir: Path) -> None: - f = tmpdir / "symlink" / "somefile" +def test_get_path_uid_symlink(tmp_path: pathlib.Path) -> None: + f = tmp_path / "symlink" / "somefile" f.parent.mkdir() f.write_text("content") - fs = f + "_link" + fs = f"{f}_link" os.symlink(f, fs) with pytest.raises(OSError): get_path_uid(fs) @@ -34,13 +34,13 @@ def test_get_path_uid_symlink(tmpdir: Path) -> None: @pytest.mark.skipif("not hasattr(os, 'O_NOFOLLOW')") @pytest.mark.skipif("not hasattr(os, 'symlink')") def test_get_path_uid_symlink_without_NOFOLLOW( - tmpdir: Path, monkeypatch: pytest.MonkeyPatch + tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch ) -> None: monkeypatch.delattr("os.O_NOFOLLOW") - f = tmpdir / "symlink" / "somefile" + f = tmp_path / "symlink" / "somefile" f.parent.mkdir() f.write_text("content") - fs = f + "_link" + fs = f"{f}_link" os.symlink(f, fs) with pytest.raises(OSError): get_path_uid(fs) diff --git a/tests/unit/test_direct_url_helpers.py b/tests/unit/test_direct_url_helpers.py index 8d94aeb50b6..11714504aa9 100644 --- a/tests/unit/test_direct_url_helpers.py +++ b/tests/unit/test_direct_url_helpers.py @@ -1,3 +1,4 @@ +import pathlib from functools import partial from unittest import mock @@ -7,9 +8,7 @@ direct_url_as_pep440_direct_reference, direct_url_from_link, ) -from pip._internal.utils.urls import path_to_url from tests.lib import PipTestEnvironment -from tests.lib.path import Path def test_as_pep440_requirement_archive() -> None: @@ -112,9 +111,9 @@ def test_from_link_vcs(mock_get_backend_for_scheme: mock.Mock) -> None: def test_from_link_vcs_with_source_dir_obtains_commit_id( - script: PipTestEnvironment, tmpdir: Path + script: PipTestEnvironment, tmp_path: pathlib.Path ) -> None: - repo_path = tmpdir / "test-repo" + repo_path = tmp_path / "test-repo" repo_path.mkdir() repo_dir = str(repo_path) script.run("git", "init", cwd=repo_dir) @@ -150,8 +149,8 @@ def test_from_link_archive() -> None: assert direct_url.info.hash == "sha1=1b8c5bc61a86f377fea47b4276c8c8a5842d2220" -def test_from_link_dir(tmpdir: Path) -> None: - dir_url = path_to_url(tmpdir) +def test_from_link_dir(tmp_path: pathlib.Path) -> None: + dir_url = tmp_path.as_uri() direct_url = direct_url_from_link(Link(dir_url)) assert direct_url.url == dir_url assert isinstance(direct_url.info, DirInfo) diff --git a/tests/unit/test_locations.py b/tests/unit/test_locations.py index 023b6687d41..6b6b71cb800 100644 --- a/tests/unit/test_locations.py +++ b/tests/unit/test_locations.py @@ -4,6 +4,7 @@ """ import getpass import os +import pathlib import shutil import sys import sysconfig @@ -14,7 +15,6 @@ import pytest from pip._internal.locations import SCHEME_KEYS, _should_use_sysconfig, get_scheme -from tests.lib.path import Path if sys.platform == "win32": pwd = Mock() @@ -119,13 +119,13 @@ def test_root_modifies_appropriately(self) -> None: @pytest.mark.incompatible_with_sysconfig @pytest.mark.incompatible_with_venv def test_distutils_config_file_read( - self, tmpdir: Path, monkeypatch: pytest.MonkeyPatch + self, tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch ) -> None: # This deals with nt/posix path differences install_scripts = os.path.normcase( os.path.abspath(os.path.join(os.path.sep, "somewhere", "else")) ) - f = tmpdir / "config" / "setup.cfg" + f = tmp_path / "config" / "setup.cfg" f.parent.mkdir() f.write_text("[install]\ninstall-scripts=" + install_scripts) from distutils.dist import Distribution @@ -145,13 +145,13 @@ def test_distutils_config_file_read( # .so) into that path; i.e. ensure platlib & purelib are set to # this path. sysconfig does not support this. def test_install_lib_takes_precedence( - self, tmpdir: Path, monkeypatch: pytest.MonkeyPatch + self, tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch ) -> None: # This deals with nt/posix path differences install_lib = os.path.normcase( os.path.abspath(os.path.join(os.path.sep, "somewhere", "else")) ) - f = tmpdir / "config" / "setup.cfg" + f = tmp_path / "config" / "setup.cfg" f.parent.mkdir() f.write_text("[install]\ninstall-lib=" + install_lib) from distutils.dist import Distribution diff --git a/tests/unit/test_network_cache.py b/tests/unit/test_network_cache.py index c7e0e382b17..28a1b7938cf 100644 --- a/tests/unit/test_network_cache.py +++ b/tests/unit/test_network_cache.py @@ -1,4 +1,5 @@ import os +import pathlib from typing import Iterator from unittest.mock import Mock @@ -6,12 +7,11 @@ from pip._vendor.cachecontrol.caches import FileCache from pip._internal.network.cache import SafeFileCache -from tests.lib.path import Path @pytest.fixture(scope="function") -def cache_tmpdir(tmpdir: Path) -> Iterator[Path]: - cache_dir = tmpdir.joinpath("cache") +def cache_tmp_path(tmp_path: pathlib.Path) -> Iterator[pathlib.Path]: + cache_dir = tmp_path.joinpath("cache") cache_dir.mkdir(parents=True) yield cache_dir @@ -23,9 +23,9 @@ class TestSafeFileCache: os.geteuid which is absent on Windows. """ - def test_cache_roundtrip(self, cache_tmpdir: Path) -> None: + def test_cache_roundtrip(self, cache_tmp_path: pathlib.Path) -> None: - cache = SafeFileCache(cache_tmpdir) + cache = SafeFileCache(str(cache_tmp_path)) assert cache.get("test key") is None cache.set("test key", b"a test string") assert cache.get("test key") == b"a test string" @@ -34,31 +34,31 @@ def test_cache_roundtrip(self, cache_tmpdir: Path) -> None: @pytest.mark.skipif("sys.platform == 'win32'") def test_safe_get_no_perms( - self, cache_tmpdir: Path, monkeypatch: pytest.MonkeyPatch + self, cache_tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch ) -> None: - os.chmod(cache_tmpdir, 000) + os.chmod(cache_tmp_path, 000) monkeypatch.setattr(os.path, "exists", lambda x: True) - cache = SafeFileCache(cache_tmpdir) + cache = SafeFileCache(str(cache_tmp_path)) cache.get("foo") @pytest.mark.skipif("sys.platform == 'win32'") - def test_safe_set_no_perms(self, cache_tmpdir: Path) -> None: - os.chmod(cache_tmpdir, 000) + def test_safe_set_no_perms(self, cache_tmp_path: pathlib.Path) -> None: + os.chmod(cache_tmp_path, 000) - cache = SafeFileCache(cache_tmpdir) + cache = SafeFileCache(str(cache_tmp_path)) cache.set("foo", b"bar") @pytest.mark.skipif("sys.platform == 'win32'") - def test_safe_delete_no_perms(self, cache_tmpdir: Path) -> None: - os.chmod(cache_tmpdir, 000) + def test_safe_delete_no_perms(self, cache_tmp_path: pathlib.Path) -> None: + os.chmod(cache_tmp_path, 000) - cache = SafeFileCache(cache_tmpdir) + cache = SafeFileCache(str(cache_tmp_path)) cache.delete("foo") - def test_cache_hashes_are_same(self, cache_tmpdir: Path) -> None: - cache = SafeFileCache(cache_tmpdir) + def test_cache_hashes_are_same(self, cache_tmp_path: pathlib.Path) -> None: + cache = SafeFileCache(str(cache_tmp_path)) key = "test key" fake_cache = Mock(FileCache, directory=cache.directory, encode=FileCache.encode) assert cache._get_cache_path(key) == FileCache._fn(fake_cache, key) diff --git a/tests/unit/test_network_session.py b/tests/unit/test_network_session.py index 18eb9539f7f..a529cc5e3f4 100644 --- a/tests/unit/test_network_session.py +++ b/tests/unit/test_network_session.py @@ -1,4 +1,5 @@ import logging +import pathlib from typing import Any, List, Optional from urllib.parse import urlparse from urllib.request import getproxies @@ -9,7 +10,6 @@ from pip import __version__ from pip._internal.models.link import Link from pip._internal.network.session import CI_ENVIRONMENT_VARIABLES, PipSession -from tests.lib.path import Path def get_user_agent() -> str: @@ -67,22 +67,18 @@ def test_cache_defaults_off(self) -> None: assert not hasattr(session.adapters["http://"], "cache") assert not hasattr(session.adapters["https://"], "cache") - def test_cache_is_enabled(self, tmpdir: Path) -> None: - cache_directory = tmpdir.joinpath("test-cache") - session = PipSession(cache=cache_directory) - - assert hasattr(session.adapters["https://"], "cache") - - assert session.adapters["https://"].cache.directory == cache_directory - - def test_http_cache_is_not_enabled(self, tmpdir: Path) -> None: - session = PipSession(cache=tmpdir.joinpath("test-cache")) + def test_cache_is_enabled(self, tmp_path: pathlib.Path) -> None: + cache_directory = tmp_path.joinpath("test-cache") + session = PipSession(cache=str(cache_directory)) + assert session.adapters["https://"].cache.directory == str(cache_directory) + def test_http_cache_is_not_enabled(self, tmp_path: pathlib.Path) -> None: + session = PipSession(cache=str(tmp_path.joinpath("test-cache"))) assert not hasattr(session.adapters["http://"], "cache") - def test_trusted_hosts_adapter(self, tmpdir: Path) -> None: + def test_trusted_hosts_adapter(self, tmp_path: pathlib.Path) -> None: session = PipSession( - cache=tmpdir.joinpath("test-cache"), + cache=str(tmp_path.joinpath("test-cache")), trusted_hosts=["example.com"], ) diff --git a/tests/unit/test_operations_prepare.py b/tests/unit/test_operations_prepare.py index 8838fa9ce0e..30263fb8c3e 100644 --- a/tests/unit/test_operations_prepare.py +++ b/tests/unit/test_operations_prepare.py @@ -1,4 +1,5 @@ import os +import pathlib import shutil from shutil import rmtree from tempfile import mkdtemp @@ -13,9 +14,7 @@ from pip._internal.network.session import PipSession from pip._internal.operations.prepare import unpack_url from pip._internal.utils.hashes import Hashes -from pip._internal.utils.urls import path_to_url from tests.lib import TestData -from tests.lib.path import Path from tests.lib.requests_mocks import MockResponse @@ -34,7 +33,7 @@ def _fake_session_get(*args: Any, **kwargs: Any) -> Dict[str, str]: session.get = _fake_session_get download = Downloader(session, progress_bar="on") - uri = path_to_url(data.packages.joinpath("simple-1.0.tar.gz")) + uri = data.packages.joinpath("simple-1.0.tar.gz").as_uri() link = Link(uri) temp_dir = mkdtemp() try: @@ -58,7 +57,7 @@ def _fake_session_get(*args: Any, **kwargs: Any) -> Dict[str, str]: @patch("pip._internal.network.download.raise_for_status") def test_download_http_url__no_directory_traversal( - mock_raise_for_status: Mock, tmpdir: Path + mock_raise_for_status: Mock, tmp_path: pathlib.Path ) -> None: """ Test that directory traversal doesn't happen on download when the @@ -80,18 +79,22 @@ def test_download_http_url__no_directory_traversal( session.get.return_value = resp download = Downloader(session, progress_bar="on") - download_dir = tmpdir.joinpath("download") - os.mkdir(download_dir) - file_path, content_type = download(link, download_dir) + download_dir = tmp_path.joinpath("download") + download_dir.mkdir() + + download(link, str(download_dir)) + # The file should be downloaded to download_dir. - actual = os.listdir(download_dir) - assert actual == ["out_dir_file"] + assert os.listdir(download_dir) == ["out_dir_file"] mock_raise_for_status.assert_called_once_with(resp) @pytest.fixture -def clean_project(tmpdir_factory: pytest.TempdirFactory, data: TestData) -> Path: - tmpdir = Path(str(tmpdir_factory.mktemp("clean_project"))) +def clean_project( + tmp_path_factory: pytest.TempPathFactory, + data: TestData, +) -> pathlib.Path: + tmpdir = pathlib.Path(str(tmp_path_factory.mktemp("clean_project"))) new_project_dir = tmpdir.joinpath("FSPkg") path = data.packages.joinpath("FSPkg") shutil.copytree(path, new_project_dir) @@ -99,36 +102,40 @@ def clean_project(tmpdir_factory: pytest.TempdirFactory, data: TestData) -> Path class Test_unpack_url: - def prep(self, tmpdir: Path, data: TestData) -> None: - self.build_dir = tmpdir.joinpath("build") - self.download_dir = tmpdir.joinpath("download") - os.mkdir(self.build_dir) - os.mkdir(self.download_dir) + def prep(self, tmp_path: pathlib.Path, data: TestData) -> None: + self.build_dir = tmp_path.joinpath("build") + self.download_dir = tmp_path.joinpath("download") + self.build_dir.mkdir() + self.download_dir.mkdir() self.dist_file = "simple-1.0.tar.gz" self.dist_file2 = "simple-2.0.tar.gz" self.dist_path = data.packages.joinpath(self.dist_file) self.dist_path2 = data.packages.joinpath(self.dist_file2) - self.dist_url = Link(path_to_url(self.dist_path)) - self.dist_url2 = Link(path_to_url(self.dist_path2)) + self.dist_url = Link(self.dist_path.as_uri()) + self.dist_url2 = Link(self.dist_path2.as_uri()) self.no_download = Mock(side_effect=AssertionError) - def test_unpack_url_no_download(self, tmpdir: Path, data: TestData) -> None: - self.prep(tmpdir, data) - unpack_url(self.dist_url, self.build_dir, self.no_download, verbosity=0) - assert os.path.isdir(os.path.join(self.build_dir, "simple")) - assert not os.path.isfile(os.path.join(self.download_dir, self.dist_file)) - - def test_unpack_url_bad_hash(self, tmpdir: Path, data: TestData) -> None: + def test_unpack_url_no_download( + self, + tmp_path: pathlib.Path, + data: TestData, + ) -> None: + self.prep(tmp_path, data) + unpack_url(self.dist_url, str(self.build_dir), self.no_download, verbosity=0) + assert self.build_dir.joinpath("simple").is_dir() + assert not self.download_dir.joinpath(self.dist_file).exists() + + def test_unpack_url_bad_hash(self, tmp_path: pathlib.Path, data: TestData) -> None: """ Test when the file url hash fragment is wrong """ - self.prep(tmpdir, data) + self.prep(tmp_path, data) url = f"{self.dist_url.url}#md5=bogus" dist_url = Link(url) with pytest.raises(HashMismatch): unpack_url( dist_url, - self.build_dir, + str(self.build_dir), download=self.no_download, hashes=Hashes({"md5": ["bogus"]}), verbosity=0, diff --git a/tests/unit/test_options.py b/tests/unit/test_options.py index ddcc8532cfd..ada5e1c3076 100644 --- a/tests/unit/test_options.py +++ b/tests/unit/test_options.py @@ -12,7 +12,6 @@ from pip._internal.commands.configuration import ConfigurationCommand from pip._internal.exceptions import PipError from tests.lib.options_helpers import AddFakeCommandMixin -from tests.lib.path import Path @contextmanager @@ -33,7 +32,7 @@ def assert_option_error( assert expected in stderr -def assert_is_default_cache_dir(value: Path) -> None: +def assert_is_default_cache_dir(value: str) -> None: # This path looks different on different platforms, but the path always # has the substring "pip". assert "pip" in value diff --git a/tests/unit/test_pep517.py b/tests/unit/test_pep517.py index 9305cf2a19b..e048b6aae75 100644 --- a/tests/unit/test_pep517.py +++ b/tests/unit/test_pep517.py @@ -1,3 +1,4 @@ +import pathlib from textwrap import dedent import pytest @@ -5,7 +6,6 @@ from pip._internal.exceptions import InstallationError, InvalidPyProjectBuildRequires from pip._internal.req import InstallRequirement from tests.lib import TestData -from tests.lib.path import Path @pytest.mark.parametrize( @@ -22,7 +22,7 @@ def test_use_pep517(shared_data: TestData, source: str, expected: bool) -> None: """ src = shared_data.src.joinpath(source) req = InstallRequirement(None, None) - req.source_dir = src # make req believe it has been unpacked + req.source_dir = str(src) # make req believe it has been unpacked req.load_pyproject_toml() assert req.use_pep517 is expected @@ -33,7 +33,7 @@ def test_use_pep517_rejects_setup_cfg_only(shared_data: TestData) -> None: """ src = shared_data.src.joinpath("pep517_setup_cfg_only") req = InstallRequirement(None, None) - req.source_dir = src # make req believe it has been unpacked + req.source_dir = str(src) # make req believe it has been unpacked with pytest.raises(InstallationError) as e: req.load_pyproject_toml() err_msg = e.value.args[0] @@ -56,7 +56,7 @@ def test_disabling_pep517_invalid(shared_data: TestData, source: str, msg: str) """ src = shared_data.src.joinpath(source) req = InstallRequirement(None, None) - req.source_dir = src # make req believe it has been unpacked + req.source_dir = str(src) # make req believe it has been unpacked # Simulate --no-use-pep517 req.use_pep517 = False @@ -72,8 +72,8 @@ def test_disabling_pep517_invalid(shared_data: TestData, source: str, msg: str) @pytest.mark.parametrize( ("spec",), [("./foo",), ("git+https://example.com/pkg@dev#egg=myproj",)] ) -def test_pep517_parsing_checks_requirements(tmpdir: Path, spec: str) -> None: - tmpdir.joinpath("pyproject.toml").write_text( +def test_pep517_parsing_checks_requirements(tmp_path: pathlib.Path, spec: str) -> None: + tmp_path.joinpath("pyproject.toml").write_text( dedent( f""" [build-system] @@ -83,7 +83,7 @@ def test_pep517_parsing_checks_requirements(tmpdir: Path, spec: str) -> None: ) ) req = InstallRequirement(None, None) - req.source_dir = tmpdir # make req believe it has been unpacked + req.source_dir = str(tmp_path) # make req believe it has been unpacked with pytest.raises(InvalidPyProjectBuildRequires) as e: req.load_pyproject_toml() diff --git a/tests/unit/test_req.py b/tests/unit/test_req.py index 18932bb344d..2719329ce2e 100644 --- a/tests/unit/test_req.py +++ b/tests/unit/test_req.py @@ -1,6 +1,7 @@ import contextlib import email.message import os +import pathlib import shutil import sys import tempfile @@ -45,9 +46,7 @@ handle_requirement_line, ) from pip._internal.resolution.legacy.resolver import Resolver -from pip._internal.utils.urls import path_to_url from tests.lib import TestData, make_test_finder, requirements_file, wheel -from tests.lib.path import Path def get_processed_req_from_line( @@ -150,7 +149,9 @@ def test_environment_marker_extras(self, data: TestData) -> None: non-wheel installs. """ reqset = RequirementSet() - req = install_req_from_editable(data.packages.joinpath("LocalEnvironMarker")) + req = install_req_from_editable( + str(data.packages.joinpath("LocalEnvironMarker")), + ) req.user_supplied = True reqset.add_unnamed_requirement(req) finder = make_test_finder(find_links=[data.find_links]) @@ -182,7 +183,7 @@ def test_missing_hash_with_require_hashes(self, data: TestData) -> None: resolver.resolve(reqset.all_requirements, True) def test_missing_hash_with_require_hashes_in_reqs_file( - self, data: TestData, tmpdir: Path + self, data: TestData, tmp_path: pathlib.Path ) -> None: """--require-hashes in a requirements file should make its way to the RequirementSet. @@ -190,8 +191,8 @@ def test_missing_hash_with_require_hashes_in_reqs_file( finder = make_test_finder(find_links=[data.find_links]) session = finder._link_collector.session command = cast(InstallCommand, create_command("install")) - with requirements_file("--require-hashes", tmpdir) as reqs_file: - options, args = command.parse_args(["-r", reqs_file]) + with requirements_file("--require-hashes", tmp_path) as reqs_file: + options, args = command.parse_args(["-r", str(reqs_file)]) command.get_requirements(args, options, finder, session) assert options.require_hashes @@ -275,7 +276,7 @@ def test_unpinned_hash_checking(self, data: TestData) -> None: def test_hash_mismatch(self, data: TestData) -> None: """A hash mismatch should raise an error.""" - file_url = path_to_url((data.packages / "simple-1.0.tar.gz").resolve()) + file_url = data.packages.joinpath("simple-1.0.tar.gz").resolve().as_uri() reqset = RequirementSet() reqset.add_unnamed_requirement( get_processed_req_from_line( @@ -397,14 +398,14 @@ def test_download_info_web_archive(self) -> None: ) def test_download_info_archive_legacy_cache( - self, tmp_path: Path, shared_data: TestData + self, tmp_path: pathlib.Path, shared_data: TestData ) -> None: """Test download_info hash is not set for an archive with legacy cache entry.""" - url = path_to_url(shared_data.packages / "simple-1.0.tar.gz") + url = shared_data.packages.joinpath("simple-1.0.tar.gz").as_uri() finder = make_test_finder() wheel_cache = WheelCache(str(tmp_path / "cache"), FormatControl()) cache_entry_dir = wheel_cache.get_path_for_link(Link(url)) - Path(cache_entry_dir).mkdir(parents=True) + pathlib.Path(cache_entry_dir).mkdir(parents=True) wheel.make_wheel(name="simple", version="1.0").save_to_dir(cache_entry_dir) with self._basic_resolver(finder, wheel_cache=wheel_cache) as resolver: ireq = get_processed_req_from_line(f"simple @ {url}") @@ -418,17 +419,17 @@ def test_download_info_archive_legacy_cache( assert not req.download_info.info.hash def test_download_info_archive_cache_with_origin( - self, tmp_path: Path, shared_data: TestData + self, tmp_path: pathlib.Path, shared_data: TestData ) -> None: """Test download_info hash is set for a web archive with cache entry that has origin.json.""" - url = path_to_url(shared_data.packages / "simple-1.0.tar.gz") + url = shared_data.packages.joinpath("simple-1.0.tar.gz").as_uri() hash = "sha256=ad977496000576e1b6c41f6449a9897087ce9da6db4f15b603fe8372af4bf3c6" finder = make_test_finder() wheel_cache = WheelCache(str(tmp_path / "cache"), FormatControl()) cache_entry_dir = wheel_cache.get_path_for_link(Link(url)) - Path(cache_entry_dir).mkdir(parents=True) - Path(cache_entry_dir).joinpath("origin.json").write_text( + pathlib.Path(cache_entry_dir).mkdir(parents=True) + pathlib.Path(cache_entry_dir).joinpath("origin.json").write_text( DirectUrl(url, ArchiveInfo(hash=hash)).to_json() ) wheel.make_wheel(name="simple", version="1.0").save_to_dir(cache_entry_dir) @@ -465,7 +466,7 @@ def test_download_info_local_dir(self, data: TestData) -> None: """Test that download_info is set for requirements from a local dir.""" finder = make_test_finder() with self._basic_resolver(finder) as resolver: - ireq_url = path_to_url(data.packages / "FSPkg") + ireq_url = data.packages.joinpath("FSPkg").as_uri() ireq = get_processed_req_from_line(f"FSPkg @ {ireq_url}") reqset = resolver.resolve([ireq], True) assert len(reqset.all_requirements) == 1 @@ -478,7 +479,7 @@ def test_download_info_local_editable_dir(self, data: TestData) -> None: """Test that download_info is set for requirements from a local editable dir.""" finder = make_test_finder() with self._basic_resolver(finder) as resolver: - ireq_url = path_to_url(data.packages / "FSPkg") + ireq_url = data.packages.joinpath("FSPkg").as_uri() ireq = get_processed_req_from_line(f"-e {ireq_url}#egg=FSPkg") reqset = resolver.resolve([ireq], True) assert len(reqset.all_requirements) == 1 @@ -909,9 +910,7 @@ def test_get_url_from_path__archive_file( isdir_mock.return_value = False isfile_mock.return_value = True name = "simple-0.1-py2.py3-none-any.whl" - path = os.path.join("/path/to/" + name) - url = path_to_url(path) - assert _get_url_from_path(path, name) == url + assert _get_url_from_path(f"/path/to/{name}", name) == f"file:///path/to/{name}" @mock.patch("pip._internal.req.req_install.os.path.isdir") @@ -922,9 +921,7 @@ def test_get_url_from_path__installable_dir( isdir_mock.return_value = True isfile_mock.return_value = True name = "some/setuptools/project" - path = os.path.join("/path/to/" + name) - url = path_to_url(path) - assert _get_url_from_path(path, name) == url + assert _get_url_from_path(f"/path/to/{name}", name) == f"file:///path/to/{name}" @mock.patch("pip._internal.req.req_install.os.path.isdir") diff --git a/tests/unit/test_req_file.py b/tests/unit/test_req_file.py index 491877fb973..036dd409ebb 100644 --- a/tests/unit/test_req_file.py +++ b/tests/unit/test_req_file.py @@ -5,7 +5,7 @@ import subprocess import textwrap from optparse import Values -from typing import TYPE_CHECKING, Any, Iterator, List, Optional, Tuple +from typing import TYPE_CHECKING, Any, Iterator, List, Optional, Tuple, Union from unittest import mock import pytest @@ -29,7 +29,6 @@ ) from pip._internal.req.req_install import InstallRequirement from tests.lib import TestData, make_test_finder, requirements_file -from tests.lib.path import Path if TYPE_CHECKING: from typing import Protocol @@ -59,7 +58,7 @@ def options(session: PipSession) -> mock.Mock: def parse_reqfile( - filename: str, + filename: Union[pathlib.Path, str], session: PipSession, finder: PackageFinder = None, options: Values = None, @@ -69,7 +68,7 @@ def parse_reqfile( # Wrap parse_requirements/install_req_from_parsed_requirement to # avoid having to write the same chunk of code in lots of tests. for parsed_req in parse_requirements( - filename, + str(filename), session, finder=finder, options=options, @@ -203,7 +202,10 @@ def __call__( @pytest.fixture -def line_processor(monkeypatch: pytest.MonkeyPatch, tmpdir: Path) -> LineProcessor: +def line_processor( + monkeypatch: pytest.MonkeyPatch, + tmp_path: pathlib.Path, +) -> LineProcessor: def process_line( line: str, filename: str, @@ -217,10 +219,10 @@ def process_line( session = PipSession() prefix = "\n" * (line_number - 1) - path = tmpdir.joinpath(filename) + path = tmp_path.joinpath(filename) path.parent.mkdir(exist_ok=True) path.write_text(prefix + line) - monkeypatch.chdir(str(tmpdir)) + monkeypatch.chdir(str(tmp_path)) return list( parse_reqfile( filename, @@ -329,15 +331,18 @@ def test_yield_editable_constraint(self, line_processor: LineProcessor) -> None: assert found_req.constraint is True def test_nested_constraints_file( - self, monkeypatch: pytest.MonkeyPatch, tmpdir: Path, session: PipSession + self, + monkeypatch: pytest.MonkeyPatch, + tmp_path: pathlib.Path, + session: PipSession, ) -> None: req_name = "hello" - req_file = tmpdir / "parent" / "req_file.txt" + req_file = tmp_path.joinpath("parent", "req_file.txt") req_file.parent.mkdir() req_file.write_text("-c reqs.txt") req_file.parent.joinpath("reqs.txt").write_text(req_name) - monkeypatch.chdir(str(tmpdir)) + monkeypatch.chdir(str(tmp_path)) reqs = list(parse_reqfile("./parent/req_file.txt", session=session)) assert len(reqs) == 1 @@ -461,14 +466,14 @@ def test_relative_local_find_links( line_processor: LineProcessor, finder: PackageFinder, monkeypatch: pytest.MonkeyPatch, - tmpdir: Path, + tmp_path: pathlib.Path, ) -> None: """ Test a relative find_links path is joined with the req file directory """ - base_path = tmpdir / "path" + base_path = tmp_path / "path" - def normalize(path: Path) -> str: + def normalize(path: pathlib.Path) -> str: return os.path.normcase(os.path.abspath(os.path.normpath(str(path)))) # Make sure the test also passes on windows @@ -517,18 +522,21 @@ def get_file_content( assert not result[0].constraint def test_relative_local_nested_req_files( - self, session: PipSession, monkeypatch: pytest.MonkeyPatch, tmpdir: Path + self, + session: PipSession, + monkeypatch: pytest.MonkeyPatch, + tmp_path: pathlib.Path, ) -> None: """ Test a relative nested req file path is joined with the req file dir """ req_name = "hello" - req_file = tmpdir / "parent" / "req_file.txt" + req_file = tmp_path.joinpath("parent", "req_file.txt") req_file.parent.mkdir() req_file.write_text("-r reqs.txt") req_file.parent.joinpath("reqs.txt").write_text(req_name) - monkeypatch.chdir(str(tmpdir)) + monkeypatch.chdir(str(tmp_path)) reqs = list(parse_reqfile("./parent/req_file.txt", session=session)) assert len(reqs) == 1 @@ -536,15 +544,15 @@ def test_relative_local_nested_req_files( assert not reqs[0].constraint def test_absolute_local_nested_req_files( - self, session: PipSession, tmpdir: Path + self, session: PipSession, tmp_path: pathlib.Path ) -> None: """ Test an absolute nested req file path """ req_name = "hello" - req_file = tmpdir / "parent" / "req_file.txt" + req_file = tmp_path.joinpath("parent", "req_file.txt") req_file.parent.mkdir() - other_req_file = tmpdir / "other" / "reqs.txt" + other_req_file = tmp_path.joinpath("other", "reqs.txt") other_req_file.parent.mkdir() # POSIX-ify the path, since Windows backslashes aren't supported. other_req_file_str = str(other_req_file).replace("\\", "/") @@ -552,19 +560,22 @@ def test_absolute_local_nested_req_files( req_file.write_text(f"-r {other_req_file_str}") other_req_file.write_text(req_name) - reqs = list(parse_reqfile(str(req_file), session=session)) + reqs = list(parse_reqfile(req_file, session=session)) assert len(reqs) == 1 assert reqs[0].name == req_name assert not reqs[0].constraint def test_absolute_http_nested_req_file_in_local( - self, session: PipSession, monkeypatch: pytest.MonkeyPatch, tmpdir: Path + self, + session: PipSession, + monkeypatch: pytest.MonkeyPatch, + tmp_path: pathlib.Path, ) -> None: """ Test a nested req file url in a local req file """ req_name = "hello" - req_file = tmpdir / "req_file.txt" + req_file = tmp_path / "req_file.txt" nested_req_file = "http://me.com/me/req_file.txt" def get_file_content( @@ -656,15 +667,15 @@ def test_remote_reqs_parse(self) -> None: pass def test_multiple_appending_options( - self, tmpdir: Path, finder: PackageFinder, options: mock.Mock + self, tmp_path: pathlib.Path, finder: PackageFinder, options: mock.Mock ) -> None: - with open(tmpdir.joinpath("req1.txt"), "w") as fp: + with tmp_path.joinpath("req1.txt").open("w") as fp: fp.write("--extra-index-url url1 \n") fp.write("--extra-index-url url2 ") list( parse_reqfile( - tmpdir.joinpath("req1.txt"), + tmp_path.joinpath("req1.txt"), finder=finder, session=PipSession(), options=options, @@ -674,7 +685,7 @@ def test_multiple_appending_options( assert finder.index_urls == ["url1", "url2"] def test_expand_existing_env_variables( - self, tmpdir: Path, finder: PackageFinder + self, tmp_path: pathlib.Path, finder: PackageFinder ) -> None: template = "https://{}:x-oauth-basic@github.com/user/{}/archive/master.zip" @@ -688,7 +699,7 @@ def make_var(name: str) -> str: ] ) - with open(tmpdir.joinpath("req1.txt"), "w") as fp: + with tmp_path.joinpath("req1.txt").open("w") as fp: fp.write(template.format(*map(make_var, env_vars))) # Construct the session outside the monkey-patch, since it access the @@ -699,7 +710,7 @@ def make_var(name: str) -> str: reqs = list( parse_reqfile( - tmpdir.joinpath("req1.txt"), finder=finder, session=session + tmp_path.joinpath("req1.txt"), finder=finder, session=session ) ) @@ -710,14 +721,14 @@ def make_var(name: str) -> str: assert reqs[0].link.url == expected_url, "variable expansion in req file failed" def test_expand_missing_env_variables( - self, tmpdir: Path, finder: PackageFinder + self, tmp_path: pathlib.Path, finder: PackageFinder ) -> None: req_url = ( "https://${NON_EXISTENT_VARIABLE}:$WRONG_FORMAT@" "%WINDOWS_FORMAT%github.com/user/repo/archive/master.zip" ) - with open(tmpdir.joinpath("req1.txt"), "w") as fp: + with tmp_path.joinpath("req1.txt").open("w") as fp: fp.write(req_url) # Construct the session outside the monkey-patch, since it access the @@ -728,7 +739,7 @@ def test_expand_missing_env_variables( reqs = list( parse_reqfile( - tmpdir.joinpath("req1.txt"), finder=finder, session=session + tmp_path.joinpath("req1.txt"), finder=finder, session=session ) ) @@ -738,13 +749,13 @@ def test_expand_missing_env_variables( reqs[0].link.url == req_url ), "ignoring invalid env variable in req file failed" - def test_join_lines(self, tmpdir: Path, finder: PackageFinder) -> None: - with open(tmpdir.joinpath("req1.txt"), "w") as fp: + def test_join_lines(self, tmp_path: pathlib.Path, finder: PackageFinder) -> None: + with tmp_path.joinpath("req1.txt").open("w") as fp: fp.write("--extra-index-url url1 \\\n--extra-index-url url2") list( parse_reqfile( - tmpdir.joinpath("req1.txt"), finder=finder, session=PipSession() + tmp_path.joinpath("req1.txt"), finder=finder, session=PipSession() ) ) @@ -764,34 +775,36 @@ def test_req_file_parse_no_only_binary( assert finder.format_control == expected def test_req_file_parse_comment_start_of_line( - self, tmpdir: Path, finder: PackageFinder + self, tmp_path: pathlib.Path, finder: PackageFinder ) -> None: """ Test parsing comments in a requirements file """ - with open(tmpdir.joinpath("req1.txt"), "w") as fp: + with tmp_path.joinpath("req1.txt").open("w") as fp: fp.write("# Comment ") reqs = list( parse_reqfile( - tmpdir.joinpath("req1.txt"), finder=finder, session=PipSession() + tmp_path.joinpath("req1.txt"), finder=finder, session=PipSession() ) ) assert not reqs def test_req_file_parse_comment_end_of_line_with_url( - self, tmpdir: Path, finder: PackageFinder + self, tmp_path: pathlib.Path, finder: PackageFinder ) -> None: """ Test parsing comments in a requirements file """ - with open(tmpdir.joinpath("req1.txt"), "w") as fp: + with tmp_path.joinpath("req1.txt").open("w") as fp: fp.write("https://example.com/foo.tar.gz # Comment ") reqs = list( parse_reqfile( - tmpdir.joinpath("req1.txt"), finder=finder, session=PipSession() + tmp_path.joinpath("req1.txt"), + finder=finder, + session=PipSession(), ) ) @@ -800,28 +813,30 @@ def test_req_file_parse_comment_end_of_line_with_url( assert reqs[0].link.url == "https://example.com/foo.tar.gz" def test_req_file_parse_egginfo_end_of_line_with_url( - self, tmpdir: Path, finder: PackageFinder + self, tmp_path: pathlib.Path, finder: PackageFinder ) -> None: """ Test parsing comments in a requirements file """ - with open(tmpdir.joinpath("req1.txt"), "w") as fp: + with tmp_path.joinpath("req1.txt").open("w") as fp: fp.write("https://example.com/foo.tar.gz#egg=wat") reqs = list( parse_reqfile( - tmpdir.joinpath("req1.txt"), finder=finder, session=PipSession() + tmp_path.joinpath("req1.txt"), + finder=finder, + session=PipSession(), ) ) assert len(reqs) == 1 assert reqs[0].name == "wat" - def test_req_file_no_finder(self, tmpdir: Path) -> None: + def test_req_file_no_finder(self, tmp_path: pathlib.Path) -> None: """ Test parsing a requirements file without a finder """ - with open(tmpdir.joinpath("req.txt"), "w") as fp: + with tmp_path.joinpath("req.txt").open("w") as fp: fp.write( """ --find-links https://example.com/ @@ -832,11 +847,11 @@ def test_req_file_no_finder(self, tmpdir: Path) -> None: """ ) - parse_reqfile(tmpdir.joinpath("req.txt"), session=PipSession()) + parse_reqfile(tmp_path.joinpath("req.txt"), session=PipSession()) def test_install_requirements_with_options( self, - tmpdir: Path, + tmp_path: pathlib.Path, finder: PackageFinder, session: PipSession, options: mock.Mock, @@ -844,18 +859,19 @@ def test_install_requirements_with_options( global_option = "--dry-run" install_option = "--prefix=/opt" - content = """ + content = f""" --only-binary :all: INITools==2.0 --global-option="{global_option}" \ --install-option "{install_option}" - """.format( - global_option=global_option, install_option=install_option - ) + """ - with requirements_file(content, tmpdir) as reqs_file: + with requirements_file(content, tmp_path) as reqs_file: req = next( parse_reqfile( - reqs_file.resolve(), finder=finder, options=options, session=session + reqs_file.resolve(), + finder=finder, + options=options, + session=session, ) ) diff --git a/tests/unit/test_req_install.py b/tests/unit/test_req_install.py index ac2c0cdbb89..3991841a2a8 100644 --- a/tests/unit/test_req_install.py +++ b/tests/unit/test_req_install.py @@ -1,4 +1,5 @@ import os +import pathlib import tempfile import pytest @@ -10,7 +11,6 @@ install_req_from_req_string, ) from pip._internal.req.req_install import InstallRequirement -from tests.lib.path import Path class TestInstallRequirementBuildDirectory: @@ -37,18 +37,15 @@ def test_tmp_build_directory(self) -> None: os.rmdir(tmp_dir) assert not os.path.exists(tmp_dir) - def test_forward_slash_results_in_a_link(self, tmpdir: Path) -> None: - install_dir = tmpdir / "foo" / "bar" + def test_forward_slash_results_in_a_link(self, tmp_path: pathlib.Path) -> None: + install_dir = tmp_path / "foo" / "bar" + install_dir.mkdir(parents=True) # Just create a file for letting the logic work setup_py_path = install_dir / "setup.py" - os.makedirs(str(install_dir)) - with open(setup_py_path, "w") as f: - f.write("") + setup_py_path.touch() - requirement = install_req_from_line( - str(install_dir).replace(os.sep, os.altsep or os.sep) - ) + requirement = install_req_from_line(install_dir.as_posix()) assert requirement.link is not None diff --git a/tests/unit/test_req_uninstall.py b/tests/unit/test_req_uninstall.py index b3049e1037c..801385ba53e 100644 --- a/tests/unit/test_req_uninstall.py +++ b/tests/unit/test_req_uninstall.py @@ -1,4 +1,5 @@ import os +import pathlib import sys from typing import Iterator, List, Optional, Tuple from unittest.mock import Mock @@ -16,7 +17,6 @@ uninstallation_paths, ) from tests.lib import create_file -from tests.lib.path import Path # Pretend all files are local, so UninstallPathSet accepts files in the tmpdir, @@ -57,12 +57,12 @@ def iter_declared_entries(self) -> Optional[Iterator[str]]: assert paths2 == paths -def test_compressed_listing(tmpdir: Path) -> None: +def test_compressed_listing(tmp_path: pathlib.Path) -> None: def in_tmpdir(paths: List[str]) -> List[str]: - li = [] - for path in paths: - li.append(str(os.path.join(tmpdir, path.replace("/", os.path.sep)))) - return li + return [ + str(os.path.join(tmp_path, path.replace("/", os.path.sep))) + for path in paths + ] sample = in_tmpdir( [ @@ -128,11 +128,11 @@ def in_tmpdir(paths: List[str]) -> List[str]: class TestUninstallPathSet: - def test_add(self, tmpdir: Path, monkeypatch: pytest.MonkeyPatch) -> None: + def test_add(self, tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setattr(pip._internal.req.req_uninstall, "is_local", mock_is_local) # Fix case for windows tests - file_extant = os.path.normcase(os.path.join(tmpdir, "foo")) - file_nonexistent = os.path.normcase(os.path.join(tmpdir, "nonexistent")) + file_extant = os.path.normcase(os.path.join(tmp_path, "foo")) + file_nonexistent = os.path.normcase(os.path.join(tmp_path, "nonexistent")) with open(file_extant, "w"): pass @@ -144,42 +144,49 @@ def test_add(self, tmpdir: Path, monkeypatch: pytest.MonkeyPatch) -> None: ups.add(file_nonexistent) assert ups._paths == {file_extant} - def test_add_pth(self, tmpdir: str, monkeypatch: pytest.MonkeyPatch) -> None: + def test_add_pth( + self, + tmp_path: pathlib.Path, + monkeypatch: pytest.MonkeyPatch, + ) -> None: monkeypatch.setattr(pip._internal.req.req_uninstall, "is_local", mock_is_local) # Fix case for windows tests - tmpdir = os.path.normcase(tmpdir) on_windows = sys.platform == "win32" - pth_file = os.path.join(tmpdir, "foo.pth") + pth_file = os.path.join(tmp_path, "foo.pth") relative = "../../example" if on_windows: share = "\\\\example\\share\\" share_com = "\\\\example.com\\share\\" # Create a .pth file for testing with open(pth_file, "w") as f: - f.writelines([tmpdir, "\n", relative, "\n"]) + f.writelines([str(tmp_path), "\n", relative, "\n"]) if on_windows: f.writelines([share, "\n", share_com, "\n"]) # Add paths to be removed pth = UninstallPthEntries(pth_file) - pth.add(tmpdir) + pth.add(str(tmp_path)) pth.add(relative) if on_windows: pth.add(share) pth.add(share_com) # Check that the paths were added to entries if on_windows: - check = {tmpdir, relative, share, share_com} + check = {str(tmp_path), relative, share, share_com} else: - check = {tmpdir, relative} + check = {str(tmp_path), relative} assert pth.entries == check @pytest.mark.skipif("sys.platform == 'win32'") - def test_add_symlink(self, tmpdir: Path, monkeypatch: pytest.MonkeyPatch) -> None: + def test_add_symlink( + self, + tmp_path: pathlib.Path, + monkeypatch: pytest.MonkeyPatch, + ) -> None: monkeypatch.setattr(pip._internal.req.req_uninstall, "is_local", mock_is_local) - f = os.path.join(tmpdir, "foo") + f = os.path.join(tmp_path, "foo") with open(f, "w"): pass - foo_link = os.path.join(tmpdir, "foo_link") + foo_link = os.path.join(tmp_path, "foo_link") os.symlink(f, foo_link) ups = UninstallPathSet(dist=Mock()) @@ -200,16 +207,16 @@ def test_compact_shorter_path(self, monkeypatch: pytest.MonkeyPatch) -> None: @pytest.mark.skipif("sys.platform == 'win32'") def test_detect_symlink_dirs( - self, monkeypatch: pytest.MonkeyPatch, tmpdir: Path + self, monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path ) -> None: monkeypatch.setattr(pip._internal.req.req_uninstall, "is_local", mock_is_local) # construct 2 paths: # tmpdir/dir/file # tmpdir/dirlink/file (where dirlink is a link to dir) - d = tmpdir.joinpath("dir") + d = tmp_path.joinpath("dir") d.mkdir() - dlink = tmpdir.joinpath("dirlink") + dlink = tmp_path.joinpath("dirlink") os.symlink(d, dlink) d.joinpath("file").touch() path1 = str(d.joinpath("file")) @@ -269,10 +276,10 @@ def test_compress_for_rename(self, monkeypatch: pytest.MonkeyPatch) -> None: @classmethod def make_stash( - cls, tmpdir: Path, paths: List[str] + cls, tmp_path: pathlib.Path, paths: List[str] ) -> Tuple[StashedUninstallPathSet, List[Tuple[str, str]]]: for dirname, subdirs, files in cls.WALK_RESULT: - root = os.path.join(tmpdir, *dirname.split("/")) + root = os.path.join(tmp_path, *dirname.split("/")) if not os.path.exists(root): os.mkdir(root) for d in subdirs: @@ -283,14 +290,14 @@ def make_stash( pathset = StashedUninstallPathSet() - paths = [os.path.join(tmpdir, *p.split("/")) for p in paths] + paths = [os.path.join(tmp_path, *p.split("/")) for p in paths] stashed_paths = [(p, pathset.stash(p)) for p in paths] return pathset, stashed_paths - def test_stash(self, tmpdir: Path) -> None: + def test_stash(self, tmp_path: pathlib.Path) -> None: pathset, stashed_paths = self.make_stash( - tmpdir, + tmp_path, [ "A/B/", "A/C/d.py", @@ -305,9 +312,9 @@ def test_stash(self, tmpdir: Path) -> None: assert stashed_paths == pathset._moves - def test_commit(self, tmpdir: Path) -> None: + def test_commit(self, tmp_path: pathlib.Path) -> None: pathset, stashed_paths = self.make_stash( - tmpdir, + tmp_path, [ "A/B/", "A/C/d.py", @@ -322,9 +329,9 @@ def test_commit(self, tmpdir: Path) -> None: assert not os.path.exists(old_path) assert not os.path.exists(new_path) - def test_rollback(self, tmpdir: Path) -> None: + def test_rollback(self, tmp_path: pathlib.Path) -> None: pathset, stashed_paths = self.make_stash( - tmpdir, + tmp_path, [ "A/B/", "A/C/d.py", @@ -340,20 +347,20 @@ def test_rollback(self, tmpdir: Path) -> None: assert not os.path.exists(new_path) @pytest.mark.skipif("sys.platform == 'win32'") - def test_commit_symlinks(self, tmpdir: Path) -> None: - adir = tmpdir / "dir" + def test_commit_symlinks(self, tmp_path: pathlib.Path) -> None: + adir = tmp_path / "dir" adir.mkdir() - dirlink = tmpdir / "dirlink" + dirlink = tmp_path / "dirlink" dirlink.symlink_to(adir) - afile = tmpdir / "file" + afile = tmp_path / "file" afile.write_text("...") - filelink = tmpdir / "filelink" + filelink = tmp_path / "filelink" filelink.symlink_to(afile) pathset = StashedUninstallPathSet() stashed_paths = [] - stashed_paths.append(pathset.stash(dirlink)) - stashed_paths.append(pathset.stash(filelink)) + stashed_paths.append(pathset.stash(str(dirlink))) + stashed_paths.append(pathset.stash(str(filelink))) for stashed_path in stashed_paths: assert os.path.lexists(stashed_path) assert not os.path.exists(dirlink) @@ -372,20 +379,20 @@ def test_commit_symlinks(self, tmpdir: Path) -> None: assert os.path.isfile(afile) @pytest.mark.skipif("sys.platform == 'win32'") - def test_rollback_symlinks(self, tmpdir: Path) -> None: - adir = tmpdir / "dir" + def test_rollback_symlinks(self, tmp_path: pathlib.Path) -> None: + adir = tmp_path / "dir" adir.mkdir() - dirlink = tmpdir / "dirlink" + dirlink = tmp_path / "dirlink" dirlink.symlink_to(adir) - afile = tmpdir / "file" + afile = tmp_path / "file" afile.write_text("...") - filelink = tmpdir / "filelink" + filelink = tmp_path / "filelink" filelink.symlink_to(afile) pathset = StashedUninstallPathSet() stashed_paths = [] - stashed_paths.append(pathset.stash(dirlink)) - stashed_paths.append(pathset.stash(filelink)) + stashed_paths.append(pathset.stash(str(dirlink))) + stashed_paths.append(pathset.stash(str(filelink))) for stashed_path in stashed_paths: assert os.path.lexists(stashed_path) assert not os.path.lexists(dirlink) diff --git a/tests/unit/test_resolution_legacy_resolver.py b/tests/unit/test_resolution_legacy_resolver.py index 134ff65b498..809eb15a9ab 100644 --- a/tests/unit/test_resolution_legacy_resolver.py +++ b/tests/unit/test_resolution_legacy_resolver.py @@ -110,7 +110,7 @@ def test_unsupported_wheel_local_file_requirement_raises( requirement_set = RequirementSet(check_supported_wheels=True) install_req = install_req_from_line( - data.packages.joinpath("simple.dist-0.1-py1-none-invalid.whl"), + str(data.packages.joinpath("simple.dist-0.1-py1-none-invalid.whl")), ) assert install_req.link is not None assert install_req.link.is_wheel diff --git a/tests/unit/test_self_check_outdated.py b/tests/unit/test_self_check_outdated.py index edfc4e82f19..7194986f5e1 100644 --- a/tests/unit/test_self_check_outdated.py +++ b/tests/unit/test_self_check_outdated.py @@ -1,6 +1,7 @@ import datetime import json import logging +import pathlib import sys from optparse import Values from typing import Optional @@ -11,7 +12,6 @@ from pip._vendor.packaging.version import Version from pip._internal import self_outdated_check -from tests.lib.path import Path @pytest.mark.parametrize( @@ -35,19 +35,19 @@ def test_get_statefile_name_known_values(key: str, expected: str) -> None: @patch("pip._internal.self_outdated_check._self_version_check_logic") @patch("pip._internal.self_outdated_check.SelfCheckState") def test_pip_self_version_check_calls_underlying_implementation( - mocked_state: Mock, mocked_function: Mock, tmpdir: Path + mocked_state: Mock, mocked_function: Mock, tmp_path: pathlib.Path ) -> None: # GIVEN mock_session = Mock() - fake_options = Values(dict(cache_dir=str(tmpdir))) + fake_options = Values({"cache_dir": str(tmp_path)}) # WHEN self_outdated_check.pip_self_version_check(mock_session, fake_options) # THEN - mocked_state.assert_called_once_with(cache_dir=str(tmpdir)) + mocked_state.assert_called_once_with(cache_dir=str(tmp_path)) mocked_function.assert_called_once_with( - state=mocked_state(cache_dir=str(tmpdir)), + state=mocked_state(cache_dir=str(tmp_path)), current_time=datetime.datetime(1970, 1, 2, 11, 0, 0), local_version=ANY, get_remote_version=ANY, @@ -134,9 +134,9 @@ def test_no_cache(self) -> None: state = self_outdated_check.SelfCheckState(cache_dir="") assert state._statefile_path is None - def test_reads_expected_statefile(self, tmpdir: Path) -> None: + def test_reads_expected_statefile(self, tmp_path: pathlib.Path) -> None: # GIVEN - cache_dir = tmpdir / "cache_dir" + cache_dir = tmp_path / "cache_dir" expected_path = ( cache_dir / "selfcheck" @@ -151,12 +151,12 @@ def test_reads_expected_statefile(self, tmpdir: Path) -> None: state = self_outdated_check.SelfCheckState(cache_dir=str(cache_dir)) # THEN - assert state._statefile_path == expected_path + assert state._statefile_path == str(expected_path) assert state._state == {"foo": "bar"} - def test_writes_expected_statefile(self, tmpdir: Path) -> None: + def test_writes_expected_statefile(self, tmp_path: pathlib.Path) -> None: # GIVEN - cache_dir = tmpdir / "cache_dir" + cache_dir = tmp_path / "cache_dir" cache_dir.mkdir() expected_path = ( cache_dir @@ -169,7 +169,7 @@ def test_writes_expected_statefile(self, tmpdir: Path) -> None: state.set("1.0.0", datetime.datetime(2000, 1, 1, 0, 0, 0)) # THEN - assert state._statefile_path == expected_path + assert state._statefile_path == str(expected_path) contents = expected_path.read_text() assert json.loads(contents) == { diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index 2d0a82bddf7..7afafacea00 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -4,6 +4,7 @@ """ import codecs import os +import pathlib import shutil import stat import sys @@ -46,7 +47,6 @@ tabulate, ) from pip._internal.utils.setuptools_build import make_setuptools_shim_args -from tests.lib.path import Path class Tests_EgglinkPath: @@ -207,11 +207,11 @@ def test_noegglink_in_sitepkgs_venv_global(self) -> None: assert egg_link_path_from_location(self.mock_dist.project_name) is None -def test_rmtree_errorhandler_nonexistent_directory(tmpdir: Path) -> None: +def test_rmtree_errorhandler_nonexistent_directory(tmp_path: pathlib.Path) -> None: """ Test rmtree_errorhandler ignores the given non-existing directory. """ - nonexistent_path = str(tmpdir / "foo") + nonexistent_path = str(tmp_path / "foo") mock_func = Mock() # Argument 3 to "rmtree_errorhandler" has incompatible type "None"; expected # "Tuple[Type[BaseException], BaseException, TracebackType]" @@ -219,12 +219,12 @@ def test_rmtree_errorhandler_nonexistent_directory(tmpdir: Path) -> None: mock_func.assert_not_called() -def test_rmtree_errorhandler_readonly_directory(tmpdir: Path) -> None: +def test_rmtree_errorhandler_readonly_directory(tmp_path: pathlib.Path) -> None: """ Test rmtree_errorhandler makes the given read-only directory writable. """ # Create read only directory - subdir_path = tmpdir / "subdir" + subdir_path = tmp_path / "subdir" subdir_path.mkdir() path = str(subdir_path) os.chmod(path, stat.S_IREAD) @@ -240,13 +240,13 @@ def test_rmtree_errorhandler_readonly_directory(tmpdir: Path) -> None: assert os.stat(path).st_mode & stat.S_IWRITE -def test_rmtree_errorhandler_reraises_error(tmpdir: Path) -> None: +def test_rmtree_errorhandler_reraises_error(tmp_path: pathlib.Path) -> None: """ Test rmtree_errorhandler reraises an exception by the given unreadable directory. """ # Create directory without read permission - subdir_path = tmpdir / "subdir" + subdir_path = tmp_path / "subdir" subdir_path.mkdir() path = str(subdir_path) os.chmod(path, stat.S_IWRITE) @@ -315,11 +315,9 @@ class Test_normalize_path: # permission bit to create them, and Python 2 doesn't support it anyway, so # it's easiest just to skip this test on Windows altogether. @pytest.mark.skipif("sys.platform == 'win32'") - def test_resolve_symlinks(self, tmpdir: Path) -> None: - print(type(tmpdir)) - print(dir(tmpdir)) + def test_resolve_symlinks(self, tmp_path: pathlib.Path) -> None: orig_working_dir = os.getcwd() - os.chdir(tmpdir) + os.chdir(tmp_path) try: d = os.path.join("foo", "bar") f = os.path.join(d, "file1") @@ -332,16 +330,16 @@ def test_resolve_symlinks(self, tmpdir: Path) -> None: assert normalize_path( "dir_link/file1", resolve_symlinks=True - ) == os.path.join(tmpdir, f) + ) == os.path.join(tmp_path, f) assert normalize_path( "dir_link/file1", resolve_symlinks=False - ) == os.path.join(tmpdir, "dir_link", "file1") + ) == os.path.join(tmp_path, "dir_link", "file1") assert normalize_path("file_link", resolve_symlinks=True) == os.path.join( - tmpdir, f + tmp_path, f ) assert normalize_path("file_link", resolve_symlinks=False) == os.path.join( - tmpdir, "file_link" + tmp_path, "file_link" ) finally: os.chdir(orig_working_dir) @@ -371,13 +369,13 @@ def test_is_hash_allowed( hashes = Hashes(hashes_data) assert hashes.is_hash_allowed(hash_name, hex_digest) == expected - def test_success(self, tmpdir: Path) -> None: + def test_success(self, tmp_path: pathlib.Path) -> None: """Make sure no error is raised when at least one hash matches. Test check_against_path because it calls everything else. """ - file = tmpdir / "to_hash" + file = tmp_path / "to_hash" file.write_text("hello") hashes = Hashes( { @@ -389,7 +387,7 @@ def test_success(self, tmpdir: Path) -> None: "md5": ["5d41402abc4b2a76b9719d911017c592"], } ) - hashes.check_against_path(file) + hashes.check_against_path(str(file)) def test_failure(self) -> None: """Hashes should raise HashMismatch when no hashes match.""" diff --git a/tests/unit/test_utils_filesystem.py b/tests/unit/test_utils_filesystem.py index 1b730f8b8f7..c5fd90f2a24 100644 --- a/tests/unit/test_utils_filesystem.py +++ b/tests/unit/test_utils_filesystem.py @@ -1,16 +1,16 @@ import os +import pathlib -from tests.lib.path import Path - -def make_file(path: str) -> None: - Path(path).touch() +def make_file(path: str) -> pathlib.Path: + p = pathlib.Path(path) + p.touch() + return p def make_valid_symlink(path: str) -> None: - target = path + "1" - make_file(target) - os.symlink(target, path) + target = make_file(path + "1") + target.symlink_to(path) def make_broken_symlink(path: str) -> None: diff --git a/tests/unit/test_utils_temp_dir.py b/tests/unit/test_utils_temp_dir.py index 6b3571ff71c..2059f767cba 100644 --- a/tests/unit/test_utils_temp_dir.py +++ b/tests/unit/test_utils_temp_dir.py @@ -1,5 +1,6 @@ import itertools import os +import pathlib import stat import tempfile from typing import Any, Iterator, Optional, Union @@ -16,7 +17,6 @@ global_tempdir_manager, tempdir_registry, ) -from tests.lib.path import Path # No need to test symlinked directories on Windows @@ -165,13 +165,13 @@ def names() -> Iterator[str]: "_package", ], ) -def test_adjacent_directory_exists(name: str, tmpdir: Path) -> None: +def test_adjacent_directory_exists(name: str, tmp_path: pathlib.Path) -> None: block_name, expect_name = itertools.islice( AdjacentTempDirectory._generate_names(name), 2 ) - original = os.path.join(tmpdir, name) - blocker = os.path.join(tmpdir, block_name) + original = os.path.join(tmp_path, name) + blocker = os.path.join(tmp_path, block_name) ensure_dir(original) ensure_dir(blocker) @@ -247,16 +247,16 @@ def test_tempdir_registry( @pytest.mark.parametrize("delete,exists", [(_default, True), (None, False)]) def test_temp_dir_does_not_delete_explicit_paths_by_default( - tmpdir: Path, delete: Optional[_Default], exists: bool + tmp_path: pathlib.Path, delete: Optional[_Default], exists: bool ) -> None: - path = tmpdir / "example" + path = tmp_path / "example" path.mkdir() with tempdir_registry() as registry: registry.set_delete(deleted_kind, True) - with TempDirectory(path=path, delete=delete, kind=deleted_kind) as d: - assert str(d.path) == path + with TempDirectory(path=str(path), delete=delete, kind=deleted_kind) as d: + assert d.path == str(path) assert os.path.exists(path) assert os.path.exists(path) == exists diff --git a/tests/unit/test_utils_unpacking.py b/tests/unit/test_utils_unpacking.py index ccb7a304925..6d100c85b35 100644 --- a/tests/unit/test_utils_unpacking.py +++ b/tests/unit/test_utils_unpacking.py @@ -1,5 +1,6 @@ import io import os +import pathlib import shutil import stat import sys @@ -14,7 +15,6 @@ from pip._internal.exceptions import InstallationError from pip._internal.utils.unpacking import is_within_directory, untar_file, unzip_file from tests.lib import TestData -from tests.lib.path import Path class TestUnpackArchives: @@ -106,7 +106,7 @@ def test_unpack_tgz(self, data: TestData) -> None: Test unpacking a *.tgz, and setting execute permissions """ test_file = data.packages.joinpath("test_tar.tgz") - untar_file(test_file, self.tempdir) + untar_file(str(test_file), self.tempdir) self.confirm_files() # Check the timestamp of an extracted file file_txt_path = os.path.join(self.tempdir, "file.txt") @@ -118,7 +118,7 @@ def test_unpack_zip(self, data: TestData) -> None: Test unpacking a *.zip, and setting execute permissions """ test_file = data.packages.joinpath("test_zip.zip") - unzip_file(test_file, self.tempdir) + unzip_file(str(test_file), self.tempdir) self.confirm_files() def test_unpack_zip_failure(self) -> None: @@ -172,17 +172,17 @@ def test_unpack_tar_success(self) -> None: untar_file(test_tar, self.tempdir) -def test_unpack_tar_unicode(tmpdir: Path) -> None: - test_tar = tmpdir / "test.tar" +def test_unpack_tar_unicode(tmp_path: pathlib.Path) -> None: + test_tar = tmp_path / "test.tar" # tarfile tries to decode incoming with tarfile.open(test_tar, "w", format=tarfile.PAX_FORMAT, encoding="utf-8") as f: metadata = tarfile.TarInfo("dir/åäö_日本語.py") f.addfile(metadata, io.BytesIO(b"hello world")) - output_dir = tmpdir / "output" + output_dir = tmp_path / "output" output_dir.mkdir() - untar_file(test_tar, str(output_dir)) + untar_file(str(test_tar), str(output_dir)) output_dir_name = str(output_dir) contents = os.listdir(output_dir_name) diff --git a/tests/unit/test_utils_virtualenv.py b/tests/unit/test_utils_virtualenv.py index 8f517d24d36..e5540fcb2b1 100644 --- a/tests/unit/test_utils_virtualenv.py +++ b/tests/unit/test_utils_virtualenv.py @@ -1,4 +1,5 @@ import logging +import pathlib import site import sys from typing import List, Optional @@ -6,7 +7,6 @@ import pytest from pip._internal.utils import virtualenv -from tests.lib.path import Path @pytest.mark.parametrize( @@ -52,21 +52,21 @@ def test_running_under_virtualenv( ) def test_virtualenv_no_global_with_regular_virtualenv( monkeypatch: pytest.MonkeyPatch, - tmpdir: Path, + tmp_path: pathlib.Path, under_virtualenv: bool, no_global_file: bool, expected: bool, ) -> None: monkeypatch.setattr(virtualenv, "_running_under_venv", lambda: False) - monkeypatch.setattr(site, "__file__", tmpdir / "site.py") + monkeypatch.setattr(site, "__file__", str(tmp_path / "site.py")) monkeypatch.setattr( virtualenv, "_running_under_regular_virtualenv", lambda: under_virtualenv, ) if no_global_file: - (tmpdir / "no-global-site-packages.txt").touch() + (tmp_path / "no-global-site-packages.txt").touch() assert virtualenv.virtualenv_no_global() == expected @@ -133,12 +133,12 @@ def test_virtualenv_no_global_with_pep_405_virtual_environment( ) def test_get_pyvenv_cfg_lines_for_pep_405_virtual_environment( monkeypatch: pytest.MonkeyPatch, - tmpdir: Path, + tmp_path: pathlib.Path, contents: Optional[str], expected: Optional[List[str]], ) -> None: - monkeypatch.setattr(sys, "prefix", str(tmpdir)) + monkeypatch.setattr(sys, "prefix", str(tmp_path)) if contents is not None: - tmpdir.joinpath("pyvenv.cfg").write_text(contents) + tmp_path.joinpath("pyvenv.cfg").write_text(contents) assert virtualenv._get_pyvenv_cfg_lines() == expected diff --git a/tests/unit/test_utils_wheel.py b/tests/unit/test_utils_wheel.py index 53e149f9493..a4304c5cbba 100644 --- a/tests/unit/test_utils_wheel.py +++ b/tests/unit/test_utils_wheel.py @@ -1,4 +1,5 @@ import os +import pathlib from contextlib import ExitStack from email import message_from_string from io import BytesIO @@ -10,14 +11,13 @@ from pip._internal.exceptions import UnsupportedWheel from pip._internal.utils import wheel from tests.lib import TestData -from tests.lib.path import Path -_ZipDir = Callable[[Path], ZipFile] +_ZipDir = Callable[[pathlib.Path], ZipFile] @pytest.fixture def zip_dir() -> Iterator[_ZipDir]: - def make_zip(path: Path) -> ZipFile: + def make_zip(path: pathlib.Path) -> ZipFile: buf = BytesIO() with ZipFile(buf, "w", allowZip64=True) as z: for dirpath, _, filenames in os.walk(path): @@ -36,38 +36,41 @@ def make_zip(path: Path) -> ZipFile: yield make_zip -def test_wheel_dist_info_dir_found(tmpdir: Path, zip_dir: _ZipDir) -> None: +def test_wheel_dist_info_dir_found(tmp_path: pathlib.Path, zip_dir: _ZipDir) -> None: expected = "simple-0.1.dist-info" - dist_info_dir = tmpdir / expected + dist_info_dir = tmp_path / expected dist_info_dir.mkdir() dist_info_dir.joinpath("WHEEL").touch() - assert wheel.wheel_dist_info_dir(zip_dir(tmpdir), "simple") == expected + assert wheel.wheel_dist_info_dir(zip_dir(tmp_path), "simple") == expected -def test_wheel_dist_info_dir_multiple(tmpdir: Path, zip_dir: _ZipDir) -> None: - dist_info_dir_1 = tmpdir / "simple-0.1.dist-info" +def test_wheel_dist_info_dir_multiple(tmp_path: pathlib.Path, zip_dir: _ZipDir) -> None: + dist_info_dir_1 = tmp_path / "simple-0.1.dist-info" dist_info_dir_1.mkdir() dist_info_dir_1.joinpath("WHEEL").touch() - dist_info_dir_2 = tmpdir / "unrelated-0.1.dist-info" + dist_info_dir_2 = tmp_path / "unrelated-0.1.dist-info" dist_info_dir_2.mkdir() dist_info_dir_2.joinpath("WHEEL").touch() with pytest.raises(UnsupportedWheel) as e: - wheel.wheel_dist_info_dir(zip_dir(tmpdir), "simple") + wheel.wheel_dist_info_dir(zip_dir(tmp_path), "simple") assert "multiple .dist-info directories found" in str(e.value) -def test_wheel_dist_info_dir_none(tmpdir: Path, zip_dir: _ZipDir) -> None: +def test_wheel_dist_info_dir_none(tmp_path: pathlib.Path, zip_dir: _ZipDir) -> None: with pytest.raises(UnsupportedWheel) as e: - wheel.wheel_dist_info_dir(zip_dir(tmpdir), "simple") + wheel.wheel_dist_info_dir(zip_dir(tmp_path), "simple") assert "directory not found" in str(e.value) -def test_wheel_dist_info_dir_wrong_name(tmpdir: Path, zip_dir: _ZipDir) -> None: - dist_info_dir = tmpdir / "unrelated-0.1.dist-info" +def test_wheel_dist_info_dir_wrong_name( + tmp_path: pathlib.Path, + zip_dir: _ZipDir, +) -> None: + dist_info_dir = tmp_path / "unrelated-0.1.dist-info" dist_info_dir.mkdir() dist_info_dir.joinpath("WHEEL").touch() with pytest.raises(UnsupportedWheel) as e: - wheel.wheel_dist_info_dir(zip_dir(tmpdir), "simple") + wheel.wheel_dist_info_dir(zip_dir(tmp_path), "simple") assert "does not start with 'simple'" in str(e.value) @@ -75,24 +78,30 @@ def test_wheel_version_ok(data: TestData) -> None: assert wheel.wheel_version(message_from_string("Wheel-Version: 1.9")) == (1, 9) -def test_wheel_metadata_fails_missing_wheel(tmpdir: Path, zip_dir: _ZipDir) -> None: - dist_info_dir = tmpdir / "simple-0.1.0.dist-info" +def test_wheel_metadata_fails_missing_wheel( + tmp_path: pathlib.Path, + zip_dir: _ZipDir, +) -> None: + dist_info_dir = tmp_path / "simple-0.1.0.dist-info" dist_info_dir.mkdir() dist_info_dir.joinpath("METADATA").touch() with pytest.raises(UnsupportedWheel) as e: - wheel.wheel_metadata(zip_dir(tmpdir), dist_info_dir.name) + wheel.wheel_metadata(zip_dir(tmp_path), dist_info_dir.name) assert "could not read" in str(e.value) -def test_wheel_metadata_fails_on_bad_encoding(tmpdir: Path, zip_dir: _ZipDir) -> None: - dist_info_dir = tmpdir / "simple-0.1.0.dist-info" +def test_wheel_metadata_fails_on_bad_encoding( + tmp_path: pathlib.Path, + zip_dir: _ZipDir, +) -> None: + dist_info_dir = tmp_path / "simple-0.1.0.dist-info" dist_info_dir.mkdir() dist_info_dir.joinpath("METADATA").touch() dist_info_dir.joinpath("WHEEL").write_bytes(b"\xff") with pytest.raises(UnsupportedWheel) as e: - wheel.wheel_metadata(zip_dir(tmpdir), dist_info_dir.name) + wheel.wheel_metadata(zip_dir(tmp_path), dist_info_dir.name) assert "error decoding" in str(e.value) diff --git a/tests/unit/test_vcs.py b/tests/unit/test_vcs.py index 64f60bc407a..f98529cbfc7 100644 --- a/tests/unit/test_vcs.py +++ b/tests/unit/test_vcs.py @@ -15,7 +15,6 @@ from pip._internal.vcs.subversion import Subversion from pip._internal.vcs.versioncontrol import RevOptions, VersionControl from tests.lib import is_svn_installed, need_svn -from tests.lib.path import Path @pytest.mark.skipif( @@ -201,8 +200,8 @@ def test_paths_are_not_mistaken_for_scp_shorthand(url: str, platform: str) -> No Git._git_remote_to_pip_url(url) -def test_git_remote_local_path(tmpdir: Path) -> None: - path = pathlib.Path(tmpdir, "project.git") +def test_git_remote_local_path(tmp_path: pathlib.Path) -> None: + path = tmp_path.joinpath("project.git") path.mkdir() # Path must exist to be recognised as a local git remote. assert Git._git_remote_to_pip_url(str(path)) == path.as_uri() diff --git a/tests/unit/test_vcs_mercurial.py b/tests/unit/test_vcs_mercurial.py index 22ec2b60ed4..fb8eb843d18 100644 --- a/tests/unit/test_vcs_mercurial.py +++ b/tests/unit/test_vcs_mercurial.py @@ -3,29 +3,30 @@ """ import configparser -import os +import pathlib from pip._internal.utils.misc import hide_url from pip._internal.vcs.mercurial import Mercurial from tests.lib import need_mercurial -from tests.lib.path import Path @need_mercurial -def test_mercurial_switch_updates_config_file_when_found(tmpdir: Path) -> None: +def test_mercurial_switch_updates_config_file_when_found( + tmp_path: pathlib.Path, +) -> None: hg = Mercurial() options = hg.make_rev_options() - hg_dir = os.path.join(tmpdir, ".hg") - os.mkdir(hg_dir) + hg_dir = tmp_path.joinpath(".hg") + hg_dir.mkdir() config = configparser.RawConfigParser() config.add_section("paths") config.set("paths", "default", "old_url") - hgrc_path = os.path.join(hg_dir, "hgrc") - with open(hgrc_path, "w") as f: + hgrc_path = hg_dir.joinpath("hgrc") + with hgrc_path.open("w") as f: config.write(f) - hg.switch(tmpdir, hide_url("new_url"), options) + hg.switch(str(tmp_path), hide_url("new_url"), options) config.read(hgrc_path) diff --git a/tests/unit/test_wheel.py b/tests/unit/test_wheel.py index a698656b2df..75d8ef9b696 100644 --- a/tests/unit/test_wheel.py +++ b/tests/unit/test_wheel.py @@ -26,7 +26,6 @@ from pip._internal.utils.misc import hash_file from pip._internal.utils.unpacking import unpack_file from tests.lib import DATA_DIR, TestData, assert_paths_equal -from tests.lib.path import Path from tests.lib.wheel import make_wheel @@ -172,8 +171,11 @@ def test_normalized_outrows( assert actual == expected -def call_get_csv_rows_for_installed(tmpdir: Path, text: str) -> List[InstalledCSVRow]: - path = tmpdir.joinpath("temp.txt") +def call_get_csv_rows_for_installed( + tmp_path: pathlib.Path, + text: str, +) -> List[InstalledCSVRow]: + path = tmp_path.joinpath("temp.txt") path.write_text(text) # Test that an installed file appearing in RECORD has its filename @@ -194,7 +196,7 @@ def call_get_csv_rows_for_installed(tmpdir: Path, text: str) -> List[InstalledCS def test_get_csv_rows_for_installed( - tmpdir: Path, caplog: pytest.LogCaptureFixture + tmp_path: pathlib.Path, caplog: pytest.LogCaptureFixture ) -> None: text = textwrap.dedent( """\ @@ -202,7 +204,7 @@ def test_get_csv_rows_for_installed( d,e,f """ ) - outrows = call_get_csv_rows_for_installed(tmpdir, text) + outrows = call_get_csv_rows_for_installed(tmp_path, text) expected = [ ("z", "b", "c"), @@ -214,7 +216,7 @@ def test_get_csv_rows_for_installed( def test_get_csv_rows_for_installed__long_lines( - tmpdir: Path, caplog: pytest.LogCaptureFixture + tmp_path: pathlib.Path, caplog: pytest.LogCaptureFixture ) -> None: text = textwrap.dedent( """\ @@ -223,7 +225,7 @@ def test_get_csv_rows_for_installed__long_lines( h,i,j,k """ ) - outrows = call_get_csv_rows_for_installed(tmpdir, text) + outrows = call_get_csv_rows_for_installed(tmp_path, text) assert outrows == [ ("z", "b", "c"), ("e", "f", "g"), @@ -258,14 +260,14 @@ def test_dist_from_broken_wheel_fails(data: TestData) -> None: package = data.packages.joinpath("corruptwheel-1.0-py2.py3-none-any.whl") with pytest.raises(InvalidWheel): - get_wheel_distribution(FilesystemWheel(package), "brokenwheel") + get_wheel_distribution(FilesystemWheel(str(package)), "brokenwheel") class TestWheelFile: - def test_unpack_wheel_no_flatten(self, tmpdir: Path) -> None: + def test_unpack_wheel_no_flatten(self, tmp_path: pathlib.Path) -> None: filepath = os.path.join(DATA_DIR, "packages", "meta-1.0-py2.py3-none-any.whl") - unpack_file(filepath, tmpdir) - assert os.path.isdir(os.path.join(tmpdir, "meta-1.0.dist-info")) + unpack_file(filepath, str(tmp_path)) + assert tmp_path.joinpath("meta-1.0.dist-info").is_dir() class TestInstallUnpackedWheel: @@ -273,12 +275,12 @@ class TestInstallUnpackedWheel: Tests for moving files from wheel src to scheme paths """ - def prep(self, data: TestData, tmpdir: str) -> None: + def prep(self, tmp_path: pathlib.Path) -> None: # Since Path implements __add__, os.path.join returns a Path object. # Passing Path objects to interfaces expecting str (like # `compileall.compile_file`) can cause failures, so we normalize it # to a string here. - tmpdir = str(tmpdir) + tmpdir = str(tmp_path) self.name = "sample" self.wheelpath = make_wheel( "sample", @@ -360,8 +362,9 @@ def assert_installed(self, expected_permission: int) -> None: pkg_data = os.path.join(self.scheme.purelib, "sample", "package_data.dat") assert os.path.isfile(pkg_data) - def test_std_install(self, data: TestData, tmpdir: Path) -> None: - self.prep(data, tmpdir) + @pytest.mark.usefixtures("data") + def test_std_install(self, tmp_path: pathlib.Path) -> None: + self.prep(tmp_path) wheel.install_wheel( self.name, self.wheelpath, @@ -370,16 +373,17 @@ def test_std_install(self, data: TestData, tmpdir: Path) -> None: ) self.assert_installed(0o644) + @pytest.mark.usefixtures("data") @pytest.mark.parametrize("user_mask, expected_permission", [(0o27, 0o640)]) def test_std_install_with_custom_umask( - self, data: TestData, tmpdir: Path, user_mask: int, expected_permission: int + self, tmp_path: pathlib.Path, user_mask: int, expected_permission: int ) -> None: """Test that the files created after install honor the permissions set when the user sets a custom umask""" prev_umask = os.umask(user_mask) try: - self.prep(data, tmpdir) + self.prep(tmp_path) wheel.install_wheel( self.name, self.wheelpath, @@ -390,8 +394,9 @@ def test_std_install_with_custom_umask( finally: os.umask(prev_umask) - def test_std_install_requested(self, data: TestData, tmpdir: Path) -> None: - self.prep(data, tmpdir) + @pytest.mark.usefixtures("data") + def test_std_install_requested(self, tmp_path: pathlib.Path) -> None: + self.prep(tmp_path) wheel.install_wheel( self.name, self.wheelpath, @@ -403,14 +408,15 @@ def test_std_install_requested(self, data: TestData, tmpdir: Path) -> None: requested_path = os.path.join(self.dest_dist_info, "REQUESTED") assert os.path.isfile(requested_path) - def test_std_install_with_direct_url(self, data: TestData, tmpdir: Path) -> None: + @pytest.mark.usefixtures("data") + def test_std_install_with_direct_url(self, tmp_path: pathlib.Path) -> None: """Test that install_wheel creates direct_url.json metadata when provided with a direct_url argument. Also test that the RECORDS file contains an entry for direct_url.json in that case. Note direct_url.url is intentionally different from wheelpath, because wheelpath is typically the result of a local build. """ - self.prep(data, tmpdir) + self.prep(tmp_path) direct_url = DirectUrl( url="file:///home/user/archive.tgz", info=ArchiveInfo(), @@ -432,14 +438,15 @@ def test_std_install_with_direct_url(self, data: TestData, tmpdir: Path) -> None with open(os.path.join(self.dest_dist_info, "RECORD")) as f2: assert DIRECT_URL_METADATA_NAME in f2.read() - def test_install_prefix(self, data: TestData, tmpdir: Path) -> None: + @pytest.mark.usefixtures("data") + def test_install_prefix(self, tmp_path: pathlib.Path) -> None: prefix = os.path.join(os.path.sep, "some", "path") - self.prep(data, tmpdir) + self.prep(tmp_path) scheme = get_scheme( self.name, user=False, home=None, - root=str(tmpdir), # Casting needed for CPython 3.10+. See GH-10358. + root=str(tmp_path), isolated=False, prefix=prefix, ) @@ -451,15 +458,16 @@ def test_install_prefix(self, data: TestData, tmpdir: Path) -> None: ) bin_dir = "Scripts" if WINDOWS else "bin" - assert os.path.exists(os.path.join(tmpdir, "some", "path", bin_dir)) - assert os.path.exists(os.path.join(tmpdir, "some", "path", "my_data")) + assert os.path.exists(os.path.join(tmp_path, "some", "path", bin_dir)) + assert os.path.exists(os.path.join(tmp_path, "some", "path", "my_data")) - def test_dist_info_contains_empty_dir(self, data: TestData, tmpdir: Path) -> None: + @pytest.mark.usefixtures("data") + def test_dist_info_contains_empty_dir(self, tmp_path: pathlib.Path) -> None: """ Test that empty dirs are not installed """ # e.g. https://github.com/pypa/pip/issues/1632#issuecomment-38027275 - self.prep(data, tmpdir) + self.prep(tmp_path) wheel.install_wheel( self.name, self.wheelpath, @@ -469,14 +477,15 @@ def test_dist_info_contains_empty_dir(self, data: TestData, tmpdir: Path) -> Non self.assert_installed(0o644) assert not os.path.isdir(os.path.join(self.dest_dist_info, "empty_dir")) + @pytest.mark.usefixtures("data") @pytest.mark.parametrize("path", ["/tmp/example", "../example", "./../example"]) def test_wheel_install_rejects_bad_paths( - self, data: TestData, tmpdir: Path, path: str + self, tmp_path: pathlib.Path, path: str ) -> None: - self.prep(data, tmpdir) + self.prep(tmp_path) wheel_path = make_wheel( "simple", "0.1.0", extra_files={path: "example contents\n"} - ).save_to_dir(tmpdir) + ).save_to_dir(tmp_path) with pytest.raises(InstallationError) as e: wheel.install_wheel( "simple", @@ -490,15 +499,16 @@ def test_wheel_install_rejects_bad_paths( assert "example" in exc_text @pytest.mark.xfail(strict=True) + @pytest.mark.usefixtures("data") @pytest.mark.parametrize("entrypoint", ["hello = hello", "hello = hello:"]) @pytest.mark.parametrize("entrypoint_type", ["console_scripts", "gui_scripts"]) def test_invalid_entrypoints_fail( - self, data: TestData, tmpdir: Path, entrypoint: str, entrypoint_type: str + self, tmp_path: pathlib.Path, entrypoint: str, entrypoint_type: str ) -> None: - self.prep(data, tmpdir) + self.prep(tmp_path) wheel_path = make_wheel( "simple", "0.1.0", entry_points={entrypoint_type: [entrypoint]} - ).save_to_dir(tmpdir) + ).save_to_dir(tmp_path) with pytest.raises(InstallationError) as e: wheel.install_wheel( "simple", @@ -657,11 +667,11 @@ def test_multi_script_all_tilde_not_at_start__multi_dir_not_on_PATH(self) -> Non class TestWheelHashCalculators: - def prep(self, tmpdir: Path) -> None: - self.test_file = tmpdir.joinpath("hash.file") + def prep(self, tmp_path: pathlib.Path) -> None: + self.test_file = tmp_path.joinpath("hash.file") # Want this big enough to trigger the internal read loops. self.test_file_len = 2 * 1024 * 1024 - with open(str(self.test_file), "w") as fp: + with self.test_file.open("w") as fp: fp.truncate(self.test_file_len) self.test_file_hash = ( "5647f05ec18958947d32874eeb788fa396a05d0bab7c1b71f112ceb7e9b31eee" @@ -670,14 +680,14 @@ def prep(self, tmpdir: Path) -> None: "sha256=VkfwXsGJWJR9ModO63iPo5agXQurfBtx8RLOt-mzHu4" ) - def test_hash_file(self, tmpdir: Path) -> None: - self.prep(tmpdir) - h, length = hash_file(self.test_file) + def test_hash_file(self, tmp_path: pathlib.Path) -> None: + self.prep(tmp_path) + h, length = hash_file(str(self.test_file)) assert length == self.test_file_len assert h.hexdigest() == self.test_file_hash - def test_rehash(self, tmpdir: Path) -> None: - self.prep(tmpdir) - h, length = wheel.rehash(self.test_file) + def test_rehash(self, tmp_path: pathlib.Path) -> None: + self.prep(tmp_path) + h, length = wheel.rehash(str(self.test_file)) assert length == str(self.test_file_len) assert h == self.test_file_hash_encoded diff --git a/tests/unit/test_wheel_builder.py b/tests/unit/test_wheel_builder.py index 0468273d66a..74d115a9f3a 100644 --- a/tests/unit/test_wheel_builder.py +++ b/tests/unit/test_wheel_builder.py @@ -178,12 +178,12 @@ def test_should_cache_git_sha(script: PipTestEnvironment) -> None: # a link referencing a sha should be cached url = "git+https://g.c/o/r@" + commit + "#egg=mypkg" - req = ReqMock(link=Link(url), source_dir=repo_path) + req = ReqMock(link=Link(url), source_dir=str(repo_path)) assert wheel_builder._should_cache(cast(InstallRequirement, req)) # a link not referencing a sha should not be cached url = "git+https://g.c/o/r@master#egg=mypkg" - req = ReqMock(link=Link(url), source_dir=repo_path) + req = ReqMock(link=Link(url), source_dir=str(repo_path)) assert not wheel_builder._should_cache(cast(InstallRequirement, req)) diff --git a/tools/protected_pip.py b/tools/protected_pip.py index 671518029a5..48230719ee2 100644 --- a/tools/protected_pip.py +++ b/tools/protected_pip.py @@ -1,15 +1,16 @@ import os +import pathlib import shutil import subprocess import sys from glob import glob -from typing import List +from typing import Iterable, Union VIRTUAL_ENV = os.environ["VIRTUAL_ENV"] TOX_PIP_DIR = os.path.join(VIRTUAL_ENV, "pip") -def pip(args: List[str]) -> None: +def pip(args: Iterable[Union[str, pathlib.Path]]) -> None: # First things first, get a recent (stable) version of pip. if not os.path.exists(TOX_PIP_DIR): subprocess.check_call( @@ -30,7 +31,7 @@ def pip(args: List[str]) -> None: pypath = pypath_env.split(os.pathsep) if pypath_env is not None else [] pypath.insert(0, TOX_PIP_DIR) os.environ["PYTHONPATH"] = os.pathsep.join(pypath) - subprocess.check_call([sys.executable, "-m", "pip"] + args) + subprocess.check_call([sys.executable, "-m", "pip", *(os.fspath(a) for a in args)]) if __name__ == "__main__":