diff --git a/news/11457.removal.rst b/news/11457.removal.rst new file mode 100644 index 00000000000..eb579147eeb --- /dev/null +++ b/news/11457.removal.rst @@ -0,0 +1,2 @@ +Remove support for the legacy setup.py develop editable method in setuptools +editable installs; setuptools >= 64 is now required. diff --git a/news/11859.removal.rst b/news/11859.removal.rst new file mode 100644 index 00000000000..fa56c8d05f6 --- /dev/null +++ b/news/11859.removal.rst @@ -0,0 +1,2 @@ +Remove the deprecated ``--global-option`` and ``--build-option``. +``--config-setting`` is now the only way to pass options to the build backend. diff --git a/news/6334.removal.rst b/news/6334.removal.rst new file mode 100644 index 00000000000..791846540b2 --- /dev/null +++ b/news/6334.removal.rst @@ -0,0 +1,2 @@ +Remove support for the deprecated ``setup.py bdist_wheel`` mechanism. Consequently, +``--use-pep517`` is now always on, and ``--no-use-pep517`` has been removed. diff --git a/src/pip/_internal/cli/cmdoptions.py b/src/pip/_internal/cli/cmdoptions.py index 3519dadf13d..5b47c65013f 100644 --- a/src/pip/_internal/cli/cmdoptions.py +++ b/src/pip/_internal/cli/cmdoptions.py @@ -11,7 +11,6 @@ # mypy: strict-optional=False from __future__ import annotations -import importlib.util import logging import os import pathlib @@ -161,8 +160,7 @@ class PipOption(Option): action="store_true", default=False, help=( - "Allow pip to only run in a virtual environment; " - "exit with an error otherwise." + "Allow pip to only run in a virtual environment; exit with an error otherwise." ), ) @@ -813,62 +811,16 @@ def _handle_dependency_group( dest="check_build_deps", action="store_true", default=False, - help="Check the build dependencies when PEP517 is used.", + help="Check the build dependencies.", ) -def _handle_no_use_pep517( - option: Option, opt: str, value: str, parser: OptionParser -) -> None: - """ - Process a value provided for the --no-use-pep517 option. - - This is an optparse.Option callback for the no_use_pep517 option. - """ - # Since --no-use-pep517 doesn't accept arguments, the value argument - # will be None if --no-use-pep517 is passed via the command-line. - # However, the value can be non-None if the option is triggered e.g. - # by an environment variable, for example "PIP_NO_USE_PEP517=true". - if value is not None: - msg = """A value was passed for --no-use-pep517, - probably using either the PIP_NO_USE_PEP517 environment variable - or the "no-use-pep517" config file option. Use an appropriate value - of the PIP_USE_PEP517 environment variable or the "use-pep517" - config file option instead. - """ - raise_option_error(parser, option=option, msg=msg) - - # If user doesn't wish to use pep517, we check if setuptools is installed - # and raise error if it is not. - packages = ("setuptools",) - if not all(importlib.util.find_spec(package) for package in packages): - msg = ( - f"It is not possible to use --no-use-pep517 " - f"without {' and '.join(packages)} installed." - ) - raise_option_error(parser, option=option, msg=msg) - - # Otherwise, --no-use-pep517 was passed via the command-line. - parser.values.use_pep517 = False - - use_pep517: Any = partial( Option, "--use-pep517", dest="use_pep517", action="store_true", - default=None, - help="Use PEP 517 for building source distributions " - "(use --no-use-pep517 to force legacy behaviour).", -) - -no_use_pep517: Any = partial( - Option, - "--no-use-pep517", - dest="use_pep517", - action="callback", - callback=_handle_no_use_pep517, - default=None, + default=True, help=SUPPRESS_HELP, ) @@ -901,30 +853,11 @@ def _handle_config_settings( action="callback", callback=_handle_config_settings, metavar="settings", - help="Configuration settings to be passed to the PEP 517 build backend. " + help="Configuration settings to be passed to the build backend. " "Settings take the form KEY=VALUE. Use multiple --config-settings options " "to pass multiple keys to the backend.", ) -build_options: Callable[..., Option] = partial( - Option, - "--build-option", - dest="build_options", - metavar="options", - action="append", - help="Extra arguments to be supplied to 'setup.py bdist_wheel'.", -) - -global_options: Callable[..., Option] = partial( - Option, - "--global-option", - dest="global_options", - action="append", - metavar="options", - help="Extra global options to be supplied to the setup.py " - "call before the install or bdist_wheel command.", -) - no_clean: Callable[..., Option] = partial( Option, "--no-clean", diff --git a/src/pip/_internal/cli/req_command.py b/src/pip/_internal/cli/req_command.py index dc1328ff019..5a7e28aa3a1 100644 --- a/src/pip/_internal/cli/req_command.py +++ b/src/pip/_internal/cli/req_command.py @@ -163,7 +163,6 @@ def make_resolver( ignore_requires_python: bool = False, force_reinstall: bool = False, upgrade_strategy: str = "to-satisfy-only", - use_pep517: bool | None = None, py_version_info: tuple[int, ...] | None = None, ) -> BaseResolver: """ @@ -172,7 +171,6 @@ def make_resolver( make_install_req = partial( install_req_from_req_string, isolated=options.isolated_mode, - use_pep517=use_pep517, ) resolver_variant = cls.determine_resolver_variant(options) # The long import name and duplicated invocation is needed to convince @@ -241,7 +239,6 @@ def get_requirements( req, comes_from=None, isolated=options.isolated_mode, - use_pep517=options.use_pep517, user_supplied=True, config_settings=getattr(options, "config_settings", None), ) @@ -252,7 +249,6 @@ def get_requirements( req_to_add = install_req_from_req_string( req, isolated=options.isolated_mode, - use_pep517=options.use_pep517, user_supplied=True, ) requirements.append(req_to_add) @@ -262,7 +258,6 @@ def get_requirements( req, user_supplied=True, isolated=options.isolated_mode, - use_pep517=options.use_pep517, config_settings=getattr(options, "config_settings", None), ) requirements.append(req_to_add) @@ -275,7 +270,6 @@ def get_requirements( req_to_add = install_req_from_parsed_requirement( parsed_req, isolated=options.isolated_mode, - use_pep517=options.use_pep517, user_supplied=True, config_settings=( parsed_req.options.get("config_settings") diff --git a/src/pip/_internal/commands/download.py b/src/pip/_internal/commands/download.py index 900fb403d6f..6ab6b2017f9 100644 --- a/src/pip/_internal/commands/download.py +++ b/src/pip/_internal/commands/download.py @@ -7,7 +7,6 @@ from pip._internal.cli.req_command import RequirementCommand, with_cleanup from pip._internal.cli.status_codes import SUCCESS from pip._internal.operations.build.build_tracker import get_build_tracker -from pip._internal.req.req_install import check_legacy_setup_py_options from pip._internal.utils.misc import ensure_dir, normalize_path, write_output from pip._internal.utils.temp_dir import TempDirectory @@ -38,7 +37,6 @@ def add_options(self) -> None: self.cmd_opts.add_option(cmdoptions.constraints()) self.cmd_opts.add_option(cmdoptions.requirements()) self.cmd_opts.add_option(cmdoptions.no_deps()) - self.cmd_opts.add_option(cmdoptions.global_options()) self.cmd_opts.add_option(cmdoptions.no_binary()) self.cmd_opts.add_option(cmdoptions.only_binary()) self.cmd_opts.add_option(cmdoptions.prefer_binary()) @@ -48,7 +46,6 @@ def add_options(self) -> None: self.cmd_opts.add_option(cmdoptions.progress_bar()) self.cmd_opts.add_option(cmdoptions.no_build_isolation()) self.cmd_opts.add_option(cmdoptions.use_pep517()) - self.cmd_opts.add_option(cmdoptions.no_use_pep517()) self.cmd_opts.add_option(cmdoptions.check_build_deps()) self.cmd_opts.add_option(cmdoptions.ignore_requires_python()) @@ -104,7 +101,6 @@ def run(self, options: Values, args: list[str]) -> int: ) reqs = self.get_requirements(args, options, finder, session) - check_legacy_setup_py_options(options, reqs) preparer = self.make_requirement_preparer( temp_build_dir=directory, @@ -122,7 +118,6 @@ def run(self, options: Values, args: list[str]) -> int: finder=finder, options=options, ignore_requires_python=options.ignore_requires_python, - use_pep517=options.use_pep517, py_version_info=options.python_version, ) diff --git a/src/pip/_internal/commands/install.py b/src/pip/_internal/commands/install.py index 1ef7a0f4410..d9e67637c52 100644 --- a/src/pip/_internal/commands/install.py +++ b/src/pip/_internal/commands/install.py @@ -41,7 +41,6 @@ from pip._internal.req import install_given_reqs from pip._internal.req.req_install import ( InstallRequirement, - check_legacy_setup_py_options, ) from pip._internal.utils.compat import WINDOWS from pip._internal.utils.filesystem import test_writable_dir @@ -59,7 +58,7 @@ running_under_virtualenv, virtualenv_no_global, ) -from pip._internal.wheel_builder import build, should_build_for_install_command +from pip._internal.wheel_builder import build logger = getLogger(__name__) @@ -210,12 +209,10 @@ def add_options(self) -> None: self.cmd_opts.add_option(cmdoptions.ignore_requires_python()) self.cmd_opts.add_option(cmdoptions.no_build_isolation()) self.cmd_opts.add_option(cmdoptions.use_pep517()) - self.cmd_opts.add_option(cmdoptions.no_use_pep517()) self.cmd_opts.add_option(cmdoptions.check_build_deps()) self.cmd_opts.add_option(cmdoptions.override_externally_managed()) self.cmd_opts.add_option(cmdoptions.config_settings()) - self.cmd_opts.add_option(cmdoptions.global_options()) self.cmd_opts.add_option( "--compile", @@ -334,8 +331,6 @@ def run(self, options: Values, args: list[str]) -> int: target_temp_dir_path = target_temp_dir.path self.enter_context(target_temp_dir) - global_options = options.global_options or [] - session = self.get_default_session(options) target_python = make_target_python(options) @@ -355,7 +350,6 @@ def run(self, options: Values, args: list[str]) -> int: try: reqs = self.get_requirements(args, options, finder, session) - check_legacy_setup_py_options(options, reqs) wheel_cache = WheelCache(options.cache_dir) @@ -384,7 +378,6 @@ def run(self, options: Values, args: list[str]) -> int: ignore_requires_python=options.ignore_requires_python, force_reinstall=options.force_reinstall, upgrade_strategy=upgrade_strategy, - use_pep517=options.use_pep517, py_version_info=options.python_version, ) @@ -425,17 +418,13 @@ def run(self, options: Values, args: list[str]) -> int: protect_pip_from_modification_on_windows(modifying_pip=modifying_pip) reqs_to_build = [ - r - for r in requirement_set.requirements_to_install - if should_build_for_install_command(r) + r for r in requirement_set.requirements_to_install if not r.is_wheel ] _, build_failures = build( reqs_to_build, wheel_cache=wheel_cache, verify=True, - build_options=[], - global_options=global_options, ) if build_failures: @@ -459,7 +448,6 @@ def run(self, options: Values, args: list[str]) -> int: installed = install_given_reqs( to_install, - global_options, root=options.root_path, home=target_temp_dir_path, prefix=options.prefix_path, diff --git a/src/pip/_internal/commands/lock.py b/src/pip/_internal/commands/lock.py index e4a978d5aaa..cd825ec19ce 100644 --- a/src/pip/_internal/commands/lock.py +++ b/src/pip/_internal/commands/lock.py @@ -11,9 +11,6 @@ from pip._internal.cli.status_codes import SUCCESS from pip._internal.models.pylock import Pylock, is_valid_pylock_file_name from pip._internal.operations.build.build_tracker import get_build_tracker -from pip._internal.req.req_install import ( - check_legacy_setup_py_options, -) from pip._internal.utils.logging import getLogger from pip._internal.utils.misc import ( get_pip_version, @@ -69,7 +66,6 @@ def add_options(self) -> None: self.cmd_opts.add_option(cmdoptions.ignore_requires_python()) self.cmd_opts.add_option(cmdoptions.no_build_isolation()) self.cmd_opts.add_option(cmdoptions.use_pep517()) - self.cmd_opts.add_option(cmdoptions.no_use_pep517()) self.cmd_opts.add_option(cmdoptions.check_build_deps()) self.cmd_opts.add_option(cmdoptions.config_settings()) @@ -114,7 +110,6 @@ def run(self, options: Values, args: list[str]) -> int: ) reqs = self.get_requirements(args, options, finder, session) - check_legacy_setup_py_options(options, reqs) wheel_cache = WheelCache(options.cache_dir) @@ -142,7 +137,6 @@ def run(self, options: Values, args: list[str]) -> int: ignore_installed=True, ignore_requires_python=options.ignore_requires_python, upgrade_strategy="to-satisfy-only", - use_pep517=options.use_pep517, ) self.trace_basic_info(finder) diff --git a/src/pip/_internal/commands/wheel.py b/src/pip/_internal/commands/wheel.py index 61be254912f..98d3da7f416 100644 --- a/src/pip/_internal/commands/wheel.py +++ b/src/pip/_internal/commands/wheel.py @@ -11,7 +11,6 @@ from pip._internal.operations.build.build_tracker import get_build_tracker from pip._internal.req.req_install import ( InstallRequirement, - check_legacy_setup_py_options, ) from pip._internal.utils.misc import ensure_dir, normalize_path from pip._internal.utils.temp_dir import TempDirectory @@ -57,7 +56,6 @@ def add_options(self) -> None: self.cmd_opts.add_option(cmdoptions.prefer_binary()) self.cmd_opts.add_option(cmdoptions.no_build_isolation()) self.cmd_opts.add_option(cmdoptions.use_pep517()) - self.cmd_opts.add_option(cmdoptions.no_use_pep517()) self.cmd_opts.add_option(cmdoptions.check_build_deps()) self.cmd_opts.add_option(cmdoptions.constraints()) self.cmd_opts.add_option(cmdoptions.editable()) @@ -76,8 +74,6 @@ def add_options(self) -> None: ) self.cmd_opts.add_option(cmdoptions.config_settings()) - self.cmd_opts.add_option(cmdoptions.build_options()) - self.cmd_opts.add_option(cmdoptions.global_options()) self.cmd_opts.add_option( "--pre", @@ -117,7 +113,6 @@ def run(self, options: Values, args: list[str]) -> int: ) reqs = self.get_requirements(args, options, finder, session) - check_legacy_setup_py_options(options, reqs) wheel_cache = WheelCache(options.cache_dir) @@ -138,7 +133,6 @@ def run(self, options: Values, args: list[str]) -> int: options=options, wheel_cache=wheel_cache, ignore_requires_python=options.ignore_requires_python, - use_pep517=options.use_pep517, ) self.trace_basic_info(finder) @@ -159,8 +153,6 @@ def run(self, options: Values, args: list[str]) -> int: reqs_to_build, wheel_cache=wheel_cache, verify=(not options.no_verify), - build_options=options.build_options or [], - global_options=options.global_options or [], ) for req in build_successes: assert req.link and req.link.is_wheel diff --git a/src/pip/_internal/distributions/sdist.py b/src/pip/_internal/distributions/sdist.py index e2821f89e00..f7bd7836d0e 100644 --- a/src/pip/_internal/distributions/sdist.py +++ b/src/pip/_internal/distributions/sdist.py @@ -20,7 +20,7 @@ class SourceDistribution(AbstractDistribution): """Represents a source distribution. The preparation step for these needs metadata for the packages to be - generated, either using PEP 517 or using the legacy `setup.py egg_info`. + generated. """ @property @@ -38,28 +38,27 @@ def prepare_distribution_metadata( build_isolation: bool, check_build_deps: bool, ) -> None: - # Load pyproject.toml, to determine whether PEP 517 is to be used + # Load pyproject.toml self.req.load_pyproject_toml() # Set up the build isolation, if this requirement should be isolated - should_isolate = self.req.use_pep517 and build_isolation - if should_isolate: + if build_isolation: # Setup an isolated environment and install the build backend static # requirements in it. self._prepare_build_backend(build_env_installer) - # Check that if the requirement is editable, it either supports PEP 660 or - # has a setup.py or a setup.cfg. This cannot be done earlier because we need - # to setup the build backend to verify it supports build_editable, nor can - # it be done later, because we want to avoid installing build requirements - # needlessly. Doing it here also works around setuptools generating - # UNKNOWN.egg-info when running get_requires_for_build_wheel on a directory - # without setup.py nor setup.cfg. - self.req.isolated_editable_sanity_check() + # Check that the build backend supports PEP 660. This cannot be done + # earlier because we need to setup the build backend to verify it + # supports build_editable, nor can it be done later, because we want + # to avoid installing build requirements needlessly. + self.req.editable_sanity_check() # Install the dynamic build requirements. self._install_build_reqs(build_env_installer) + else: + # When not using build isolation, we still need to check that + # the build backend supports PEP 660. + self.req.editable_sanity_check() # Check if the current environment provides build dependencies - should_check_deps = self.req.use_pep517 and check_build_deps - if should_check_deps: + if check_build_deps: pyproject_requires = self.req.pyproject_requires assert pyproject_requires is not None conflicting, missing = self.req.build_env.check_requirements( diff --git a/src/pip/_internal/operations/build/metadata_legacy.py b/src/pip/_internal/operations/build/metadata_legacy.py deleted file mode 100644 index e385b5ddf76..00000000000 --- a/src/pip/_internal/operations/build/metadata_legacy.py +++ /dev/null @@ -1,73 +0,0 @@ -"""Metadata generation logic for legacy source distributions.""" - -import logging -import os - -from pip._internal.build_env import BuildEnvironment -from pip._internal.cli.spinners import open_spinner -from pip._internal.exceptions import ( - InstallationError, - InstallationSubprocessError, - MetadataGenerationFailed, -) -from pip._internal.utils.setuptools_build import make_setuptools_egg_info_args -from pip._internal.utils.subprocess import call_subprocess -from pip._internal.utils.temp_dir import TempDirectory - -logger = logging.getLogger(__name__) - - -def _find_egg_info(directory: str) -> str: - """Find an .egg-info subdirectory in `directory`.""" - filenames = [f for f in os.listdir(directory) if f.endswith(".egg-info")] - - if not filenames: - raise InstallationError(f"No .egg-info directory found in {directory}") - - if len(filenames) > 1: - raise InstallationError( - f"More than one .egg-info directory found in {directory}" - ) - - return os.path.join(directory, filenames[0]) - - -def generate_metadata( - build_env: BuildEnvironment, - setup_py_path: str, - source_dir: str, - isolated: bool, - details: str, -) -> str: - """Generate metadata using setup.py-based defacto mechanisms. - - Returns the generated metadata directory. - """ - logger.debug( - "Running setup.py (path:%s) egg_info for package %s", - setup_py_path, - details, - ) - - egg_info_dir = TempDirectory(kind="pip-egg-info", globally_managed=True).path - - args = make_setuptools_egg_info_args( - setup_py_path, - egg_info_dir=egg_info_dir, - no_user_config=isolated, - ) - - with build_env: - with open_spinner("Preparing metadata (setup.py)") as spinner: - try: - call_subprocess( - args, - cwd=source_dir, - command_desc="python setup.py egg_info", - spinner=spinner, - ) - except InstallationSubprocessError as error: - raise MetadataGenerationFailed(package_details=details) from error - - # Return the .egg-info directory. - return _find_egg_info(egg_info_dir) diff --git a/src/pip/_internal/operations/build/wheel_legacy.py b/src/pip/_internal/operations/build/wheel_legacy.py deleted file mode 100644 index 02ef8e57075..00000000000 --- a/src/pip/_internal/operations/build/wheel_legacy.py +++ /dev/null @@ -1,119 +0,0 @@ -from __future__ import annotations - -import logging -import os.path - -from pip._internal.cli.spinners import open_spinner -from pip._internal.utils.deprecation import deprecated -from pip._internal.utils.setuptools_build import make_setuptools_bdist_wheel_args -from pip._internal.utils.subprocess import call_subprocess, format_command_args - -logger = logging.getLogger(__name__) - - -def format_command_result( - command_args: list[str], - command_output: str, -) -> str: - """Format command information for logging.""" - command_desc = format_command_args(command_args) - text = f"Command arguments: {command_desc}\n" - - if not command_output: - text += "Command output: None" - elif logger.getEffectiveLevel() > logging.DEBUG: - text += "Command output: [use --verbose to show]" - else: - if not command_output.endswith("\n"): - command_output += "\n" - text += f"Command output:\n{command_output}" - - return text - - -def get_legacy_build_wheel_path( - names: list[str], - temp_dir: str, - name: str, - command_args: list[str], - command_output: str, -) -> str | None: - """Return the path to the wheel in the temporary build directory.""" - # Sort for determinism. - names = sorted(names) - if not names: - msg = f"Legacy build of wheel for {name!r} created no files.\n" - msg += format_command_result(command_args, command_output) - logger.warning(msg) - return None - - if len(names) > 1: - msg = ( - f"Legacy build of wheel for {name!r} created more than one file.\n" - f"Filenames (choosing first): {names}\n" - ) - msg += format_command_result(command_args, command_output) - logger.warning(msg) - - return os.path.join(temp_dir, names[0]) - - -def build_wheel_legacy( - name: str, - setup_py_path: str, - source_dir: str, - global_options: list[str], - build_options: list[str], - tempd: str, -) -> str | None: - """Build one unpacked package using the "legacy" build process. - - Returns path to wheel if successfully built. Otherwise, returns None. - """ - deprecated( - reason=( - f"Building {name!r} using the legacy setup.py bdist_wheel mechanism, " - "which will be removed in a future version." - ), - replacement=( - "to use the standardized build interface by " - "setting the `--use-pep517` option, " - "(possibly combined with `--no-build-isolation`), " - f"or adding a `pyproject.toml` file to the source tree of {name!r}" - ), - gone_in="25.3", - issue=6334, - ) - - wheel_args = make_setuptools_bdist_wheel_args( - setup_py_path, - global_options=global_options, - build_options=build_options, - destination_dir=tempd, - ) - - spin_message = f"Building wheel for {name} (setup.py)" - with open_spinner(spin_message) as spinner: - logger.debug("Destination directory: %s", tempd) - - try: - output = call_subprocess( - wheel_args, - command_desc="python setup.py bdist_wheel", - cwd=source_dir, - spinner=spinner, - ) - except Exception: - spinner.finish("error") - logger.error("Failed building wheel for %s", name) - return None - - names = os.listdir(tempd) - wheel_path = get_legacy_build_wheel_path( - names=names, - temp_dir=tempd, - name=name, - command_args=wheel_args, - command_output=output, - ) - return wheel_path diff --git a/src/pip/_internal/operations/install/editable_legacy.py b/src/pip/_internal/operations/install/editable_legacy.py deleted file mode 100644 index 0603d3d8819..00000000000 --- a/src/pip/_internal/operations/install/editable_legacy.py +++ /dev/null @@ -1,48 +0,0 @@ -"""Legacy editable installation process, i.e. `setup.py develop`.""" - -from __future__ import annotations - -import logging -from collections.abc import Sequence - -from pip._internal.build_env import BuildEnvironment -from pip._internal.utils.logging import indent_log -from pip._internal.utils.setuptools_build import make_setuptools_develop_args -from pip._internal.utils.subprocess import call_subprocess - -logger = logging.getLogger(__name__) - - -def install_editable( - *, - global_options: Sequence[str], - prefix: str | None, - home: str | None, - use_user_site: bool, - name: str, - setup_py_path: str, - isolated: bool, - build_env: BuildEnvironment, - unpacked_source_directory: str, -) -> None: - """Install a package in editable mode. Most arguments are pass-through - to setuptools. - """ - logger.info("Running setup.py develop for %s", name) - - args = make_setuptools_develop_args( - setup_py_path, - global_options=global_options, - no_user_config=isolated, - prefix=prefix, - home=home, - use_user_site=use_user_site, - ) - - with indent_log(): - with build_env: - call_subprocess( - args, - command_desc="python setup.py develop", - cwd=unpacked_source_directory, - ) diff --git a/src/pip/_internal/pyproject.py b/src/pip/_internal/pyproject.py index 5c08b60e5b5..8c2f7221c93 100644 --- a/src/pip/_internal/pyproject.py +++ b/src/pip/_internal/pyproject.py @@ -1,6 +1,5 @@ from __future__ import annotations -import importlib.util import os from collections import namedtuple from typing import Any @@ -30,13 +29,11 @@ def make_pyproject_path(unpacked_source_directory: str) -> str: def load_pyproject_toml( - use_pep517: bool | None, pyproject_toml: str, setup_py: str, req_name: str -) -> BuildSystemDetails | None: + pyproject_toml: str, setup_py: str, req_name: str +) -> BuildSystemDetails: """Load the pyproject.toml file. Parameters: - use_pep517 - Has the user requested PEP 517 processing? None - means the user hasn't explicitly specified. pyproject_toml - Location of the project's pyproject.toml file setup_py - Location of the project's setup.py file req_name - The name of the requirement we're processing (for @@ -69,57 +66,7 @@ def load_pyproject_toml( else: build_system = None - # The following cases must use PEP 517 - # We check for use_pep517 being non-None and falsy because that means - # the user explicitly requested --no-use-pep517. The value 0 as - # opposed to False can occur when the value is provided via an - # environment variable or config file option (due to the quirk of - # strtobool() returning an integer in pip's configuration code). - if has_pyproject and not has_setup: - if use_pep517 is not None and not use_pep517: - raise InstallationError( - "Disabling PEP 517 processing is invalid: " - "project does not have a setup.py" - ) - use_pep517 = True - elif build_system and "build-backend" in build_system: - if use_pep517 is not None and not use_pep517: - raise InstallationError( - "Disabling PEP 517 processing is invalid: " - "project specifies a build backend of {} " - "in pyproject.toml".format(build_system["build-backend"]) - ) - use_pep517 = True - - # If we haven't worked out whether to use PEP 517 yet, - # and the user hasn't explicitly stated a preference, - # we do so if the project has a pyproject.toml file - # or if we cannot import setuptools or wheels. - - # We fallback to PEP 517 when without setuptools or without the wheel package, - # so setuptools can be installed as a default build backend. - # For more info see: - # https://discuss.python.org/t/pip-without-setuptools-could-the-experience-be-improved/11810/9 - # https://github.com/pypa/pip/issues/8559 - elif use_pep517 is None: - use_pep517 = ( - has_pyproject - or not importlib.util.find_spec("setuptools") - or not importlib.util.find_spec("wheel") - ) - - # At this point, we know whether we're going to use PEP 517. - assert use_pep517 is not None - - # If we're using the legacy code path, there is nothing further - # for us to do here. - if not use_pep517: - return None - if build_system is None: - # Either the user has a pyproject.toml with no build-system - # section, or the user has no pyproject.toml, but has opted in - # explicitly via --use-pep517. # In the absence of any explicit backend specification, we # assume the setuptools backend that most closely emulates the # traditional direct setup.py execution, and require wheel and @@ -130,12 +77,6 @@ def load_pyproject_toml( "build-backend": "setuptools.build_meta:__legacy__", } - # If we're using PEP 517, we have build system information (either - # from pyproject.toml, or defaulted by the code above). - # Note that at this point, we do not know if the user has actually - # specified a backend, though. - assert build_system is not None - # Ensure that the build-system section in pyproject.toml conforms # to PEP 518. diff --git a/src/pip/_internal/req/__init__.py b/src/pip/_internal/req/__init__.py index e5050ee588b..5fc8752d8e4 100644 --- a/src/pip/_internal/req/__init__.py +++ b/src/pip/_internal/req/__init__.py @@ -2,7 +2,7 @@ import collections import logging -from collections.abc import Generator, Sequence +from collections.abc import Generator from dataclasses import dataclass from pip._internal.cli.progress_bars import BarType, get_install_progress_renderer @@ -37,7 +37,6 @@ def _validate_requirements( def install_given_reqs( requirements: list[InstallRequirement], - global_options: Sequence[str], root: str | None, home: str | None, prefix: str | None, @@ -83,7 +82,6 @@ def install_given_reqs( try: requirement.install( - global_options, root=root, home=home, prefix=prefix, diff --git a/src/pip/_internal/req/constructors.py b/src/pip/_internal/req/constructors.py index 76c8c38499a..f8531e113a3 100644 --- a/src/pip/_internal/req/constructors.py +++ b/src/pip/_internal/req/constructors.py @@ -225,9 +225,7 @@ def install_req_from_editable( editable_req: str, comes_from: InstallRequirement | str | None = None, *, - use_pep517: bool | None = None, isolated: bool = False, - global_options: list[str] | None = None, hash_options: dict[str, list[str]] | None = None, constraint: bool = False, user_supplied: bool = False, @@ -244,9 +242,7 @@ def install_req_from_editable( permit_editable_wheels=permit_editable_wheels, link=parts.link, constraint=constraint, - use_pep517=use_pep517, isolated=isolated, - global_options=global_options, hash_options=hash_options, config_settings=config_settings, extras=parts.extras, @@ -389,9 +385,7 @@ def install_req_from_line( name: str, comes_from: str | InstallRequirement | None = None, *, - use_pep517: bool | None = None, isolated: bool = False, - global_options: list[str] | None = None, hash_options: dict[str, list[str]] | None = None, constraint: bool = False, line_source: str | None = None, @@ -411,9 +405,7 @@ def install_req_from_line( comes_from, link=parts.link, markers=parts.markers, - use_pep517=use_pep517, isolated=isolated, - global_options=global_options, hash_options=hash_options, config_settings=config_settings, constraint=constraint, @@ -426,7 +418,6 @@ def install_req_from_req_string( req_string: str, comes_from: InstallRequirement | None = None, isolated: bool = False, - use_pep517: bool | None = None, user_supplied: bool = False, ) -> InstallRequirement: try: @@ -455,7 +446,6 @@ def install_req_from_req_string( req, comes_from, isolated=isolated, - use_pep517=use_pep517, user_supplied=user_supplied, ) @@ -463,7 +453,6 @@ def install_req_from_req_string( def install_req_from_parsed_requirement( parsed_req: ParsedRequirement, isolated: bool = False, - use_pep517: bool | None = None, user_supplied: bool = False, config_settings: dict[str, str | list[str]] | None = None, ) -> InstallRequirement: @@ -471,7 +460,6 @@ def install_req_from_parsed_requirement( req = install_req_from_editable( parsed_req.requirement, comes_from=parsed_req.comes_from, - use_pep517=use_pep517, constraint=parsed_req.constraint, isolated=isolated, user_supplied=user_supplied, @@ -482,13 +470,7 @@ def install_req_from_parsed_requirement( req = install_req_from_line( parsed_req.requirement, comes_from=parsed_req.comes_from, - use_pep517=use_pep517, isolated=isolated, - global_options=( - parsed_req.options.get("global_options", []) - if parsed_req.options - else [] - ), hash_options=( parsed_req.options.get("hashes", {}) if parsed_req.options else {} ), @@ -509,9 +491,7 @@ def install_req_from_link_and_ireq( editable=ireq.editable, link=link, markers=ireq.markers, - use_pep517=ireq.use_pep517, isolated=ireq.isolated, - global_options=ireq.global_options, hash_options=ireq.hash_options, config_settings=ireq.config_settings, user_supplied=ireq.user_supplied, @@ -532,9 +512,7 @@ def install_req_drop_extras(ireq: InstallRequirement) -> InstallRequirement: editable=ireq.editable, link=ireq.link, markers=ireq.markers, - use_pep517=ireq.use_pep517, isolated=ireq.isolated, - global_options=ireq.global_options, hash_options=ireq.hash_options, constraint=ireq.constraint, extras=[], diff --git a/src/pip/_internal/req/req_file.py b/src/pip/_internal/req/req_file.py index 0aad0a36602..a4f54b438f2 100644 --- a/src/pip/_internal/req/req_file.py +++ b/src/pip/_internal/req/req_file.py @@ -65,7 +65,6 @@ # options to be passed to requirements SUPPORTED_OPTIONS_REQ: list[Callable[..., optparse.Option]] = [ - cmdoptions.global_options, cmdoptions.hash, cmdoptions.config_settings, ] diff --git a/src/pip/_internal/req/req_install.py b/src/pip/_internal/req/req_install.py index c9f6bff17e8..195f13e3851 100644 --- a/src/pip/_internal/req/req_install.py +++ b/src/pip/_internal/req/req_install.py @@ -7,7 +7,7 @@ import sys import uuid import zipfile -from collections.abc import Collection, Iterable, Sequence +from collections.abc import Collection, Iterable from optparse import Values from pathlib import Path from typing import Any @@ -34,12 +34,6 @@ from pip._internal.models.link import Link from pip._internal.operations.build.metadata import generate_metadata from pip._internal.operations.build.metadata_editable import generate_editable_metadata -from pip._internal.operations.build.metadata_legacy import ( - generate_metadata as generate_metadata_legacy, -) -from pip._internal.operations.install.editable_legacy import ( - install_editable as install_editable_legacy, -) from pip._internal.operations.install.wheel import install_wheel from pip._internal.pyproject import load_pyproject_toml, make_pyproject_path from pip._internal.req.req_uninstall import UninstallPathSet @@ -79,10 +73,8 @@ def __init__( editable: bool = False, link: Link | None = None, markers: Marker | None = None, - use_pep517: bool | None = None, isolated: bool = False, *, - global_options: list[str] | None = None, hash_options: dict[str, list[str]] | None = None, config_settings: dict[str, str | list[str]] | None = None, constraint: bool = False, @@ -149,7 +141,6 @@ def __init__( # Set to True after successful installation self.install_succeeded: bool | None = None # Supplied options - self.global_options = global_options if global_options else [] self.hash_options = hash_options if hash_options else {} self.config_settings = config_settings # Set to True after successful preparation of this requirement @@ -177,23 +168,6 @@ def __init__( # The PEP 517 backend we should use to build the project self.pep517_backend: BuildBackendHookCaller | None = None - # Are we using PEP 517 for this requirement? - # After pyproject.toml has been loaded, the only valid values are True - # and False. Before loading, None is valid (meaning "use the default"). - # Setting an explicit value before loading pyproject.toml is supported, - # but after loading this flag should be treated as read only. - self.use_pep517 = use_pep517 - - # If config settings are provided, enforce PEP 517. - if self.config_settings: - if self.use_pep517 is False: - logger.warning( - "--no-use-pep517 ignored for %s " - "because --config-settings are specified.", - self, - ) - self.use_pep517 = True - # This requirement needs more preparation before it can be built self.needs_more_preparation = False @@ -250,8 +224,6 @@ def name(self) -> str | None: @functools.cached_property def supports_pyproject_editable(self) -> bool: - if not self.use_pep517: - return False assert self.pep517_backend with self.build_env: runner = runner_with_spinner_message( @@ -492,13 +464,6 @@ def setup_py_path(self) -> str: return setup_py - @property - def setup_cfg_path(self) -> str: - assert self.source_dir, f"No source dir for {self}" - setup_cfg = os.path.join(self.unpacked_source_directory, "setup.cfg") - - return setup_cfg - @property def pyproject_toml_path(self) -> str: assert self.source_dir, f"No source dir for {self}" @@ -508,20 +473,12 @@ def load_pyproject_toml(self) -> None: """Load the pyproject.toml file. After calling this routine, all of the attributes related to PEP 517 - processing for this requirement have been set. In particular, the - use_pep517 attribute can be used to determine whether we should - follow the PEP 517 or legacy (setup.py) code path. + processing for this requirement have been set. """ pyproject_toml_data = load_pyproject_toml( - self.use_pep517, self.pyproject_toml_path, self.setup_py_path, str(self) + self.pyproject_toml_path, self.setup_py_path, str(self) ) - - if pyproject_toml_data is None: - assert not self.config_settings - self.use_pep517 = False - return - - self.use_pep517 = True + assert pyproject_toml_data requires, backend, check, backend_path = pyproject_toml_data self.requirements_to_check = check self.pyproject_requires = requires @@ -532,23 +489,15 @@ def load_pyproject_toml(self) -> None: backend_path=backend_path, ) - def isolated_editable_sanity_check(self) -> None: + def editable_sanity_check(self) -> None: """Check that an editable requirement if valid for use with PEP 517/518. - This verifies that an editable that has a pyproject.toml either supports PEP 660 - or as a setup.py or a setup.cfg + This verifies that an editable has a build backend that supports PEP 660. """ - if ( - self.editable - and self.use_pep517 - and not self.supports_pyproject_editable - and not os.path.isfile(self.setup_py_path) - and not os.path.isfile(self.setup_cfg_path) - ): + if self.editable and not self.supports_pyproject_editable: raise InstallationError( - f"Project {self} has a 'pyproject.toml' and its build " - f"backend is missing the 'build_editable' hook. Since it does not " - f"have a 'setup.py' nor a 'setup.cfg', " + f"Project {self} uses a build backend " + f"that is missing the 'build_editable' hook, so " f"it cannot be installed in editable mode. " f"Consider using a build backend that supports PEP 660." ) @@ -562,30 +511,21 @@ def prepare_metadata(self) -> None: assert self.source_dir, f"No source dir for {self}" details = self.name or f"from {self.link}" - if self.use_pep517: - assert self.pep517_backend is not None - if ( - self.editable - and self.permit_editable_wheels - and self.supports_pyproject_editable - ): - self.metadata_directory = generate_editable_metadata( - build_env=self.build_env, - backend=self.pep517_backend, - details=details, - ) - else: - self.metadata_directory = generate_metadata( - build_env=self.build_env, - backend=self.pep517_backend, - details=details, - ) + assert self.pep517_backend is not None + if ( + self.editable + and self.permit_editable_wheels + and self.supports_pyproject_editable + ): + self.metadata_directory = generate_editable_metadata( + build_env=self.build_env, + backend=self.pep517_backend, + details=details, + ) else: - self.metadata_directory = generate_metadata_legacy( + self.metadata_directory = generate_metadata( build_env=self.build_env, - setup_py_path=self.setup_py_path, - source_dir=self.unpacked_source_directory, - isolated=self.isolated, + backend=self.pep517_backend, details=details, ) @@ -809,7 +749,6 @@ def archive(self, build_dir: str | None) -> None: def install( self, - global_options: Sequence[str] | None = None, root: str | None = None, home: str | None = None, prefix: str | None = None, @@ -827,43 +766,6 @@ def install( prefix=prefix, ) - if self.editable and not self.is_wheel: - deprecated( - reason=( - f"Legacy editable install of {self} (setup.py develop) " - "is deprecated." - ), - replacement=( - "to add a pyproject.toml or enable --use-pep517, " - "and use setuptools >= 64. " - "If the resulting installation is not behaving as expected, " - "try using --config-settings editable_mode=compat. " - "Please consult the setuptools documentation for more information" - ), - gone_in="25.3", - issue=11457, - ) - if self.config_settings: - logger.warning( - "--config-settings ignored for legacy editable install of %s. " - "Consider upgrading to a version of setuptools " - "that supports PEP 660 (>= 64).", - self, - ) - install_editable_legacy( - global_options=global_options if global_options is not None else [], - prefix=prefix, - home=home, - use_user_site=use_user_site, - name=self.req.name, - setup_py_path=self.setup_py_path, - isolated=self.isolated, - build_env=self.build_env, - unpacked_source_directory=self.unpacked_source_directory, - ) - self.install_succeeded = True - return - assert self.is_wheel assert self.local_file_path @@ -915,23 +817,3 @@ def _has_option(options: Values, reqs: list[InstallRequirement], option: str) -> if getattr(req, option, None): return True return False - - -def check_legacy_setup_py_options( - options: Values, - reqs: list[InstallRequirement], -) -> None: - has_build_options = _has_option(options, reqs, "build_options") - has_global_options = _has_option(options, reqs, "global_options") - if has_build_options or has_global_options: - deprecated( - reason="--build-option and --global-option are deprecated.", - issue=11859, - replacement="to use --config-settings", - gone_in="25.3", - ) - logger.warning( - "Implying --no-binary=:all: due to the presence of " - "--build-option / --global-option. " - ) - options.format_control.disallow_binaries() diff --git a/src/pip/_internal/resolution/resolvelib/candidates.py b/src/pip/_internal/resolution/resolvelib/candidates.py index 5a4ab8154d9..108942768f9 100644 --- a/src/pip/_internal/resolution/resolvelib/candidates.py +++ b/src/pip/_internal/resolution/resolvelib/candidates.py @@ -69,10 +69,8 @@ def make_install_req_from_link( line, user_supplied=template.user_supplied, comes_from=template.comes_from, - use_pep517=template.use_pep517, isolated=template.isolated, constraint=template.constraint, - global_options=template.global_options, hash_options=template.hash_options, config_settings=template.config_settings, ) @@ -90,11 +88,9 @@ def make_install_req_from_editable( link.url, user_supplied=template.user_supplied, comes_from=template.comes_from, - use_pep517=template.use_pep517, isolated=template.isolated, constraint=template.constraint, permit_editable_wheels=template.permit_editable_wheels, - global_options=template.global_options, hash_options=template.hash_options, config_settings=template.config_settings, ) @@ -115,10 +111,8 @@ def _make_install_req_from_dist( line, user_supplied=template.user_supplied, comes_from=template.comes_from, - use_pep517=template.use_pep517, isolated=template.isolated, constraint=template.constraint, - global_options=template.global_options, hash_options=template.hash_options, config_settings=template.config_settings, ) diff --git a/src/pip/_internal/utils/setuptools_build.py b/src/pip/_internal/utils/setuptools_build.py deleted file mode 100644 index 1b8c7a1c21f..00000000000 --- a/src/pip/_internal/utils/setuptools_build.py +++ /dev/null @@ -1,149 +0,0 @@ -from __future__ import annotations - -import sys -import textwrap -from collections.abc import Sequence - -# Shim to wrap setup.py invocation with setuptools -# Note that __file__ is handled via two {!r} *and* %r, to ensure that paths on -# Windows are correctly handled (it should be "C:\\Users" not "C:\Users"). -_SETUPTOOLS_SHIM = textwrap.dedent( - """ - exec(compile(''' - # This is -- a caller that pip uses to run setup.py - # - # - It imports setuptools before invoking setup.py, to enable projects that directly - # import from `distutils.core` to work with newer packaging standards. - # - It provides a clear error message when setuptools is not installed. - # - It sets `sys.argv[0]` to the underlying `setup.py`, when invoking `setup.py` so - # setuptools doesn't think the script is `-c`. This avoids the following warning: - # manifest_maker: standard file '-c' not found". - # - It generates a shim setup.py, for handling setup.cfg-only projects. - import os, sys, tokenize, traceback - - try: - import setuptools - except ImportError: - print( - "ERROR: Can not execute `setup.py` since setuptools failed to import in " - "the build environment with exception:", - file=sys.stderr, - ) - traceback.print_exc() - sys.exit(1) - - __file__ = %r - sys.argv[0] = __file__ - - if os.path.exists(__file__): - filename = __file__ - with tokenize.open(__file__) as f: - setup_py_code = f.read() - else: - filename = "" - setup_py_code = "from setuptools import setup; setup()" - - exec(compile(setup_py_code, filename, "exec")) - ''' % ({!r},), "", "exec")) - """ -).rstrip() - - -def make_setuptools_shim_args( - setup_py_path: str, - global_options: Sequence[str] | None = None, - no_user_config: bool = False, - unbuffered_output: bool = False, -) -> list[str]: - """ - Get setuptools command arguments with shim wrapped setup file invocation. - - :param setup_py_path: The path to setup.py to be wrapped. - :param global_options: Additional global options. - :param no_user_config: If True, disables personal user configuration. - :param unbuffered_output: If True, adds the unbuffered switch to the - argument list. - """ - args = [sys.executable] - if unbuffered_output: - args += ["-u"] - args += ["-c", _SETUPTOOLS_SHIM.format(setup_py_path)] - if global_options: - args += global_options - if no_user_config: - args += ["--no-user-cfg"] - return args - - -def make_setuptools_bdist_wheel_args( - setup_py_path: str, - global_options: Sequence[str], - build_options: Sequence[str], - destination_dir: str, -) -> list[str]: - # NOTE: Eventually, we'd want to also -S to the flags here, when we're - # isolating. Currently, it breaks Python in virtualenvs, because it - # relies on site.py to find parts of the standard library outside the - # virtualenv. - args = make_setuptools_shim_args( - setup_py_path, global_options=global_options, unbuffered_output=True - ) - args += ["bdist_wheel", "-d", destination_dir] - args += build_options - return args - - -def make_setuptools_clean_args( - setup_py_path: str, - global_options: Sequence[str], -) -> list[str]: - args = make_setuptools_shim_args( - setup_py_path, global_options=global_options, unbuffered_output=True - ) - args += ["clean", "--all"] - return args - - -def make_setuptools_develop_args( - setup_py_path: str, - *, - global_options: Sequence[str], - no_user_config: bool, - prefix: str | None, - home: str | None, - use_user_site: bool, -) -> list[str]: - assert not (use_user_site and prefix) - - args = make_setuptools_shim_args( - setup_py_path, - global_options=global_options, - no_user_config=no_user_config, - ) - - args += ["develop", "--no-deps"] - - if prefix: - args += ["--prefix", prefix] - if home is not None: - args += ["--install-dir", home] - - if use_user_site: - args += ["--user", "--prefix="] - - return args - - -def make_setuptools_egg_info_args( - setup_py_path: str, - egg_info_dir: str | None, - no_user_config: bool, -) -> list[str]: - args = make_setuptools_shim_args(setup_py_path, no_user_config=no_user_config) - - args += ["egg_info"] - - if egg_info_dir: - args += ["--egg-base", egg_info_dir] - - return args diff --git a/src/pip/_internal/wheel_builder.py b/src/pip/_internal/wheel_builder.py index c5d260700af..3e1b783d71b 100644 --- a/src/pip/_internal/wheel_builder.py +++ b/src/pip/_internal/wheel_builder.py @@ -18,12 +18,9 @@ from pip._internal.models.wheel import Wheel from pip._internal.operations.build.wheel import build_wheel_pep517 from pip._internal.operations.build.wheel_editable import build_wheel_editable -from pip._internal.operations.build.wheel_legacy import build_wheel_legacy from pip._internal.req.req_install import InstallRequirement from pip._internal.utils.logging import indent_log from pip._internal.utils.misc import ensure_dir, hash_file -from pip._internal.utils.setuptools_build import make_setuptools_clean_args -from pip._internal.utils.subprocess import call_subprocess from pip._internal.utils.temp_dir import TempDirectory from pip._internal.utils.urls import path_to_url from pip._internal.vcs import vcs @@ -43,37 +40,12 @@ def _contains_egg_info(s: str) -> bool: return bool(_egg_info_re.search(s)) -def _should_build( - req: InstallRequirement, -) -> bool: - """Return whether an InstallRequirement should be built into a wheel.""" - assert not req.constraint - - if req.is_wheel: - return False - - assert req.source_dir - - if req.editable: - # we only build PEP 660 editable requirements - return req.supports_pyproject_editable - - return True - - -def should_build_for_install_command( - req: InstallRequirement, -) -> bool: - return _should_build(req) - - def _should_cache( req: InstallRequirement, ) -> bool | None: """ Return whether a built InstallRequirement can be stored in the persistent - wheel cache, assuming the wheel cache is available, and _should_build() - has determined a wheel needs to be built. + wheel cache, assuming the wheel cache is available. """ if req.editable or not req.source_dir: # never cache editable requirements @@ -148,8 +120,6 @@ def _build_one( req: InstallRequirement, output_dir: str, verify: bool, - build_options: list[str], - global_options: list[str], editable: bool, ) -> str | None: """Build one wheel. @@ -170,9 +140,7 @@ def _build_one( # Install build deps into temporary directory (PEP 518) with req.build_env: - wheel_path = _build_one_inside_env( - req, output_dir, build_options, global_options, editable - ) + wheel_path = _build_one_inside_env(req, output_dir, editable) if wheel_path and verify: try: _verify_one(req, wheel_path) @@ -185,44 +153,24 @@ def _build_one( def _build_one_inside_env( req: InstallRequirement, output_dir: str, - build_options: list[str], - global_options: list[str], editable: bool, ) -> str | None: with TempDirectory(kind="wheel") as temp_dir: assert req.name - if req.use_pep517: - assert req.metadata_directory - assert req.pep517_backend - if global_options: - logger.warning( - "Ignoring --global-option when building %s using PEP 517", req.name - ) - if build_options: - logger.warning( - "Ignoring --build-option when building %s using PEP 517", req.name - ) - if editable: - wheel_path = build_wheel_editable( - name=req.name, - backend=req.pep517_backend, - metadata_directory=req.metadata_directory, - tempd=temp_dir.path, - ) - else: - wheel_path = build_wheel_pep517( - name=req.name, - backend=req.pep517_backend, - metadata_directory=req.metadata_directory, - tempd=temp_dir.path, - ) + assert req.metadata_directory + assert req.pep517_backend + if editable: + wheel_path = build_wheel_editable( + name=req.name, + backend=req.pep517_backend, + metadata_directory=req.metadata_directory, + tempd=temp_dir.path, + ) else: - wheel_path = build_wheel_legacy( + wheel_path = build_wheel_pep517( name=req.name, - setup_py_path=req.setup_py_path, - source_dir=req.unpacked_source_directory, - global_options=global_options, - build_options=build_options, + backend=req.pep517_backend, + metadata_directory=req.metadata_directory, tempd=temp_dir.path, ) @@ -247,35 +195,13 @@ def _build_one_inside_env( req.name, e, ) - # Ignore return, we can't do anything else useful. - if not req.use_pep517: - _clean_one_legacy(req, global_options) return None -def _clean_one_legacy(req: InstallRequirement, global_options: list[str]) -> bool: - clean_args = make_setuptools_clean_args( - req.setup_py_path, - global_options=global_options, - ) - - logger.info("Running setup.py clean for %s", req.name) - try: - call_subprocess( - clean_args, command_desc="python setup.py clean", cwd=req.source_dir - ) - return True - except Exception: - logger.error("Failed cleaning build dir for %s", req.name) - return False - - def build( requirements: Iterable[InstallRequirement], wheel_cache: WheelCache, verify: bool, - build_options: list[str], - global_options: list[str], ) -> BuildResult: """Build wheels. @@ -300,8 +226,6 @@ def build( req, cache_dir, verify, - build_options, - global_options, req.editable and req.permit_editable_wheels, ) if wheel_file: diff --git a/tests/data/packages/SetupPyUTF8/setup.py b/tests/data/packages/SetupPyUTF8/setup.py index bd9fd2a294b..026d3a215e6 100644 --- a/tests/data/packages/SetupPyUTF8/setup.py +++ b/tests/data/packages/SetupPyUTF8/setup.py @@ -1,4 +1,4 @@ -from distutils.core import setup +from setuptools import setup setup( name="SetupPyUTF8", diff --git a/tests/data/src/chattymodule/backend.py b/tests/data/src/chattymodule/backend.py new file mode 100644 index 00000000000..5993b53f607 --- /dev/null +++ b/tests/data/src/chattymodule/backend.py @@ -0,0 +1,23 @@ +import os +import sys + +from setuptools import build_meta +from setuptools.build_meta import * + + +def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None): + if config_settings and "fail" in config_settings: + print("I DIE, I DIE in prepare_metadata_for_build_wheel") + sys.exit(1) + print("HELLO FROM CHATTYMODULE prepare_metadata_for_build_wheel") + return build_meta.prepare_metadata_for_build_wheel( + metadata_directory, config_settings + ) + + +def build_wheel(wheel_directory, config_settings=None, metadata_directory=None): + if config_settings and "fail" in config_settings: + print("I DIE, I DIE in build_wheel") + sys.exit(1) + print("HELLO FROM CHATTYMODULE build_wheel") + return build_meta.build_wheel(wheel_directory, config_settings, metadata_directory) diff --git a/tests/data/src/chattymodule/pyproject.toml b/tests/data/src/chattymodule/pyproject.toml new file mode 100644 index 00000000000..54de20d46fc --- /dev/null +++ b/tests/data/src/chattymodule/pyproject.toml @@ -0,0 +1,11 @@ +[build-system] +requires = ["setuptools"] +build-backend = "backend" +backend-path = ["."] + +[project] +name = "chattymodule" +version = "0.0.1" + +[tool.setuptools] +py-modules = ["chattymodule"] diff --git a/tests/data/src/chattymodule/setup.cfg b/tests/data/src/chattymodule/setup.cfg deleted file mode 100644 index 79bc67848ff..00000000000 --- a/tests/data/src/chattymodule/setup.cfg +++ /dev/null @@ -1,5 +0,0 @@ -[bdist_wheel] -# This flag says that the code is written to work on both Python 2 and Python -# 3. If at all possible, it is good practice to do this. If you cannot, you -# will need to generate wheels for each Python version that you support. -universal=1 diff --git a/tests/data/src/chattymodule/setup.py b/tests/data/src/chattymodule/setup.py deleted file mode 100644 index 9f411b6fdff..00000000000 --- a/tests/data/src/chattymodule/setup.py +++ /dev/null @@ -1,22 +0,0 @@ -# A chatty setup.py for testing pip subprocess output handling - -import os -import sys - -from setuptools import setup - -print(f"HELLO FROM CHATTYMODULE {sys.argv[1]}") -print(sys.argv) -print(sys.executable) -print(sys.version) - -if "--fail" in sys.argv: - print("I DIE, I DIE") - sys.exit(1) - -setup( - name="chattymodule", - version="0.0.1", - description="A sample Python project with a single module", - py_modules=["chattymodule"], -) diff --git a/tests/functional/test_check.py b/tests/functional/test_check.py index 06ed1b08eac..656d5ac866b 100644 --- a/tests/functional/test_check.py +++ b/tests/functional/test_check.py @@ -34,7 +34,9 @@ def test_basic_check_missing_dependency(script: PipTestEnvironment) -> None: install_requires=["missing==0.1"], ) # Let's install pkga without its dependency - res = script.pip("install", "--no-index", pkga_path, "--no-deps") + res = script.pip( + "install", "--no-build-isolation", "--no-index", pkga_path, "--no-deps" + ) assert "Successfully installed pkga-1.0" in res.stdout, str(res) result = script.pip("check", expect_error=True) @@ -53,7 +55,9 @@ def test_basic_check_broken_dependency(script: PipTestEnvironment) -> None: install_requires=["broken>=1.0"], ) # Let's install pkga without its dependency - res = script.pip("install", "--no-index", pkga_path, "--no-deps") + res = script.pip( + "install", "--no-build-isolation", "--no-index", pkga_path, "--no-deps" + ) assert "Successfully installed pkga-1.0" in res.stdout, str(res) # Setup broken==0.1 @@ -65,6 +69,7 @@ def test_basic_check_broken_dependency(script: PipTestEnvironment) -> None: # Let's install broken==0.1 res = script.pip( "install", + "--no-build-isolation", "--no-index", broken_path, "--no-warn-conflicts", @@ -88,7 +93,9 @@ def test_basic_check_broken_dependency_and_missing_dependency( install_requires=["broken>=1.0"], ) # Let's install pkga without its dependency - res = script.pip("install", "--no-index", pkga_path, "--no-deps") + res = script.pip( + "install", "--no-build-isolation", "--no-index", pkga_path, "--no-deps" + ) assert "Successfully installed pkga-1.0" in res.stdout, str(res) # Setup broken==0.1 @@ -99,7 +106,9 @@ def test_basic_check_broken_dependency_and_missing_dependency( install_requires=["missing"], ) # Let's install broken==0.1 - res = script.pip("install", "--no-index", broken_path, "--no-deps") + res = script.pip( + "install", "--no-build-isolation", "--no-index", broken_path, "--no-deps" + ) assert "Successfully installed broken-0.1" in res.stdout, str(res) result = script.pip("check", expect_error=True) @@ -122,7 +131,9 @@ def test_check_complicated_name_missing(script: PipTestEnvironment) -> None: ) # Without dependency - result = script.pip("install", "--no-index", package_a_path, "--no-deps") + result = script.pip( + "install", "--no-build-isolation", "--no-index", package_a_path, "--no-deps" + ) assert ( "Successfully installed package_A-1.0" in result.stdout or "Successfully installed package-A-1.0" in result.stdout @@ -148,7 +159,9 @@ def test_check_complicated_name_broken(script: PipTestEnvironment) -> None: ) # With broken dependency - result = script.pip("install", "--no-index", package_a_path, "--no-deps") + result = script.pip( + "install", "--no-build-isolation", "--no-index", package_a_path, "--no-deps" + ) assert ( "Successfully installed package_A-1.0" in result.stdout or "Successfully installed package-A-1.0" in result.stdout @@ -156,6 +169,7 @@ def test_check_complicated_name_broken(script: PipTestEnvironment) -> None: result = script.pip( "install", + "--no-build-isolation", "--no-index", dependency_b_path_incompatible, "--no-deps", @@ -184,7 +198,9 @@ def test_check_complicated_name_clean(script: PipTestEnvironment) -> None: version="1.0", ) - result = script.pip("install", "--no-index", package_a_path, "--no-deps") + result = script.pip( + "install", "--no-build-isolation", "--no-index", package_a_path, "--no-deps" + ) assert ( "Successfully installed package_A-1.0" in result.stdout or "Successfully installed package-A-1.0" in result.stdout @@ -192,6 +208,7 @@ def test_check_complicated_name_clean(script: PipTestEnvironment) -> None: result = script.pip( "install", + "--no-build-isolation", "--no-index", dependency_b_path, "--no-deps", @@ -215,7 +232,9 @@ def test_check_considers_conditional_reqs(script: PipTestEnvironment) -> None: ], ) - result = script.pip("install", "--no-index", package_a_path, "--no-deps") + result = script.pip( + "install", "--no-build-isolation", "--no-index", package_a_path, "--no-deps" + ) assert ( "Successfully installed package_A-1.0" in result.stdout or "Successfully installed package-A-1.0" in result.stdout @@ -238,7 +257,9 @@ def test_check_development_versions_are_also_considered( install_requires=["depend>=1.0"], ) # Let's install pkga without its dependency - res = script.pip("install", "--no-index", pkga_path, "--no-deps") + res = script.pip( + "install", "--no-build-isolation", "--no-index", pkga_path, "--no-deps" + ) assert "Successfully installed pkga-1.0" in res.stdout, str(res) # Setup depend==1.1.0.dev0 @@ -250,6 +271,7 @@ def test_check_development_versions_are_also_considered( # Let's install depend==1.1.0.dev0 res = script.pip( "install", + "--no-build-isolation", "--no-index", depend_path, "--no-warn-conflicts", diff --git a/tests/functional/test_cli.py b/tests/functional/test_cli.py index 6d2e2a12935..02429eb9a4d 100644 --- a/tests/functional/test_cli.py +++ b/tests/functional/test_cli.py @@ -45,7 +45,9 @@ def test_entrypoints_work(entrypoint: str, script: PipTestEnvironment) -> None: ) # expect_temp because pip install will generate fake_pkg.egg-info - script.pip("install", "-vvv", str(fake_pkg), expect_temp=True) + script.pip( + "install", "--no-build-isolation", "-vvv", str(fake_pkg), expect_temp=True + ) result = script.pip("-V") result2 = script.run("fake_pip", "-V", allow_stderr_warning=True) assert result.stdout == result2.stdout diff --git a/tests/functional/test_completion.py b/tests/functional/test_completion.py index f0396aa0c68..5d83694d50b 100644 --- a/tests/functional/test_completion.py +++ b/tests/functional/test_completion.py @@ -94,7 +94,7 @@ def script_with_launchers( tmpdir = tmpdir_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) + script.pip("install", "--no-index", "-f", common_wheels, pip_src) return script diff --git a/tests/functional/test_config_settings.py b/tests/functional/test_config_settings.py index 87de5fcc4c7..d762737ea55 100644 --- a/tests/functional/test_config_settings.py +++ b/tests/functional/test_config_settings.py @@ -111,27 +111,6 @@ def make_project( return name, version, project_dir -def test_config_settings_implies_pep517( - script: PipTestEnvironment, tmp_path: Path -) -> None: - """Test that setup.py bdist_wheel is not used when config settings are.""" - pkg_path = tmp_path / "pkga" - pkg_path.mkdir() - pkg_path.joinpath("setup.py").write_text( - "from setuptools import setup; setup(name='pkga')\n" - ) - result = script.pip( - "wheel", - "--no-build-isolation", - "--config-settings", - "FOO=Hello", - pkg_path, - cwd=tmp_path, - ) - assert "Successfully built pkga" in result.stdout - assert "Preparing metadata (pyproject.toml)" in result.stdout - - def test_backend_sees_config(script: PipTestEnvironment) -> None: name, version, project_dir = make_project(script.scratch_path) script.pip( diff --git a/tests/functional/test_download.py b/tests/functional/test_download.py index c5887aa1bf0..3bc9a241ea4 100644 --- a/tests/functional/test_download.py +++ b/tests/functional/test_download.py @@ -17,7 +17,6 @@ ScriptFactory, TestData, TestPipResult, - create_basic_sdist_for_package, create_really_basic_wheel, ) from tests.lib.server import MockServer, file_response @@ -54,8 +53,18 @@ def test_download_wheel(script: PipTestEnvironment, data: TestData) -> None: """ Test using "pip download" to download a *.whl archive. """ + # This test needs --no-build-isolation because `meta` depends on `simple` + # which is a source distribution for which it needs to prepare metadata + # to look for transitive dependencies. result = script.pip( - "download", "--no-index", "-f", data.packages, "-d", ".", "meta" + "download", + "--no-build-isolation", + "--no-index", + "-f", + data.packages, + "-d", + ".", + "meta", ) result.did_create(Path("scratch") / "meta-1.0-py2.py3-none-any.whl") result.did_not_create(script.site_packages / "piptestpackage") @@ -122,7 +131,14 @@ def test_download_should_download_wheel_deps( dep_filename = "translationstring-1.1.tar.gz" wheel_path = "/".join((data.find_links, wheel_filename)) result = script.pip( - "download", wheel_path, "-d", ".", "--find-links", data.find_links, "--no-index" + "download", + "--no-build-isolation", + wheel_path, + "-d", + ".", + "--find-links", + data.find_links, + "--no-index", ) result.did_create(Path("scratch") / wheel_filename) result.did_create(Path("scratch") / dep_filename) @@ -687,8 +703,7 @@ def make_args(python_version: str) -> list[str]: args = make_args("33") result = script.pip(*args, expect_error=True) expected_err = ( - "ERROR: Package 'mypackage' requires a different Python: " - "3.3.0 not in '==3.2'" + "ERROR: Package 'mypackage' requires a different Python: 3.3.0 not in '==3.2'" ) assert expected_err in result.stderr, f"stderr: {result.stderr}" @@ -978,6 +993,7 @@ def test_download_prefer_binary_when_wheel_doesnt_satisfy_req( result = script.pip( "download", + "--no-build-isolation", "--prefer-binary", "--no-index", "-f", @@ -1006,6 +1022,7 @@ def test_prefer_binary_when_wheel_doesnt_satisfy_req_req_file( result = script.pip( "download", + "--no-build-isolation", "--no-index", "-f", data.packages, @@ -1023,6 +1040,7 @@ def test_download_prefer_binary_when_only_tarball_exists( ) -> None: result = script.pip( "download", + "--no-build-isolation", "--prefer-binary", "--no-index", "-f", @@ -1047,6 +1065,7 @@ def test_prefer_binary_when_only_tarball_exists_req_file( ) result = script.pip( "download", + "--no-build-isolation", "--no-index", "-f", data.packages, @@ -1078,6 +1097,7 @@ def test_download_file_url( shared_script.pip( "download", + "--no-build-isolation", "-d", str(download_dir), "--no-index", @@ -1102,7 +1122,12 @@ def test_download_file_url_existing_ok_download( url = f"{simple_pkg.as_uri()}#sha256={sha256(downloaded_path_bytes).hexdigest()}" shared_script.pip( - "download", "-d", str(download_dir), url, "--disable-pip-version-check" + "download", + "--no-build-isolation", + "-d", + str(download_dir), + url, + "--disable-pip-version-check", ) assert downloaded_path_bytes == downloaded_path.read_bytes() @@ -1123,6 +1148,7 @@ def test_download_file_url_existing_bad_download( result = shared_script.pip( "download", + "--no-build-isolation", "-d", str(download_dir), url, @@ -1159,6 +1185,7 @@ def test_download_http_url_bad_hash( result = shared_script.pip( "download", + "--no-build-isolation", "-d", str(download_dir), url, @@ -1187,56 +1214,19 @@ def test_download_editable( requirements_path.write_text("-e " + editable_path + "\n") download_dir = tmpdir / "download_dir" script.pip( - "download", "--no-deps", "-r", str(requirements_path), "-d", str(download_dir) + "download", + "--no-build-isolation", + "--no-deps", + "-r", + str(requirements_path), + "-d", + str(download_dir), ) downloads = os.listdir(download_dir) assert len(downloads) == 1 assert downloads[0].endswith(".zip") -def test_download_use_pep517_propagation( - script: PipTestEnvironment, tmpdir: Path, common_wheels: Path -) -> None: - """ - Check that --use-pep517 applies not just to the requirements specified - on the command line, but to their dependencies too. - """ - - create_basic_sdist_for_package(script, "fake_proj", "1.0", depends=["fake_dep"]) - - # If --use-pep517 is in effect, then setup.py should be running in an isolated - # environment that doesn't have pip in it. - create_basic_sdist_for_package( - script, - "fake_dep", - "1.0", - setup_py_prelude=textwrap.dedent( - """\ - try: - import pip - except ImportError: - pass - else: - raise Exception(f"not running in isolation") - """ - ), - ) - - download_dir = tmpdir / "download_dir" - script.pip( - "download", - f"--dest={download_dir}", - "--no-index", - f"--find-links={common_wheels}", - f"--find-links={script.scratch_path}", - "--use-pep517", - "fake_proj", - ) - - downloads = os.listdir(download_dir) - assert len(downloads) == 2 - - @pytest.fixture def download_local_html_index( script: PipTestEnvironment, @@ -1256,6 +1246,7 @@ def run_for_generated_index( """ pip_args = [ "download", + "--no-build-isolation", "-d", str(download_dir), "-i", @@ -1287,6 +1278,7 @@ def run_for_generated_index( """ pip_args = [ "download", + "--no-build-isolation", "-d", str(download_dir), "-i", diff --git a/tests/functional/test_freeze.py b/tests/functional/test_freeze.py index 9883beb87fd..374c960514c 100644 --- a/tests/functional/test_freeze.py +++ b/tests/functional/test_freeze.py @@ -24,7 +24,6 @@ need_svn, wheel, ) -from tests.lib.direct_url import get_created_direct_url_path from tests.lib.venv import VirtualEnvironment distribute_re = re.compile("^distribute==[0-9.]+\n", re.MULTILINE) @@ -210,7 +209,7 @@ def test_freeze_editable_not_vcs(script: PipTestEnvironment) -> None: # Rename the .git directory so the directory is no longer recognized # as a VCS directory. os.rename(os.path.join(pkg_path, ".git"), os.path.join(pkg_path, ".bak")) - script.pip("install", "-e", pkg_path) + script.pip("install", "--no-build-isolation", "-e", pkg_path) result = script.pip("freeze") # We need to apply os.path.normcase() to the path since that is what @@ -232,7 +231,7 @@ def test_freeze_editable_git_with_no_remote( Test an editable Git install with no remote url. """ pkg_path = _create_test_package(script.scratch_path) - script.pip("install", "-e", pkg_path) + script.pip("install", "--no-build-isolation", "-e", pkg_path) result = script.pip("freeze") if not deprecated_python: @@ -596,7 +595,7 @@ def test_freeze_nested_vcs( os.fspath(src_path), expect_stderr=True, ) - script.pip("install", "-e", src_path, expect_stderr=True) + script.pip("install", "--no-build-isolation", "-e", src_path, expect_stderr=True) # Check the freeze output recognizes the inner VCS. result = script.pip("freeze", expect_stderr=True) @@ -994,7 +993,7 @@ def test_freeze_direct_url_archive( script: PipTestEnvironment, shared_data: TestData ) -> None: req = "simple @ " + shared_data.packages.joinpath("simple-2.0.tar.gz").as_uri() - script.pip("install", req) + script.pip("install", "--no-build-isolation", req) result = script.pip("freeze") assert req in result.stdout @@ -1038,8 +1037,8 @@ def test_freeze_pep610_editable(script: PipTestEnvironment) -> None: is correctly frozeon as editable. """ pkg_path = _create_test_package(script.scratch_path, name="testpkg") - result = script.pip("install", pkg_path) - direct_url_path = get_created_direct_url_path(result, "testpkg") + result = script.pip("install", "--no-build-isolation", pkg_path) + direct_url_path = result.get_created_direct_url_path("testpkg") assert direct_url_path # patch direct_url.json to simulate an editable install with open(direct_url_path) as f: diff --git a/tests/functional/test_install.py b/tests/functional/test_install.py index a1bd81d31d0..3b949baa6a6 100644 --- a/tests/functional/test_install.py +++ b/tests/functional/test_install.py @@ -16,6 +16,7 @@ import pytest from pip._internal.cli.status_codes import ERROR, SUCCESS +from pip._internal.models.direct_url import DirectUrl from pip._internal.models.index import PyPI, TestPyPI from pip._internal.utils.misc import rmtree from pip._internal.utils.urls import path_to_url @@ -105,8 +106,13 @@ def test_pep518_refuses_conflicting_requires( create_basic_wheel_for_package(script, "setuptools", "1.0") create_basic_wheel_for_package(script, "wheel", "1.0") project_dir = data.src.joinpath("pep518_conflicting_requires") - result = script.pip_install_local( - "-f", script.scratch_path, project_dir, expect_error=True + result = script.pip( + "install", + "--no-index", + "-f", + script.scratch_path, + project_dir, + expect_error=True, ) assert result.returncode != 0 assert ( @@ -290,7 +296,7 @@ def test_pip_second_command_line_interface_works( Check if ``pip`` commands behaves equally """ # Re-install pip so we get the launchers. - script.pip_install_local("-f", common_wheels, pip_src) + script.pip("install", "--no-index", "-f", common_wheels, pip_src) args = [f"pip{pyversion}"] args.extend(["install", "INITools==0.2"]) args.extend(["-f", os.fspath(data.packages)]) @@ -400,7 +406,9 @@ def test_basic_install_editable_from_svn(script: PipTestEnvironment) -> None: """ checkout_path = _create_test_package(script.scratch_path) repo_url = _create_svn_repo(script.scratch_path, checkout_path) - result = script.pip("install", "-e", "svn+" + repo_url + "#egg=version-pkg") + result = script.pip( + "install", "--no-build-isolation", "-e", "svn+" + repo_url + "#egg=version-pkg" + ) result.assert_installed("version_pkg", with_files=[".svn"]) @@ -409,6 +417,7 @@ def _test_install_editable_from_git(script: PipTestEnvironment) -> None: pkg_path = _create_test_package(script.scratch_path, name="testpackage", vcs="git") args = [ "install", + "--no-build-isolation", "-e", f"git+{pkg_path.as_uri()}#egg=testpackage", ] @@ -437,7 +446,9 @@ def test_install_editable_uninstalls_existing( to_install = data.packages.joinpath("pip_test_package-0.1.tar.gz") result = script.pip_install_local(to_install) assert "Successfully installed pip-test-package" in result.stdout - result.assert_installed("piptestpackage", editable=False) + result.assert_installed( + "piptestpackage", dist_name="pip-test-package", editable=False + ) result = script.pip( "install", @@ -449,7 +460,9 @@ def test_install_editable_uninstalls_existing( ) ), ) - result.assert_installed("pip-test-package", with_files=[".git"]) + result.assert_installed( + "piptestpackage", dist_name="pip-test-package", with_files=[".git"] + ) assert "Found existing installation: pip-test-package 0.1" in result.stdout assert "Uninstalling pip-test-package-" in result.stdout assert "Successfully uninstalled pip-test-package" in result.stdout @@ -469,13 +482,8 @@ def test_install_editable_uninstalls_existing_from_path( result.assert_installed("simplewheel", editable=False) result.did_create(simple_folder) - result = script.pip( - "install", - "-e", - to_install, - ) - install_path = script.site_packages / "simplewheel.egg-link" - result.did_create(install_path) + result = script.pip_install_local("-e", to_install) + script.assert_installed_editable("simplewheel") assert "Found existing installation: simplewheel 1.0" in result.stdout assert "Uninstalling simplewheel-" in result.stdout assert "Successfully uninstalled simplewheel" in result.stdout @@ -488,7 +496,7 @@ def test_basic_install_editable_from_hg(script: PipTestEnvironment) -> None: pkg_path = _create_test_package(script.scratch_path, name="testpackage", vcs="hg") url = f"hg+{pkg_path.as_uri()}#egg=testpackage" assert url.startswith("hg+file") - args = ["install", "-e", url] + args = ["install", "--no-build-isolation", "-e", url] result = script.pip(*args) result.assert_installed("testpackage", with_files=[".hg"]) @@ -501,6 +509,7 @@ def test_vcs_url_final_slash_normalization(script: PipTestEnvironment) -> None: pkg_path = _create_test_package(script.scratch_path, name="testpackage", vcs="hg") args = [ "install", + "--no-build-isolation", "-e", f"hg+{pkg_path.as_uri()}/#egg=testpackage", ] @@ -516,6 +525,7 @@ def test_install_editable_from_bazaar(script: PipTestEnvironment) -> None: ) args = [ "install", + "--no-build-isolation", "-e", f"bzr+{pkg_path.as_uri()}/#egg=testpackage", ] @@ -531,7 +541,7 @@ def test_vcs_url_urlquote_normalization(script: PipTestEnvironment) -> None: script.scratch_path, name="django_wikiapp", vcs="git" ) url = f"git+{pkg_path.as_uri().replace('django_', 'django%5F')}/#egg=django_wikiapp" - script.pip("install", "-e", url) + script.pip("install", "--no-build-isolation", "-e", url) @pytest.mark.parametrize("resolver", ["", "--use-deprecated=legacy-resolver"]) @@ -541,7 +551,7 @@ def test_basic_install_from_local_directory( """ Test installing from a local directory. """ - args = ["install"] + args = ["install", "--no-build-isolation"] if resolver: args.append(resolver) to_install = data.packages.joinpath("FSPkg") @@ -571,7 +581,6 @@ def test_basic_install_relative_directory( Test installing a requirement using a relative path. """ dist_info_folder = script.site_packages / "fspkg-0.1.dev0.dist-info" - egg_link_file = script.site_packages / "FSPkg.egg-link" package_folder = script.site_packages / "fspkg" # Compute relative install path to FSPkg from scratch path. @@ -589,13 +598,19 @@ def test_basic_install_relative_directory( # Install as either editable or not. if not editable: - result = script.pip("install", req_path, cwd=script.scratch_path) + result = script.pip( + "install", "--no-build-isolation", req_path, cwd=script.scratch_path + ) result.did_create(dist_info_folder) result.did_create(package_folder) else: # Editable install. - result = script.pip("install", "-e", req_path, cwd=script.scratch_path) - result.did_create(egg_link_file) + result = script.pip( + "install", "--no-build-isolation", "-e", req_path, cwd=script.scratch_path + ) + direct_url = result.get_created_direct_url("fspkg") + assert direct_url + assert direct_url.is_local_editable() def test_install_quiet(script: PipTestEnvironment, data: TestData) -> None: @@ -607,7 +622,7 @@ def test_install_quiet(script: PipTestEnvironment, data: TestData) -> None: # https://github.com/pypa/pip/issues/3418 # https://github.com/docker-library/python/issues/83 to_install = data.packages.joinpath("FSPkg") - result = script.pip("install", "-qqq", to_install) + result = script.pip("install", "--no-build-isolation", "-qqq", to_install) assert result.stdout == "" assert result.stderr == "" @@ -789,12 +804,12 @@ def test_hashed_install_from_cache( tmpdir, ) as reqs_file: result = script.pip_install_local( - "--use-pep517", "--no-build-isolation", "-r", reqs_file.resolve() + "--no-build-isolation", "-r", reqs_file.resolve() ) assert "Created wheel for simple2" in result.stdout script.pip("uninstall", "simple2", "-y") result = script.pip_install_local( - "--use-pep517", "--no-build-isolation", "-r", reqs_file.resolve() + "--no-build-isolation", "-r", reqs_file.resolve() ) assert "Using cached simple2" in result.stdout # now try with an invalid hash @@ -804,7 +819,6 @@ def test_hashed_install_from_cache( ) as reqs_file: script.pip("uninstall", "simple2", "-y") result = script.pip_install_local( - "--use-pep517", "--no-build-isolation", "-r", reqs_file.resolve(), @@ -862,7 +876,7 @@ def test_install_from_local_directory_with_in_tree_build( in_tree_build_dir = to_install / "build" assert not in_tree_build_dir.exists() - result = script.pip("install", to_install) + result = script.pip("install", "--no-build-isolation", 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) @@ -895,41 +909,6 @@ def test_editable_install__local_dir_no_setup_py( ) -@pytest.mark.skipif( - sys.version_info >= (3, 12), - reason="Setuptools<64 does not support Python 3.12+", -) -@pytest.mark.network -def test_editable_install_legacy__local_dir_no_setup_py_with_pyproject( - script: PipTestEnvironment, -) -> None: - """ - Test installing in legacy editable mode from a local directory with no - setup.py but that does have pyproject.toml with a build backend that does - not support the build_editable hook. - """ - local_dir = script.scratch_path.joinpath("temp") - local_dir.mkdir() - pyproject_path = local_dir.joinpath("pyproject.toml") - pyproject_path.write_text( - textwrap.dedent( - """ - [build-system] - requires = ["setuptools<64"] - build-backend = "setuptools.build_meta" - """ - ) - ) - - result = script.pip("install", "-e", local_dir, expect_error=True) - assert not result.files_created - - msg = result.stderr - assert "has a 'pyproject.toml'" in msg - assert "does not have a 'setup.py' nor a 'setup.cfg'" in msg - assert "cannot be installed in editable mode" in msg - - def test_editable_install__local_dir_setup_requires_with_pyproject( script: PipTestEnvironment, shared_data: TestData ) -> None: @@ -1016,7 +995,7 @@ def test_install_curdir(script: PipTestEnvironment, data: TestData) -> None: egg_info = join(run_from, "FSPkg.egg-info") if os.path.isdir(egg_info): rmtree(egg_info) - result = script.pip("install", curdir, cwd=run_from) + result = script.pip("install", "--no-build-isolation", curdir, cwd=run_from) fspkg_folder = script.site_packages / "fspkg" dist_info_folder = script.site_packages / "fspkg-0.1.dev0.dist-info" result.did_create(fspkg_folder) @@ -1028,31 +1007,13 @@ def test_install_pardir(script: PipTestEnvironment, data: TestData) -> None: Test installing parent directory ('..'). """ run_from = data.packages.joinpath("FSPkg", "fspkg") - result = script.pip("install", pardir, cwd=run_from) + result = script.pip("install", "--no-build-isolation", pardir, cwd=run_from) fspkg_folder = script.site_packages / "fspkg" dist_info_folder = script.site_packages / "fspkg-0.1.dev0.dist-info" result.did_create(fspkg_folder) result.did_create(dist_info_folder) -@pytest.mark.network -def test_install_global_option(script: PipTestEnvironment) -> None: - """ - Test using global distutils options. - (In particular those that disable the actual install action) - """ - result = script.pip( - "install", - "--global-option=--version", - "INITools==0.1", - expect_error=True, # build is going to fail because of --version - ) - assert "INITools==0.1\n" in result.stdout - assert not result.files_created - assert "Implying --no-binary=:all:" in result.stderr - assert "A possible replacement is to use --config-settings" in result.stderr - - def test_install_with_hacked_egg_info( script: PipTestEnvironment, data: TestData ) -> None: @@ -1060,30 +1021,10 @@ def test_install_with_hacked_egg_info( test installing a package which defines its own egg_info class """ run_from = data.packages.joinpath("HackedEggInfo") - result = script.pip("install", ".", cwd=run_from) + result = script.pip("install", "--no-build-isolation", ".", cwd=run_from) assert "Successfully installed hackedegginfo-0.0.0\n" in result.stdout -@pytest.mark.xfail -@pytest.mark.network -@need_mercurial -def test_install_global_option_using_editable( - script: PipTestEnvironment, tmpdir: Path -) -> None: - """ - Test using global distutils options, but in an editable installation - """ - url = "hg+http://bitbucket.org/runeh/anyjson" - result = script.pip( - "install", - "--global-option=--version", - "-e", - f"{local_checkout(url, tmpdir)}@0.2.5#egg=anyjson", - expect_stderr=True, - ) - assert "Successfully installed anyjson" in result.stdout - - @pytest.mark.network def test_install_package_with_same_name_in_curdir(script: PipTestEnvironment) -> None: """ @@ -1110,7 +1051,7 @@ def test_install_folder_using_dot_slash(script: PipTestEnvironment) -> None: script.scratch_path.joinpath("mock").mkdir() pkg_path = script.scratch_path / "mock" pkg_path.joinpath("setup.py").write_text(mock100_setup_py) - result = script.pip("install", "./mock") + result = script.pip("install", "--no-build-isolation", "./mock") dist_info_folder = script.site_packages / "mock-100.1.dist-info" result.did_create(dist_info_folder) @@ -1122,7 +1063,7 @@ def test_install_folder_using_slash_in_the_end(script: PipTestEnvironment) -> No script.scratch_path.joinpath("mock").mkdir() pkg_path = script.scratch_path / "mock" pkg_path.joinpath("setup.py").write_text(mock100_setup_py) - result = script.pip("install", "mock" + os.path.sep) + result = script.pip("install", "--no-build-isolation", "mock" + os.path.sep) dist_info_folder = script.site_packages / "mock-100.1.dist-info" result.did_create(dist_info_folder) @@ -1135,7 +1076,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", "--no-build-isolation", Path("initools") / "mock") dist_info_folder = script.site_packages / "mock-100.1.dist-info" result.did_create(dist_info_folder) @@ -1315,7 +1256,7 @@ def main(): pass """ ) ) - result = script.pip("install", opt, target_dir, pkga_path) + result = script.pip("install", "--no-build-isolation", opt, target_dir, pkga_path) # This assertion isn't actually needed, if we get the script warning # the script.pip() call will fail with "stderr not expected". But we # leave the assertion to make the intention of the code clearer. @@ -1329,6 +1270,7 @@ def test_install_package_with_root(script: PipTestEnvironment, data: TestData) - root_dir = script.scratch_path / "root" result = script.pip( "install", + "--no-build-isolation", "--root", root_dir, "-f", @@ -1360,6 +1302,7 @@ def test_install_package_with_prefix( prefix_path = script.scratch_path / "prefix" result = script.pip( "install", + "--no-build-isolation", "--prefix", prefix_path, "-f", @@ -1402,10 +1345,19 @@ def _test_install_editable_with_prefix( # install pkga package into the absolute prefix directory prefix_path = script.scratch_path / "prefix" - result = script.pip("install", "--editable", pkga_path, "--prefix", prefix_path) + result = script.pip( + "install", + "--no-build-isolation", + "--editable", + pkga_path, + "--prefix", + prefix_path, + ) # assert pkga is installed at correct location - install_path = script.scratch / site_packages / "pkga.egg-link" + install_path = ( + script.scratch / site_packages / "pkga-0.1.dist-info" / "direct_url.json" + ) result.did_create(install_path) return result @@ -1431,7 +1383,11 @@ def test_install_editable_with_target(script: PipTestEnvironment) -> None: target.mkdir() result = script.pip("install", "--editable", pkg_path, "--target", target) - result.did_create(script.scratch / "target" / "pkg.egg-link") + direct_url_path = result.get_created_direct_url_path("pkg") + assert direct_url_path + assert direct_url_path.parent.parent == target + direct_url = DirectUrl.from_json(direct_url_path.read_text()) + assert direct_url.is_local_editable() result.did_create(script.scratch / "target" / "watching_testrunner.py") @@ -1443,28 +1399,6 @@ def test_install_editable_with_prefix_setup_py(script: PipTestEnvironment) -> No _test_install_editable_with_prefix(script, {"setup.py": setup_py}) -@pytest.mark.skipif( - sys.version_info >= (3, 12), - reason="Setuptools<64 does not support Python 3.12+", -) -@pytest.mark.network -def test_install_editable_legacy_with_prefix_setup_cfg( - script: PipTestEnvironment, -) -> None: - setup_cfg = """[metadata] -name = pkga -version = 0.1 -""" - pyproject_toml = """[build-system] -requires = ["setuptools<64", "wheel"] -build-backend = "setuptools.build_meta" -""" - result = _test_install_editable_with_prefix( - script, {"setup.cfg": setup_cfg, "pyproject.toml": pyproject_toml} - ) - assert "(setup.py develop) is deprecated" in result.stderr - - def test_install_package_conflict_prefix_and_user( script: PipTestEnvironment, data: TestData ) -> None: @@ -1498,6 +1432,7 @@ def test_install_package_that_emits_unicode( to_install = data.packages.joinpath("BrokenEmitsUTF8") result = script.pip( "install", + "--no-build-isolation", to_install, expect_error=True, expect_temp=True, @@ -1515,7 +1450,7 @@ def test_install_package_with_utf8_setup( ) -> None: """Install a package with a setup.py that declares a utf-8 encoding.""" to_install = data.packages.joinpath("SetupPyUTF8") - script.pip("install", to_install) + script.pip("install", "--no-build-isolation", to_install) def test_install_package_with_latin1_setup( @@ -1523,7 +1458,7 @@ def test_install_package_with_latin1_setup( ) -> None: """Install a package with a setup.py that declares a latin-1 encoding.""" to_install = data.packages.joinpath("SetupPyLatin1") - script.pip("install", to_install) + script.pip("install", "--no-build-isolation", to_install) def test_url_req_case_mismatch_no_index( @@ -1539,7 +1474,13 @@ def test_url_req_case_mismatch_no_index( """ Upper = "/".join((data.find_links, "Upper-1.0.tar.gz")) result = script.pip( - "install", "--no-index", "-f", data.find_links, Upper, "requiresupper" + "install", + "--no-build-isolation", + "--no-index", + "-f", + data.find_links, + Upper, + "requiresupper", ) # only Upper-1.0.tar.gz should get installed. @@ -1568,7 +1509,12 @@ def test_url_req_case_mismatch_file_index( """ Dinner = "/".join((data.find_links3, "dinner", "Dinner-1.0.tar.gz")) result = script.pip( - "install", "--index-url", data.find_links3, Dinner, "requiredinner" + "install", + "--no-build-isolation", + "--index-url", + data.find_links3, + Dinner, + "requiredinner", ) # only Dinner-1.0.tar.gz should get installed. @@ -1588,6 +1534,7 @@ def test_url_incorrect_case_no_index( """ result = script.pip( "install", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -1611,6 +1558,7 @@ def test_url_incorrect_case_file_index( """ result = script.pip( "install", + "--no-build-isolation", "--index-url", data.find_links3, "dinner", @@ -1678,7 +1626,7 @@ def test_install_upgrade_editable_depending_on_other_editable( """ ) ) - script.pip("install", "--editable", pkga_path) + script.pip("install", "--no-build-isolation", "--editable", pkga_path) result = script.pip("list", "--format=freeze") assert "pkga==0.1" in result.stdout @@ -1694,7 +1642,14 @@ def test_install_upgrade_editable_depending_on_other_editable( """ ) ) - script.pip("install", "--upgrade", "--editable", pkgb_path, "--no-index") + script.pip( + "install", + "--no-build-isolation", + "--upgrade", + "--editable", + pkgb_path, + "--no-index", + ) result = script.pip("list", "--format=freeze") assert "pkgb==0.1" in result.stdout @@ -1702,7 +1657,12 @@ def test_install_upgrade_editable_depending_on_other_editable( def test_install_subprocess_output_handling( script: PipTestEnvironment, data: TestData ) -> None: - args = ["install", os.fspath(data.src.joinpath("chattymodule"))] + args = [ + "install", + "--no-build-isolation", + "--no-cache", + os.fspath(data.src.joinpath("chattymodule")), + ] # Regular install should not show output from the chatty setup.py result = script.pip(*args) @@ -1713,48 +1673,56 @@ def test_install_subprocess_output_handling( # Only count examples with sys.argv[1] == egg_info, because we call # setup.py multiple times, which should not count as duplicate output. result = script.pip(*(args + ["--verbose"]), expect_stderr=True) - assert 1 == result.stderr.count("HELLO FROM CHATTYMODULE egg_info") + assert 1 == result.stderr.count( + "HELLO FROM CHATTYMODULE prepare_metadata_for_build_wheel" + ) + assert 1 == result.stderr.count("HELLO FROM CHATTYMODULE build_wheel") script.pip("uninstall", "-y", "chattymodule") # If the install fails, then we *should* show the output... but only once, # even if --verbose is given. - result = script.pip(*(args + ["--global-option=--fail"]), expect_error=True) - # This error is emitted 3 times: - # - by setup.py bdist_wheel - # - by setup.py clean - assert 2 == result.stderr.count("I DIE, I DIE") + result = script.pip(*(args + ["--config-setting=fail=1"]), expect_error=True) + assert 1 == result.stderr.count("I DIE, I DIE") + assert 1 == result.stderr.count("I DIE, I DIE in prepare_metadata_for_build_wheel") result = script.pip( - *(args + ["--global-option=--fail", "--verbose"]), expect_error=True + *(args + ["--config-setting=fail=1", "--verbose"]), expect_error=True ) - assert 2 == result.stderr.count("I DIE, I DIE") + assert 1 == result.stderr.count("I DIE, I DIE") + assert 1 == result.stderr.count("I DIE, I DIE in prepare_metadata_for_build_wheel") def test_install_log(script: PipTestEnvironment, data: TestData, tmpdir: Path) -> None: # test that verbose logs go to "--log" file f = tmpdir.joinpath("log.txt") - result = script.pip(f"--log={f}", "install", data.src.joinpath("chattymodule")) + result = script.pip( + f"--log={f}", + "install", + "--no-build-isolation", + data.src.joinpath("chattymodule"), + ) assert 0 == result.stdout.count("HELLO FROM CHATTYMODULE") with open(f) as fp: - # one from egg_info, one from install + # one from prepare_metadata_for_build_wheel, one from build_wheel assert 2 == fp.read().count("HELLO FROM CHATTYMODULE") def test_install_topological_sort(script: PipTestEnvironment, data: TestData) -> None: - res = str(script.pip("install", "TopoRequires4", "--no-index", "-f", data.packages)) + res = str( + script.pip( + "install", + "--no-build-isolation", + "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 -def test_cleanup_after_failed_wheel(script: PipTestEnvironment) -> None: - res = script.pip_install_local("wheelbrokenafter", expect_error=True) - assert "ERROR: Failed building wheel for wheelbrokenafter" in res.stderr - # OK, assert that we *said* we were cleaning up: - # /!\ if in need to change this, also change test_pep517_no_legacy_cleanup - assert "Running setup.py clean for wheelbrokenafter" in str(res), str(res) - - def test_install_builds_wheels(script: PipTestEnvironment, data: TestData) -> None: # We need to use a subprocess to get the right value on Windows. res = script.run( @@ -1772,6 +1740,7 @@ def test_install_builds_wheels(script: PipTestEnvironment, data: TestData) -> No to_install = data.packages.joinpath("requires_wheelbroken_upper") res = script.pip( "install", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -1801,6 +1770,7 @@ def test_install_no_binary_builds_wheels( to_install = data.packages.joinpath("requires_wheelbroken_upper") res = script.pip( "install", + "--no-build-isolation", "--no-index", "--no-binary=upper", "-f", @@ -1847,10 +1817,13 @@ def test_install_no_binary_uses_cached_wheels( script: PipTestEnvironment, data: TestData ) -> None: # Seed the cache - script.pip("install", "--no-index", "-f", data.find_links, "upper") + script.pip( + "install", "--no-build-isolation", "--no-index", "-f", data.find_links, "upper" + ) script.pip("uninstall", "upper", "-y") res = script.pip( "install", + "--no-build-isolation", "--no-index", "--no-binary=:all:", "-f", @@ -1879,6 +1852,7 @@ def test_install_editable_with_wrong_egg_name( ) result = script.pip( "install", + "--no-build-isolation", "--editable", path_to_url(str(pkga_path)) + "#egg=pkgb", expect_error=(resolver_variant == "resolvelib"), @@ -1899,7 +1873,9 @@ def test_install_tar_xz(script: PipTestEnvironment, data: TestData) -> None: import lzma # noqa except ImportError: pytest.skip("No lzma support") - res = script.pip("install", data.packages / "singlemodule-0.0.1.tar.xz") + res = script.pip( + "install", "--no-build-isolation", data.packages / "singlemodule-0.0.1.tar.xz" + ) assert "Successfully installed singlemodule-0.0.1" in res.stdout, res @@ -1908,7 +1884,9 @@ def test_install_tar_lzma(script: PipTestEnvironment, data: TestData) -> None: import lzma # noqa except ImportError: pytest.skip("No lzma support") - res = script.pip("install", data.packages / "singlemodule-0.0.1.tar.lzma") + res = script.pip( + "install", "--no-build-isolation", data.packages / "singlemodule-0.0.1.tar.lzma" + ) assert "Successfully installed singlemodule-0.0.1" in res.stdout, res @@ -1959,7 +1937,7 @@ def test_install_incompatible_python_requires(script: PipTestEnvironment) -> Non """ ) ) - result = script.pip("install", pkga_path, expect_error=True) + result = script.pip("install", "--no-build-isolation", pkga_path, expect_error=True) assert _get_expected_error_text() in result.stderr, str(result) @@ -1978,7 +1956,9 @@ def test_install_incompatible_python_requires_editable( """ ) ) - result = script.pip("install", f"--editable={pkga_path}", expect_error=True) + result = script.pip( + "install", "--no-build-isolation", f"--editable={pkga_path}", expect_error=True + ) assert _get_expected_error_text() in result.stderr, str(result) @@ -2021,7 +2001,7 @@ def test_install_compatible_python_requires(script: PipTestEnvironment) -> None: """ ) ) - res = script.pip("install", pkga_path) + res = script.pip("install", "--no-build-isolation", pkga_path) assert "Successfully installed pkga-0.1" in res.stdout, res @@ -2064,6 +2044,7 @@ def test_install_from_test_pypi_with_ext_url_dep_is_blocked( ) -> None: res = script.pip( "install", + "--no-build-isolation", "--index-url", index, "pep-508-url-deps", @@ -2127,12 +2108,15 @@ def test_install_conflict_results_in_warning( ) # Install pkgA without its dependency - result1 = script.pip("install", "--no-index", pkgA_path, "--no-deps") + result1 = script.pip( + "install", "--no-build-isolation", "--no-index", pkgA_path, "--no-deps" + ) assert "Successfully installed pkgA-1.0" in result1.stdout, str(result1) # Then install an incorrect version of the dependency result2 = script.pip( "install", + "--no-build-isolation", "--no-index", pkgB_path, allow_stderr_error=True, @@ -2157,11 +2141,19 @@ def test_install_conflict_warning_can_be_suppressed( ) # Install pkgA without its dependency - result1 = script.pip("install", "--no-index", pkgA_path, "--no-deps") + result1 = script.pip( + "install", "--no-build-isolation", "--no-index", pkgA_path, "--no-deps" + ) assert "Successfully installed pkgA-1.0" in result1.stdout, str(result1) # Then install an incorrect version of the dependency; suppressing warning - result2 = script.pip("install", "--no-index", pkgB_path, "--no-warn-conflicts") + result2 = script.pip( + "install", + "--no-build-isolation", + "--no-index", + pkgB_path, + "--no-warn-conflicts", + ) assert "Successfully installed pkgB-2.0" in result2.stdout, str(result2) @@ -2237,6 +2229,7 @@ def test_ignore_yanked_file(script: PipTestEnvironment, data: TestData) -> None: result = script.pip( "install", "simple", + "--no-build-isolation", "--index-url", data.index_url("yanked"), ) @@ -2272,7 +2265,13 @@ def test_valid_index_url_argument( Test the behaviour of an valid --index-url argument """ - result = script.pip("install", "--index-url", shared_data.find_links3, "Dinner") + result = script.pip( + "install", + "--no-build-isolation", + "--index-url", + shared_data.find_links3, + "Dinner", + ) assert "Successfully installed Dinner" in result.stdout, str(result) @@ -2289,6 +2288,7 @@ def test_install_yanked_file_and_print_warning( result = script.pip( "install", "simple==3.0", + "--no-build-isolation", "--index-url", data.index_url("yanked"), expect_stderr=True, @@ -2377,7 +2377,15 @@ def test_install_sends_client_cert( url = f"https://{server.host}:{server.port}/simple" - args = ["install", "-vvv", "--cert", cert_path, "--client-cert", cert_path] + args = [ + "install", + "--no-build-isolation", + "-vvv", + "--cert", + cert_path, + "--client-cert", + cert_path, + ] args.extend(["--index-url", url]) args.extend(install_args) args.append("simple") @@ -2469,7 +2477,9 @@ def test_install_verify_package_name_normalization( pkg_path = create_test_package_with_setup( script, name="simple-package", version="1.0" ) - result = script.pip("install", "-e", ".", expect_stderr=True, cwd=pkg_path) + result = script.pip( + "install", "--no-build-isolation", "-e", ".", expect_stderr=True, cwd=pkg_path + ) assert "Successfully installed simple-package" in result.stdout result = script.pip("install", package_name) @@ -2480,7 +2490,7 @@ def test_install_logs_pip_version_in_debug( script: PipTestEnvironment, shared_data: TestData ) -> None: fake_package = shared_data.packages / "simple-2.0.tar.gz" - result = script.pip("install", "-v", fake_package) + result = script.pip("install", "--no-build-isolation", "-v", fake_package) pattern = "Using pip .* from .*" assert_re_match(pattern, result.stdout) @@ -2504,6 +2514,7 @@ def install_find_links( else () ), *(("--dry-run",) if dry_run else ()), + "--no-build-isolation", "--no-index", "--find-links", data.find_links, diff --git a/tests/functional/test_install_check.py b/tests/functional/test_install_check.py index a0598fe2703..cb8312b535d 100644 --- a/tests/functional/test_install_check.py +++ b/tests/functional/test_install_check.py @@ -27,13 +27,16 @@ def test_check_install_canonicalization(script: PipTestEnvironment) -> None: ) # Let's install pkgA without its dependency - result = script.pip("install", "--no-index", pkga_path, "--no-deps") + result = script.pip( + "install", "--no-build-isolation", "--no-index", pkga_path, "--no-deps" + ) assert "Successfully installed pkgA-1.0" in result.stdout, str(result) # Install the first missing dependency. Only an error for the # second dependency should remain. result = script.pip( "install", + "--no-build-isolation", "--no-index", normal_path, "--quiet", @@ -51,6 +54,7 @@ def test_check_install_canonicalization(script: PipTestEnvironment) -> None: # name normalization (as in https://github.com/pypa/pip/issues/5134) result = script.pip( "install", + "--no-build-isolation", "--no-index", special_path, "--quiet", @@ -88,12 +92,15 @@ def test_check_install_does_not_warn_for_out_of_graph_issues( ) # Install a package without it's dependencies - result = script.pip("install", "--no-index", pkg_broken_path, "--no-deps") + result = script.pip( + "install", "--no-build-isolation", "--no-index", pkg_broken_path, "--no-deps" + ) assert "requires" not in result.stderr # Install conflict package result = script.pip( "install", + "--no-build-isolation", "--no-index", pkg_conflict_path, allow_stderr_error=True, @@ -110,6 +117,7 @@ def test_check_install_does_not_warn_for_out_of_graph_issues( # Install unrelated package result = script.pip( "install", + "--no-build-isolation", "--no-index", pkg_unrelated_path, "--quiet", diff --git a/tests/functional/test_install_cleanup.py b/tests/functional/test_install_cleanup.py index bc34defc978..457657073c4 100644 --- a/tests/functional/test_install_cleanup.py +++ b/tests/functional/test_install_cleanup.py @@ -28,16 +28,3 @@ def test_no_clean_option_blocks_cleaning_after_install( allow_stderr_warning=True, ) assert exists(build) - - -@pytest.mark.network -def test_pep517_no_legacy_cleanup(script: PipTestEnvironment, data: TestData) -> None: - """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) - # Must not have built the package - expected = "Failed building wheel for pep517-wrapper-buildsys" - assert expected in str(res) - # Must not have attempted legacy cleanup - assert "setup.py clean" not in str(res) diff --git a/tests/functional/test_install_compat.py b/tests/functional/test_install_compat.py index 47ba41bdf9e..c0ba64c25d7 100644 --- a/tests/functional/test_install_compat.py +++ b/tests/functional/test_install_compat.py @@ -73,4 +73,4 @@ def test_setup_py_with_dos_line_endings( Refs https://github.com/pypa/pip/issues/237 """ to_install = data.packages.joinpath("LineEndings") - script.pip("install", to_install) + script.pip("install", "--no-build-isolation", to_install) diff --git a/tests/functional/test_install_config.py b/tests/functional/test_install_config.py index baee7e80d55..678e51822c1 100644 --- a/tests/functional/test_install_config.py +++ b/tests/functional/test_install_config.py @@ -199,6 +199,7 @@ def test_config_file_override_stack( script.pip("install", "-vvv", "INITools", expect_error=True) script.pip( "install", + "--no-build-isolation", "-vvv", "--index-url", f"{base_address}/simple3", @@ -250,7 +251,13 @@ def test_install_no_binary_via_config_disables_cached_wheels( ) config_file.close() res = script.pip( - "install", "--no-index", "-f", data.find_links, "upper", expect_stderr=True + "install", + "--no-build-isolation", + "--no-index", + "-f", + data.find_links, + "upper", + expect_stderr=True, ) finally: os.unlink(config_file.name) @@ -520,6 +527,7 @@ def set_password(self, url, username): with server_running(server): result = script.pip( "install", + "--no-build-isolation", "--index-url", url, "--cert", diff --git a/tests/functional/test_install_direct_url.py b/tests/functional/test_install_direct_url.py index 5aefab09cb3..f67a8615b21 100644 --- a/tests/functional/test_install_direct_url.py +++ b/tests/functional/test_install_direct_url.py @@ -3,29 +3,19 @@ from pip._internal.models.direct_url import VcsInfo from tests.lib import PipTestEnvironment, TestData, _create_test_package -from tests.lib.direct_url import get_created_direct_url def test_install_find_links_no_direct_url(script: PipTestEnvironment) -> None: result = script.pip_install_local("simple") - assert not get_created_direct_url(result, "simple") - - -def test_install_vcs_editable_no_direct_url(script: PipTestEnvironment) -> None: - pkg_path = _create_test_package(script.scratch_path, name="testpkg") - args = ["install", "-e", f"git+{pkg_path.as_uri()}#egg=testpkg"] - result = script.pip(*args) - # legacy editable installs do not generate .dist-info, - # hence no direct_url.json - assert not get_created_direct_url(result, "testpkg") + assert not result.get_created_direct_url("simple") def test_install_vcs_non_editable_direct_url(script: PipTestEnvironment) -> None: pkg_path = _create_test_package(script.scratch_path, name="testpkg") url = pkg_path.as_uri() - args = ["install", f"git+{url}#egg=testpkg"] + args = ["install", "--no-build-isolation", f"git+{url}#egg=testpkg"] result = script.pip(*args) - direct_url = get_created_direct_url(result, "testpkg") + direct_url = result.get_created_direct_url("testpkg") assert direct_url assert direct_url.url == url assert isinstance(direct_url.info, VcsInfo) @@ -35,8 +25,8 @@ def test_install_vcs_non_editable_direct_url(script: PipTestEnvironment) -> None def test_install_archive_direct_url(script: PipTestEnvironment, data: TestData) -> None: req = "simple @ " + data.packages.joinpath("simple-2.0.tar.gz").as_uri() assert req.startswith("simple @ file://") - result = script.pip("install", req) - assert get_created_direct_url(result, "simple") + result = script.pip("install", "--no-build-isolation", req) + assert result.get_created_direct_url("simple") @pytest.mark.network @@ -48,7 +38,7 @@ def test_install_vcs_constraint_direct_url(script: PipTestEnvironment) -> None: "#egg=pip-test-package" ) result = script.pip("install", "pip-test-package", "-c", constraints_file) - assert get_created_direct_url(result, "pip_test_package") + assert result.get_created_direct_url("pip_test_package") def test_install_vcs_constraint_direct_file_url(script: PipTestEnvironment) -> None: @@ -56,5 +46,7 @@ def test_install_vcs_constraint_direct_file_url(script: PipTestEnvironment) -> N url = pkg_path.as_uri() constraints_file = script.scratch_path / "constraints.txt" constraints_file.write_text(f"git+{url}#egg=testpkg") - result = script.pip("install", "testpkg", "-c", constraints_file) - assert get_created_direct_url(result, "testpkg") + result = script.pip( + "install", "--no-build-isolation", "testpkg", "-c", constraints_file + ) + assert result.get_created_direct_url("testpkg") diff --git a/tests/functional/test_install_extras.py b/tests/functional/test_install_extras.py index 44dbc2a3694..5a0ebc23ced 100644 --- a/tests/functional/test_install_extras.py +++ b/tests/functional/test_install_extras.py @@ -35,6 +35,7 @@ def test_extras_after_wheel(script: PipTestEnvironment, data: TestData) -> None: no_extra = script.pip( "install", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -45,6 +46,7 @@ def test_extras_after_wheel(script: PipTestEnvironment, data: TestData) -> None: extra = script.pip( "install", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -84,6 +86,7 @@ def test_nonexistent_extra_warns_user_no_wheel( result = script.pip( "install", "--no-binary=:all:", + "--no-build-isolation", "--no-index", "--find-links=" + data.find_links, "simple[nonexistent]", @@ -273,4 +276,4 @@ def test_install_setuptools_extras_inconsistency( """ ) ) - script.pip("install", "--dry-run", test_project_path) + script.pip("install", "--no-build-isolation", "--dry-run", test_project_path) diff --git a/tests/functional/test_install_index.py b/tests/functional/test_install_index.py index 73b122a6141..4ebc005ba09 100644 --- a/tests/functional/test_install_index.py +++ b/tests/functional/test_install_index.py @@ -9,6 +9,7 @@ def test_find_links_relative_path(script: PipTestEnvironment, data: TestData) -> result = script.pip( "install", "parent==0.1", + "--no-build-isolation", "--no-index", "--find-links", "packages/", @@ -27,7 +28,6 @@ def test_find_links_no_doctype(script: PipTestEnvironment, data: TestData) -> No result = script.pip( "install", "simple==1.0", - "--use-pep517", "--no-build-isolation", "--no-index", "--find-links", @@ -52,6 +52,7 @@ def test_find_links_requirements_file_relative_path( ) result = script.pip( "install", + "--no-build-isolation", "-r", script.scratch_path / "test-req.txt", cwd=data.root, @@ -69,7 +70,9 @@ def test_install_from_file_index_hash_link( Test that a pkg can be installed from a file:// index using a link with a hash """ - result = script.pip("install", "-i", data.index_url(), "simple==1.0") + result = script.pip( + "install", "--no-build-isolation", "-i", data.index_url(), "simple==1.0" + ) dist_info_folder = script.site_packages / "simple-1.0.dist-info" result.did_create(dist_info_folder) @@ -79,6 +82,8 @@ def test_file_index_url_quoting(script: PipTestEnvironment, data: TestData) -> N Test url quoting of file index url with a space """ index_url = data.index_url("in dex") - result = script.pip("install", "-vvv", "--index-url", index_url, "simple") + result = script.pip( + "install", "--no-build-isolation", "-vvv", "--index-url", index_url, "simple" + ) result.did_create(script.site_packages / "simple") result.did_create(script.site_packages / "simple-1.0.dist-info") diff --git a/tests/functional/test_install_report.py b/tests/functional/test_install_report.py index 968e30f2dec..ab35c30932b 100644 --- a/tests/functional/test_install_report.py +++ b/tests/functional/test_install_report.py @@ -50,6 +50,7 @@ def test_install_report_dep( report_path = tmp_path / "report.json" script.pip( "install", + "--no-build-isolation", "require_simple", "--dry-run", "--no-index", @@ -75,6 +76,7 @@ def test_yanked_version( report_path = tmp_path / "report.json" script.pip( "install", + "--no-build-isolation", "simple==3.0", "--index-url", data.index_url("yanked"), @@ -102,6 +104,7 @@ def test_skipped_yanked_version( report_path = tmp_path / "report.json" script.pip( "install", + "--no-build-isolation", "simple", "--index-url", data.index_url("yanked"), diff --git a/tests/functional/test_install_reqs.py b/tests/functional/test_install_reqs.py index 3c5b6db4a68..e1c0906298f 100644 --- a/tests/functional/test_install_reqs.py +++ b/tests/functional/test_install_reqs.py @@ -13,7 +13,6 @@ _create_test_package_with_subdirectory, create_basic_sdist_for_package, create_basic_wheel_for_package, - make_wheel, need_svn, requirements_file, ) @@ -188,8 +187,7 @@ def test_schema_check_in_requirements_file(script: PipTestEnvironment) -> None: """ script.scratch_path.joinpath("file-egg-req.txt").write_text( "\n{}\n".format( - "git://github.com/alex/django-fixture-generator.git" - "#egg=fixture_generator" + "git://github.com/alex/django-fixture-generator.git#egg=fixture_generator" ) ) @@ -217,7 +215,6 @@ def test_relative_requirements_file( """ dist_info_folder = script.site_packages / "fspkg-0.1.dev0.dist-info" - egg_link_file = script.site_packages / "FSPkg.egg-link" package_folder = script.site_packages / "fspkg" # Compute relative install path to FSPkg from scratch path. @@ -238,7 +235,12 @@ def test_relative_requirements_file( if not editable: with requirements_file(req_path + "\n", script.scratch_path) as reqs_file: result = script.pip( - "install", "-vvv", "-r", reqs_file.name, cwd=script.scratch_path + "install", + "--no-build-isolation", + "-vvv", + "-r", + reqs_file.name, + cwd=script.scratch_path, ) result.did_create(dist_info_folder) result.did_create(package_folder) @@ -247,9 +249,16 @@ def test_relative_requirements_file( "-e " + req_path + "\n", script.scratch_path ) as reqs_file: result = script.pip( - "install", "-vvv", "-r", reqs_file.name, cwd=script.scratch_path + "install", + "--no-build-isolation", + "-vvv", + "-r", + reqs_file.name, + cwd=script.scratch_path, ) - result.did_create(egg_link_file) + direct_url = result.get_created_direct_url("fspkg") + assert direct_url + assert direct_url.is_local_editable() @pytest.mark.xfail @@ -290,6 +299,7 @@ def test_package_in_constraints_and_dependencies( ) result = script.pip( "install", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -315,6 +325,7 @@ def test_constraints_apply_to_dependency_groups( ) result = script.pip( "install", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -331,6 +342,7 @@ def test_multiple_constraints_files(script: PipTestEnvironment, data: TestData) script.scratch_path.joinpath("inner.txt").write_text("Upper==1.0") result = script.pip( "install", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -357,6 +369,7 @@ def test_respect_order_in_requirements_file( result = script.pip( "install", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -384,9 +397,8 @@ def test_install_local_editable_with_extras( res = script.pip_install_local( "-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") - res.did_create(script.site_packages / "simple") + res.assert_installed("LocalExtras", editable=True, editable_vcs=False) + res.assert_installed("simple", editable=False) def test_install_collected_dependencies_first(script: PipTestEnvironment) -> None: @@ -444,7 +456,13 @@ def test_wheel_user_with_prefix_in_pydistutils_cfg( ) result = script.pip( - "install", "--user", "--no-index", "-f", data.find_links, "requiresupper" + "install", + "--no-build-isolation", + "--user", + "--no-index", + "-f", + data.find_links, + "requiresupper", ) # Check that we are really installing a wheel assert "installed requiresupper" in result.stdout @@ -456,6 +474,7 @@ def test_constraints_not_installed_by_default( script.scratch_path.joinpath("c.txt").write_text("requiresupper") result = script.pip( "install", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -491,6 +510,7 @@ def test_constraints_local_editable_install_causes_error( to_install = data.src.joinpath("singlemodule") result = script.pip( "install", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -523,6 +543,7 @@ def test_constraints_local_install_causes_error( to_install = data.src.joinpath("singlemodule") result = script.pip( "install", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -570,6 +591,7 @@ def test_constraints_constrain_to_local( ) result = script.pip( "install", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -589,6 +611,7 @@ def test_constrained_to_url_install_same_url( script.scratch_path.joinpath("constraints.txt").write_text(constraints) result = script.pip( "install", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -817,8 +840,7 @@ def test_install_unsupported_wheel_link_with_marker(script: PipTestEnvironment) result = script.pip("install", "-r", script.scratch_path / "with-marker.txt") assert ( - "Ignoring asdf: markers 'sys_platform == \"xyz\"' don't match " - "your environment" + "Ignoring asdf: markers 'sys_platform == \"xyz\"' don't match your environment" ) in result.stdout assert len(result.files_created) == 0 @@ -918,26 +940,3 @@ def test_config_settings_local_to_package( assert "--verbose" not in simple3_args simple2_args = simple2_sdist.args() assert "--verbose" not in simple2_args - - -def test_nonpep517_setuptools_import_failure(script: PipTestEnvironment) -> None: - """Any import failures of `setuptools` should inform the user both that it's - not pip's fault, but also exactly what went wrong in the import.""" - # Install a poisoned version of 'setuptools' that fails to import. - name = "setuptools_poisoned" - module = """\ -raise ImportError("this 'setuptools' was intentionally poisoned") -""" - path = make_wheel(name, "0.1.0", extra_files={"setuptools.py": module}).save_to_dir( - script.scratch_path - ) - script.pip("install", "--no-index", path) - - result = script.pip_install_local("--no-use-pep517", "simple", expect_error=True) - nice_message = ( - "ERROR: Can not execute `setup.py`" - " since setuptools failed to import in the build environment" - ) - exc_message = "ImportError: this 'setuptools' was intentionally poisoned" - assert nice_message in result.stderr - assert exc_message in result.stderr diff --git a/tests/functional/test_install_requested.py b/tests/functional/test_install_requested.py index 2c5cad9fcc8..cc834af2ab2 100644 --- a/tests/functional/test_install_requested.py +++ b/tests/functional/test_install_requested.py @@ -23,7 +23,12 @@ def _assert_requested_absent( def test_install_requested_basic(script: PipTestEnvironment, data: TestData) -> None: result = script.pip( - "install", "--no-index", "-f", data.find_links, "require_simple" + "install", + "--no-build-isolation", + "--no-index", + "-f", + data.find_links, + "require_simple", ) _assert_requested_present(script, result, "require_simple", "1.0") # dependency is not REQUESTED @@ -36,6 +41,7 @@ def test_install_requested_requirements( script.scratch_path.joinpath("requirements.txt").write_text("require_simple\n") result = script.pip( "install", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -54,6 +60,7 @@ def test_install_requested_dep_in_requirements( ) result = script.pip( "install", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -72,6 +79,7 @@ def test_install_requested_reqs_and_constraints( script.scratch_path.joinpath("constraints.txt").write_text("simple<3\n") result = script.pip( "install", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -94,6 +102,7 @@ def test_install_requested_in_reqs_and_constraints( script.scratch_path.joinpath("constraints.txt").write_text("simple<3\n") result = script.pip( "install", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -113,6 +122,7 @@ def test_install_requested_from_cli_with_constraint( script.scratch_path.joinpath("constraints.txt").write_text("simple<3\n") result = script.pip( "install", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -133,6 +143,7 @@ def test_install_requested_from_cli_with_url_constraint( ) result = script.pip( "install", + "--no-build-isolation", "--no-index", "-c", script.scratch_path / "constraints.txt", diff --git a/tests/functional/test_install_upgrade.py b/tests/functional/test_install_upgrade.py index 43b43d64f82..de52218e96f 100644 --- a/tests/functional/test_install_upgrade.py +++ b/tests/functional/test_install_upgrade.py @@ -167,9 +167,22 @@ def test_upgrade_with_newest_already_installed( If the newest version of a package is already installed, the package should not be reinstalled and the user should be informed. """ - script.pip("install", "-f", data.find_links, "--no-index", "simple") + script.pip( + "install", + "--no-build-isolation", + "-f", + data.find_links, + "--no-index", + "simple", + ) result = script.pip( - "install", "--upgrade", "-f", data.find_links, "--no-index", "simple" + "install", + "--no-build-isolation", + "--upgrade", + "-f", + data.find_links, + "--no-index", + "simple", ) assert not result.files_created, "simple upgraded when it should not have" if resolver_variant == "resolvelib": @@ -217,8 +230,7 @@ def test_uninstall_before_upgrade_from_url(script: PipTestEnvironment) -> None: result.did_create(script.site_packages / "initools") result2 = script.pip( "install", - "https://files.pythonhosted.org/packages/source/I/INITools/INITools-" - "0.3.tar.gz", + "https://files.pythonhosted.org/packages/source/I/INITools/INITools-0.3.tar.gz", ) assert result2.files_created, "upgrade to INITools 0.3 failed" result3 = script.pip("uninstall", "initools", "-y") @@ -236,8 +248,7 @@ def test_upgrade_to_same_version_from_url(script: PipTestEnvironment) -> None: result.did_create(script.site_packages / "initools") result2 = script.pip( "install", - "https://files.pythonhosted.org/packages/source/I/INITools/INITools-" - "0.3.tar.gz", + "https://files.pythonhosted.org/packages/source/I/INITools/INITools-0.3.tar.gz", ) assert ( script.site_packages / "initools" not in result2.files_updated @@ -288,10 +299,18 @@ def test_uninstall_rollback(script: PipTestEnvironment, data: TestData) -> None: crafted to fail on install). """ - result = script.pip("install", "-f", data.find_links, "--no-index", "broken==0.1") + result = script.pip( + "install", + "--no-build-isolation", + "-f", + data.find_links, + "--no-index", + "broken==0.1", + ) result.did_create(script.site_packages / "broken.py") result2 = script.pip( "install", + "--no-build-isolation", "-f", data.find_links, "--no-index", diff --git a/tests/functional/test_install_user.py b/tests/functional/test_install_user.py index 0b1e025cbbe..7d39bc3ce11 100644 --- a/tests/functional/test_install_user.py +++ b/tests/functional/test_install_user.py @@ -75,7 +75,7 @@ def test_install_subversion_usersite_editable_with_distribute( ) ), ) - result.assert_installed("INITools", use_user_site=True) + result.assert_installed("INITools") def test_install_from_current_directory_into_usersite( self, script: PipTestEnvironment, data: TestData @@ -86,6 +86,7 @@ def test_install_from_current_directory_into_usersite( run_from = data.packages.joinpath("FSPkg") result = script.pip( "install", + "--no-build-isolation", "-vvv", "--user", curdir, diff --git a/tests/functional/test_install_vcs_git.py b/tests/functional/test_install_vcs_git.py index 38d416fb62d..187b6faafa0 100644 --- a/tests/functional/test_install_vcs_git.py +++ b/tests/functional/test_install_vcs_git.py @@ -108,7 +108,11 @@ def _install_version_pkg_only( """ version_pkg_url = _make_version_pkg_url(path, rev=rev) script.pip( - "install", "-e", version_pkg_url, allow_stderr_warning=allow_stderr_warning + "install", + "--no-build-isolation", + "-e", + version_pkg_url, + allow_stderr_warning=allow_stderr_warning, ) @@ -183,7 +187,9 @@ def test_install_editable_from_git_with_https( url_path = "pypa/pip-test-package.git" local_url = _github_checkout(url_path, tmpdir, egg="pip-test-package") result = script.pip("install", "-e", local_url) - result.assert_installed("pip-test-package", with_files=[".git"]) + result.assert_installed( + "piptestpackage", dist_name="pip-test-package", with_files=[".git"] + ) @pytest.mark.network @@ -193,11 +199,12 @@ def test_install_noneditable_git(script: PipTestEnvironment) -> None: """ result = script.pip( "install", - "git+https://github.com/pypa/pip-test-package.git" - "@0.1.1#egg=pip-test-package", + "git+https://github.com/pypa/pip-test-package.git@0.1.1#egg=pip-test-package", ) dist_info_folder = script.site_packages / "pip_test_package-0.1.1.dist-info" - result.assert_installed("piptestpackage", without_egg_link=True, editable=False) + result.assert_installed( + "piptestpackage", dist_name="pip-test-package", editable=False + ) result.did_create(dist_info_folder) @@ -339,29 +346,6 @@ def test_install_git_logs_commit_sha( assert f"Resolved {base_local_url[4:]} to commit {expected_sha}" in result.stdout -@pytest.mark.network -def test_git_with_tag_name_and_update(script: PipTestEnvironment, tmpdir: 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) - - local_url = f"{base_local_url}#egg=pip-test-package" - result = script.pip("install", "-e", local_url) - result.assert_installed("pip-test-package", with_files=[".git"]) - - new_local_url = f"{base_local_url}@0.1.2#egg=pip-test-package" - result = script.pip( - "install", - "--global-option=--version", - "-e", - new_local_url, - allow_stderr_warning=True, - ) - assert "0.1.2" in result.stdout - - @pytest.mark.network def test_git_branch_should_not_be_changed( script: PipTestEnvironment, tmpdir: Path @@ -393,7 +377,6 @@ def test_git_with_non_editable_unpacking( ) result = script.pip( "install", - "--global-option=--quiet", local_url, allow_stderr_warning=True, ) @@ -446,7 +429,7 @@ def test_git_with_ambiguous_revs(script: PipTestEnvironment) -> None: version_pkg_path = _create_test_package(script.scratch_path) version_pkg_url = _make_version_pkg_url(version_pkg_path, rev="0.1") script.run("git", "tag", "0.1", cwd=version_pkg_path) - result = script.pip("install", "-e", version_pkg_url) + result = script.pip("install", "--no-build-isolation", "-e", version_pkg_url) assert "Could not find a tag or branch" not in result.stdout # it is 'version-pkg' instead of 'version_pkg' because # egg-link name is version-pkg.egg-link because it is a single .py module @@ -587,11 +570,11 @@ def test_install_git_branch_not_cached(script: PipTestEnvironment) -> None: PKG = "gitbranchnotcached" repo_dir = _create_test_package(script.scratch_path, name=PKG) url = _make_version_pkg_url(repo_dir, rev="master", name=PKG) - result = script.pip("install", url, "--only-binary=:all:") + result = script.pip("install", "--no-build-isolation", url, "--only-binary=:all:") assert f"Successfully built {PKG}" in result.stdout, result.stdout script.pip("uninstall", "-y", PKG) # build occurs on the second install too because it is not cached - result = script.pip("install", url) + result = script.pip("install", "--no-build-isolation", url) assert f"Successfully built {PKG}" in result.stdout, result.stdout @@ -603,9 +586,9 @@ def test_install_git_sha_cached(script: PipTestEnvironment) -> None: repo_dir = _create_test_package(script.scratch_path, name=PKG) commit = script.run("git", "rev-parse", "HEAD", cwd=repo_dir).stdout.strip() url = _make_version_pkg_url(repo_dir, rev=commit, name=PKG) - result = script.pip("install", url) + result = script.pip("install", "--no-build-isolation", url) assert f"Successfully built {PKG}" in result.stdout, result.stdout script.pip("uninstall", "-y", PKG) # build does not occur on the second install because it is cached - result = script.pip("install", url) + result = script.pip("install", "--no-build-isolation", url) assert f"Successfully built {PKG}" not in result.stdout, result.stdout diff --git a/tests/functional/test_install_wheel.py b/tests/functional/test_install_wheel.py index e01ecfb57f3..9ab76ba17b7 100644 --- a/tests/functional/test_install_wheel.py +++ b/tests/functional/test_install_wheel.py @@ -38,7 +38,7 @@ def test_install_from_future_wheel_version( result = script.pip("install", package, "--no-index", expect_error=True) with pytest.raises(TestFailure): - result.assert_installed("futurewheel", without_egg_link=True, editable=False) + result.assert_installed("futurewheel", editable=False) package = make_wheel_with_file( name="futurewheel", @@ -46,7 +46,7 @@ def test_install_from_future_wheel_version( wheel_metadata_updates={"Wheel-Version": "1.9"}, ).save_to_dir(tmpdir) result = script.pip("install", package, "--no-index", expect_stderr=True) - result.assert_installed("futurewheel", without_egg_link=True, editable=False) + result.assert_installed("futurewheel", editable=False) @pytest.mark.parametrize( @@ -67,7 +67,7 @@ def test_install_from_broken_wheel( package = data.packages.joinpath(wheel_name) result = script.pip("install", package, "--no-index", expect_error=True) with pytest.raises(TestFailure): - result.assert_installed("futurewheel", without_egg_link=True, editable=False) + result.assert_installed("futurewheel", editable=False) def test_basic_install_from_wheel( @@ -299,6 +299,7 @@ def test_install_from_wheel_installs_deps( shutil.copy(data.packages / "source-1.0.tar.gz", tmpdir) result = script.pip( "install", + "--no-build-isolation", "--no-index", "--find-links", tmpdir, diff --git a/tests/functional/test_list.py b/tests/functional/test_list.py index 468e6acd6c2..f058439279f 100644 --- a/tests/functional/test_list.py +++ b/tests/functional/test_list.py @@ -15,7 +15,6 @@ make_wheel, wheel, ) -from tests.lib.direct_url import get_created_direct_url_path @pytest.fixture(scope="session") @@ -28,6 +27,7 @@ def simple_script( script = script_factory(tmpdir.joinpath("workspace")) script.pip( "install", + "--no-build-isolation", "-f", shared_data.find_links, "--no-index", @@ -170,6 +170,7 @@ def test_uptodate_flag(script: PipTestEnvironment, data: TestData) -> None: """ script.pip( "install", + "--no-build-isolation", "-f", data.find_links, "--no-index", @@ -210,6 +211,7 @@ def test_uptodate_columns_flag(script: PipTestEnvironment, data: TestData) -> No """ script.pip( "install", + "--no-build-isolation", "-f", data.find_links, "--no-index", @@ -245,6 +247,7 @@ def test_outdated_flag(script: PipTestEnvironment, data: TestData) -> None: """ script.pip( "install", + "--no-build-isolation", "-f", data.find_links, "--no-index", @@ -299,6 +302,7 @@ def test_outdated_columns_flag(script: PipTestEnvironment, data: TestData) -> No """ script.pip( "install", + "--no-build-isolation", "-f", data.find_links, "--no-index", @@ -338,9 +342,17 @@ def pip_test_package_script( ) -> PipTestEnvironment: tmpdir = tmpdir_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( "install", + "--no-build-isolation", + "-f", + shared_data.find_links, + "--no-index", + "simple==1.0", + ) + script.pip( + "install", + "--no-build-isolation", "-e", "git+https://github.com/pypa/pip-test-package.git#egg=pip-test-package", ) @@ -427,9 +439,17 @@ def test_outdated_editables_flag(script: PipTestEnvironment, data: TestData) -> """ test the behavior of --editable --outdated flag in the list command """ - script.pip("install", "-f", data.find_links, "--no-index", "simple==1.0") + script.pip( + "install", + "--no-build-isolation", + "-f", + data.find_links, + "--no-index", + "simple==1.0", + ) result = script.pip( "install", + "--no-build-isolation", "-e", "git+https://github.com/pypa/pip-test-package.git@0.1#egg=pip-test-package", ) @@ -452,9 +472,17 @@ def test_outdated_editables_columns_flag( """ test the behavior of --editable --outdated flag in the list command """ - script.pip("install", "-f", data.find_links, "--no-index", "simple==1.0") + script.pip( + "install", + "--no-build-isolation", + "-f", + data.find_links, + "--no-index", + "simple==1.0", + ) result = script.pip( "install", + "--no-build-isolation", "-e", "git+https://github.com/pypa/pip-test-package.git@0.1#egg=pip-test-package", ) @@ -479,6 +507,7 @@ def test_outdated_not_required_flag(script: PipTestEnvironment, data: TestData) """ script.pip( "install", + "--no-build-isolation", "-f", data.find_links, "--no-index", @@ -498,7 +527,14 @@ def test_outdated_not_required_flag(script: PipTestEnvironment, data: TestData) def test_outdated_pre(script: PipTestEnvironment, data: TestData) -> None: - script.pip("install", "-f", data.find_links, "--no-index", "simple==1.0") + script.pip( + "install", + "--no-build-isolation", + "-f", + data.find_links, + "--no-index", + "simple==1.0", + ) # Let's build a fake wheelhouse script.scratch_path.joinpath("wheelhouse").mkdir() @@ -546,7 +582,14 @@ def test_outdated_pre(script: PipTestEnvironment, data: TestData) -> None: def test_outdated_formats(script: PipTestEnvironment, data: TestData) -> None: """Test of different outdated formats""" - script.pip("install", "-f", data.find_links, "--no-index", "simple==1.0") + script.pip( + "install", + "--no-build-isolation", + "-f", + data.find_links, + "--no-index", + "simple==1.0", + ) # Let's build a fake wheelhouse script.scratch_path.joinpath("wheelhouse").mkdir() @@ -608,7 +651,14 @@ def test_outdated_formats(script: PipTestEnvironment, data: TestData) -> None: def test_not_required_flag(script: PipTestEnvironment, data: TestData) -> None: - script.pip("install", "-f", data.find_links, "--no-index", "TopoRequires4") + script.pip( + "install", + "--no-build-isolation", + "-f", + data.find_links, + "--no-index", + "TopoRequires4", + ) result = script.pip("list", "--not-required", expect_stderr=True) assert "TopoRequires4 " in result.stdout, str(result) assert "TopoRequires " not in result.stdout @@ -735,8 +785,8 @@ def test_list_pep610_editable(script: PipTestEnvironment) -> None: is correctly listed as editable. """ pkg_path = _create_test_package(script.scratch_path, name="testpkg") - result = script.pip("install", pkg_path) - direct_url_path = get_created_direct_url_path(result, "testpkg") + result = script.pip("install", "--no-build-isolation", pkg_path) + direct_url_path = result.get_created_direct_url_path("testpkg") assert direct_url_path # patch direct_url.json to simulate an editable install with open(direct_url_path) as f: diff --git a/tests/functional/test_lock.py b/tests/functional/test_lock.py index 727bd72c8a0..9cc6a03a494 100644 --- a/tests/functional/test_lock.py +++ b/tests/functional/test_lock.py @@ -59,6 +59,7 @@ def test_lock_sdist_from_findlinks( """Test locking a simple wheel package, to the default pylock.toml.""" result = script.pip( "lock", + "--no-build-isolation", "simple==2.0", "--no-binary=simple", "--quiet", diff --git a/tests/functional/test_new_resolver.py b/tests/functional/test_new_resolver.py index c094e675a30..b5b26128037 100644 --- a/tests/functional/test_new_resolver.py +++ b/tests/functional/test_new_resolver.py @@ -5,7 +5,6 @@ from typing import TYPE_CHECKING, Callable, Protocol import pytest -from packaging.utils import canonicalize_name from tests.conftest import ScriptFactory from tests.lib import ( @@ -14,27 +13,12 @@ create_basic_wheel_for_package, create_test_package_with_setup, ) -from tests.lib.direct_url import get_created_direct_url from tests.lib.venv import VirtualEnvironment from tests.lib.wheel import make_wheel 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 - # corresponding .egg-link file installed. - # TODO: Implement a more rigorous way to test for editable installations. - egg_links = {f"{canonicalize_name(arg)}.egg-link" for arg in args} - actual_egg_links = { - f"{canonicalize_name(p.stem)}.egg-link" - for p in script.site_packages_path.glob("*.egg-link") - } - assert ( - egg_links <= actual_egg_links - ), f"{args!r} not all found in {script.site_packages_path!r}" - - @pytest.fixture def make_fake_wheel(script: PipTestEnvironment) -> MakeFakeWheel: def _make_fake_wheel(name: str, version: str, wheel_tag: str) -> pathlib.Path: @@ -331,6 +315,7 @@ def test_new_resolver_installs_editable(script: PipTestEnvironment) -> None: ) script.pip( "install", + "--no-build-isolation", "--no-cache-dir", "--no-index", "--find-links", @@ -340,7 +325,7 @@ def test_new_resolver_installs_editable(script: PipTestEnvironment) -> None: source_dir, ) script.assert_installed(base="0.1.0", dep="0.1.0") - assert_editable(script, "dep") + script.assert_installed_editable("dep") @pytest.mark.parametrize( @@ -380,6 +365,7 @@ def test_new_resolver_requires_python( args = [ "install", + "--no-build-isolation", "--no-cache-dir", "--no-index", "--find-links", @@ -536,6 +522,7 @@ def test_new_resolver_only_builds_sdists_when_needed( # We only ever need to check dep 0.2.0 as it's the latest version script.pip( "install", + "--no-build-isolation", "--no-cache-dir", "--no-index", "--find-links", @@ -807,6 +794,7 @@ def test_new_resolver_constraint_on_path_empty( result = script.pip( "install", + "--no-build-isolation", "--no-cache-dir", "--no-index", "-c", @@ -1045,6 +1033,7 @@ def test_new_resolver_extra_merge_in_package( script.pip( "install", + "--no-build-isolation", "--no-cache-dir", "--no-index", "--find-links", @@ -1089,6 +1078,7 @@ def test_new_resolver_build_directory_error_zazo_19(script: PipTestEnvironment) script.pip( "install", + "--no-build-isolation", "--no-cache-dir", "--no-index", "--find-links", @@ -1184,6 +1174,7 @@ def test_new_resolver_prefers_installed_in_upgrade_if_latest( # Install the version that's not on the index. script.pip( "install", + "--no-build-isolation", "--no-cache-dir", "--no-index", local_pkg, @@ -1192,6 +1183,7 @@ def test_new_resolver_prefers_installed_in_upgrade_if_latest( # Now --upgrade should still pick the local version because it's "better". script.pip( "install", + "--no-build-isolation", "--no-cache-dir", "--no-index", "--find-links", @@ -1303,6 +1295,7 @@ def test_new_resolver_does_reinstall_local_sdists(script: PipTestEnvironment) -> ) script.pip( "install", + "--no-build-isolation", "--no-cache-dir", "--no-index", archive_path, @@ -1311,6 +1304,7 @@ def test_new_resolver_does_reinstall_local_sdists(script: PipTestEnvironment) -> result = script.pip( "install", + "--no-build-isolation", "--no-cache-dir", "--no-index", archive_path, @@ -1324,6 +1318,7 @@ def test_new_resolver_does_reinstall_local_paths(script: PipTestEnvironment) -> pkg = create_test_package_with_setup(script, name="pkg", version="1.0") script.pip( "install", + "--no-build-isolation", "--no-cache-dir", "--no-index", pkg, @@ -1332,6 +1327,7 @@ def test_new_resolver_does_reinstall_local_paths(script: PipTestEnvironment) -> result = script.pip( "install", + "--no-build-isolation", "--no-cache-dir", "--no-index", pkg, @@ -1350,6 +1346,7 @@ def test_new_resolver_does_not_reinstall_when_from_a_local_index( ) script.pip( "install", + "--no-build-isolation", "--no-cache-dir", "--no-index", "--find-links", @@ -1863,6 +1860,7 @@ def test_new_resolver_succeeds_on_matching_constraint_and_requirement( script.pip( "install", + "--no-build-isolation", "--no-cache-dir", "--no-index", "-c", @@ -1872,7 +1870,7 @@ def test_new_resolver_succeeds_on_matching_constraint_and_requirement( script.assert_installed(test_pkg="0.1.0") if editable: - assert_editable(script, "test_pkg") + script.assert_installed_editable("test_pkg") def test_new_resolver_applies_url_constraint_to_dep(script: PipTestEnvironment) -> None: @@ -2155,9 +2153,9 @@ def test_new_resolver_direct_url_with_extras( ) script.assert_installed(pkg1="1", pkg2="1", pkg3="1") - assert not get_created_direct_url(result, "pkg1") - assert get_created_direct_url(result, "pkg2") - assert not get_created_direct_url(result, "pkg3") + assert not result.get_created_direct_url("pkg1") + assert result.get_created_direct_url("pkg2") + assert not result.get_created_direct_url("pkg3") def test_new_resolver_modifies_installed_incompatible( @@ -2215,6 +2213,7 @@ def test_new_resolver_transitively_depends_on_unnamed_local( script.pip( "install", + "--no-build-isolation", "--no-cache-dir", "--no-index", "--find-links", @@ -2268,6 +2267,7 @@ def test_new_resolver_file_url_normalize( script.pip( "install", + "--no-build-isolation", "--no-cache-dir", "--no-index", format_input(lib_a), @@ -2479,7 +2479,7 @@ def test_new_resolver_constraint_on_link_with_extra_indirect( def test_new_resolver_do_not_backtrack_on_build_failure( script: PipTestEnvironment, ) -> None: - create_basic_sdist_for_package(script, "pkg1", "2.0", fails_egg_info=True) + create_basic_sdist_for_package(script, "pkg1", "2.0", fails_build=True) create_basic_wheel_for_package(script, "pkg1", "1.0") result = script.pip( @@ -2492,14 +2492,14 @@ def test_new_resolver_do_not_backtrack_on_build_failure( expect_error=True, ) - assert "egg_info" in result.stderr + assert "Failed to build 'pkg1'" in result.stderr def test_new_resolver_works_when_failing_package_builds_are_disallowed( script: PipTestEnvironment, ) -> None: create_basic_wheel_for_package(script, "pkg2", "1.0", depends=["pkg1"]) - create_basic_sdist_for_package(script, "pkg1", "2.0", fails_egg_info=True) + create_basic_sdist_for_package(script, "pkg1", "2.0", fails_build=True) create_basic_wheel_for_package(script, "pkg1", "1.0") constraints_file = script.scratch_path / "constraints.txt" constraints_file.write_text("pkg1 != 2.0") diff --git a/tests/functional/test_new_resolver_errors.py b/tests/functional/test_new_resolver_errors.py index ebca917d0a5..06c7dafaf41 100644 --- a/tests/functional/test_new_resolver_errors.py +++ b/tests/functional/test_new_resolver_errors.py @@ -88,7 +88,9 @@ 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-build-isolation", "--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 5fb1f2bf799..b9d4d7c4adf 100644 --- a/tests/functional/test_new_resolver_hashes.py +++ b/tests/functional/test_new_resolver_hashes.py @@ -72,6 +72,7 @@ def test_new_resolver_hash_intersect( result = script.pip( "install", + "--no-build-isolation", "--no-cache-dir", "--no-deps", "--no-index", @@ -102,6 +103,7 @@ def test_new_resolver_hash_intersect_from_constraint( result = script.pip( "install", + "--no-build-isolation", "--no-cache-dir", "--no-deps", "--no-index", @@ -163,6 +165,7 @@ def test_new_resolver_hash_intersect_empty( result = script.pip( "install", + "--no-build-isolation", "--no-cache-dir", "--no-deps", "--no-index", diff --git a/tests/functional/test_pep517.py b/tests/functional/test_pep517.py index 47dae96817f..e36c5f80277 100644 --- a/tests/functional/test_pep517.py +++ b/tests/functional/test_pep517.py @@ -4,7 +4,6 @@ from pathlib import Path from typing import Any -import pytest import tomli_w from pip._internal.build_env import ( @@ -129,25 +128,6 @@ def test_pep517_install_with_reqs( result.assert_installed("project", editable=False) -def test_no_use_pep517_without_setup_py( - script: PipTestEnvironment, tmpdir: Path, data: TestData -) -> None: - """Using --no-use-pep517 requires setup.py""" - project_dir = make_project( - tmpdir, requires=["test_backend"], backend="test_backend" - ) - result = script.pip( - "install", - "--no-index", - "--no-use-pep517", - "-f", - data.backends, - project_dir, - expect_error=True, - ) - assert "project does not have a setup.py" in result.stderr - - def test_conflicting_pep517_backend_requirements( script: PipTestEnvironment, tmpdir: Path, data: TestData ) -> None: @@ -390,45 +370,3 @@ def test_explicit_setuptools_backend( project_dir, ) result.assert_installed(name, editable=False) - - -@pytest.mark.network -def test_pep517_and_build_options( - script: PipTestEnvironment, tmpdir: Path, data: TestData, common_wheels: Path -) -> None: - """Backend generated requirements are installed in the build env""" - project_dir, name = make_pyproject_with_setup(tmpdir) - result = script.pip( - "wheel", - "--wheel-dir", - tmpdir, - "--build-option", - "foo", - "-f", - common_wheels, - project_dir, - allow_stderr_warning=True, - ) - assert "Ignoring --build-option when building" in result.stderr - assert "using PEP 517" in result.stderr - - -@pytest.mark.network -def test_pep517_and_global_options( - script: PipTestEnvironment, tmpdir: Path, data: TestData, common_wheels: Path -) -> None: - """Backend generated requirements are installed in the build env""" - project_dir, name = make_pyproject_with_setup(tmpdir) - result = script.pip( - "wheel", - "--wheel-dir", - tmpdir, - "--global-option", - "foo", - "-f", - common_wheels, - project_dir, - allow_stderr_warning=True, - ) - assert "Ignoring --global-option when building" in result.stderr - assert "using PEP 517" in result.stderr diff --git a/tests/functional/test_pep660.py b/tests/functional/test_pep660.py index 9cf3da31172..881d0cc8402 100644 --- a/tests/functional/test_pep660.py +++ b/tests/functional/test_pep660.py @@ -2,6 +2,7 @@ from pathlib import Path from typing import Any +import pytest import tomli_w from tests.lib import PipTestEnvironment @@ -164,53 +165,31 @@ def test_install_pep660_from_reqs_file( ), "a .egg-link file should not have been created" -def test_install_no_pep660_setup_py_fallback( - tmpdir: Path, script: PipTestEnvironment +@pytest.mark.parametrize("isolation_arg", [[], ["--no-build-isolation"]]) +def test_install_no_pep660( + isolation_arg: list[str], + tmpdir: Path, + script: PipTestEnvironment, + common_wheels: Path, ) -> 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) - result = script.pip( - "install", - "--no-index", - "--no-build-isolation", - "--editable", - project_dir, - allow_stderr_warning=False, - ) - _assert_hook_called(project_dir, "prepare_metadata_for_build_wheel") - assert ( - result.test_env.site_packages.joinpath("project.egg-link") - in result.files_created - ), "a .egg-link file should have been created" - + Test the error message when the build backend does not support PEP 660. -def test_install_no_pep660_setup_cfg_fallback( - tmpdir: 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. + The error is the same with and without build isolation. """ - project_dir = _make_project(tmpdir, BACKEND_WITHOUT_PEP660, with_setup_py=False) + project_dir = _make_project(tmpdir, BACKEND_WITHOUT_PEP660, with_setup_py=True) result = script.pip( "install", "--no-index", - "--no-build-isolation", + "-f", + common_wheels, + *isolation_arg, "--editable", project_dir, - allow_stderr_warning=False, + allow_error=True, ) - print(result.stdout, result.stderr) - _assert_hook_called(project_dir, "prepare_metadata_for_build_wheel") - assert ( - result.test_env.site_packages.joinpath("project.egg-link") - in result.files_created - ), ".egg-link file should have been created" + assert result.returncode != 0 + assert "missing the 'build_editable' hook" in result.stderr def test_wheel_editable_pep660_basic(tmpdir: Path, script: PipTestEnvironment) -> None: diff --git a/tests/functional/test_proxy.py b/tests/functional/test_proxy.py index 32eb94a1edf..0810d82d3af 100644 --- a/tests/functional/test_proxy.py +++ b/tests/functional/test_proxy.py @@ -77,6 +77,7 @@ def test_proxy_does_not_override_netrc( script.environ["NETRC"] = netrc script.pip( "install", + "--no-build-isolation", "--proxy", f"http://127.0.0.1:{proxy1.flags.port}", "--trusted-host", diff --git a/tests/functional/test_show.py b/tests/functional/test_show.py index ea831935372..40a40b0aa24 100644 --- a/tests/functional/test_show.py +++ b/tests/functional/test_show.py @@ -36,7 +36,7 @@ def test_show_with_files_not_found(script: PipTestEnvironment, data: TestData) - installed-files.txt not found. """ editable = data.packages.joinpath("SetupPyUTF8") - script.pip("install", "-e", editable) + script.run("python", "setup.py", "develop", cwd=editable) result = script.pip("show", "-f", "SetupPyUTF8") lines = result.stdout.splitlines() assert len(lines) == 13 @@ -264,7 +264,14 @@ def test_pip_show_divider(script: PipTestEnvironment, data: TestData) -> None: """ Expect a divider between packages """ - script.pip("install", "pip-test-package", "--no-index", "-f", data.packages) + script.pip( + "install", + "--no-build-isolation", + "pip-test-package", + "--no-index", + "-f", + data.packages, + ) result = script.pip("show", "pip", "pip-test-package") lines = result.stdout.splitlines() assert "---" in lines @@ -273,7 +280,14 @@ def test_pip_show_divider(script: PipTestEnvironment, data: TestData) -> None: def test_package_name_is_canonicalized( script: PipTestEnvironment, data: TestData ) -> None: - script.pip("install", "pip-test-package", "--no-index", "-f", data.packages) + script.pip( + "install", + "--no-build-isolation", + "pip-test-package", + "--no-index", + "-f", + data.packages, + ) dash_show_result = script.pip("show", "pip-test-package") underscore_upper_show_result = script.pip("show", "pip-test_Package") @@ -289,7 +303,14 @@ def test_show_required_by_packages_basic( Test that installed packages that depend on this package are shown """ editable_path = os.path.join(data.src, "requires_simple") - script.pip("install", "--no-index", "-f", data.find_links, editable_path) + script.pip( + "install", + "--no-build-isolation", + "--no-index", + "-f", + data.find_links, + editable_path, + ) result = script.pip("show", "simple") lines = result.stdout.splitlines() @@ -309,7 +330,14 @@ def test_show_required_by_packages_capitalized( where the package has a capital letter """ editable_path = os.path.join(data.src, "requires_capitalized") - script.pip("install", "--no-index", "-f", data.find_links, editable_path) + script.pip( + "install", + "--no-build-isolation", + "--no-index", + "-f", + data.find_links, + editable_path, + ) result = script.pip("show", "simple") lines = result.stdout.splitlines() @@ -330,9 +358,23 @@ def test_show_required_by_packages_requiring_capitalized( lower and upper case letters """ required_package_path = os.path.join(data.src, "requires_capitalized") - script.pip("install", "--no-index", "-f", data.find_links, required_package_path) + script.pip( + "install", + "--no-build-isolation", + "--no-index", + "-f", + data.find_links, + required_package_path, + ) editable_path = os.path.join(data.src, "requires_requires_capitalized") - script.pip("install", "--no-index", "-f", data.find_links, editable_path) + script.pip( + "install", + "--no-build-isolation", + "--no-index", + "-f", + data.find_links, + editable_path, + ) result = script.pip("show", "Requires_Capitalized") lines = result.stdout.splitlines() diff --git a/tests/functional/test_uninstall.py b/tests/functional/test_uninstall.py index 7d041bb69e0..1b2f32b152c 100644 --- a/tests/functional/test_uninstall.py +++ b/tests/functional/test_uninstall.py @@ -210,9 +210,9 @@ def test_uninstall_overlapping_package( parent_pkg = data.packages.joinpath("parent-0.1.tar.gz") child_pkg = data.packages.joinpath("child-0.1.tar.gz") - result1 = script.pip("install", parent_pkg) + result1 = script.pip("install", "--no-build-isolation", parent_pkg) result1.did_create(join(script.site_packages, "parent")) - result2 = script.pip("install", child_pkg) + result2 = script.pip("install", "--no-build-isolation", child_pkg) result2.did_create(join(script.site_packages, "child")) result2.did_create( normpath(join(script.site_packages, "parent/plugins/child_plugin.py")) @@ -269,7 +269,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 = script_name.with_suffix(".exe") - script.pip("install", pkg_path) + script.pip("install", "--no-build-isolation", pkg_path) assert script_name.exists() script.assert_installed(ep_install="0.1") @@ -296,7 +296,7 @@ def test_uninstall_gui_scripts(script: PipTestEnvironment) -> None: script_name = script.bin_path.joinpath("test_") if sys.platform == "win32": script_name = script_name.with_suffix(".exe") - script.pip("install", pkg_path) + script.pip("install", "--no-build-isolation", pkg_path) assert script_name.exists() script.pip("uninstall", pkg_name, "-y") assert not script_name.exists() @@ -313,7 +313,7 @@ def test_uninstall_console_scripts(script: PipTestEnvironment) -> None: version="0.1", entry_points={"console_scripts": ["discover = discover:main"]}, ) - result = script.pip("install", pkg_path) + result = script.pip("install", "--no-build-isolation", pkg_path) result.did_create(script.bin / f"discover{script.exe}") result2 = script.pip("uninstall", "discover", "-y") assert_all_changes( @@ -344,7 +344,7 @@ def test_uninstall_console_scripts_uppercase_name(script: PipTestEnvironment) -> ) script_name = script.bin_path.joinpath("Test" + script.exe) - script.pip("install", pkg_path) + script.pip("install", "--no-build-isolation", pkg_path) assert script_name.exists() script.pip("uninstall", "ep_install", "-y") @@ -437,7 +437,7 @@ def _test_uninstall_editable_with_source_outside_venv( temp_pkg_dir, expect_stderr=True, ) - result2 = script.pip("install", "-e", temp_pkg_dir) + result2 = script.run("python", "setup.py", "develop", cwd=temp_pkg_dir) result2.did_create(join(script.site_packages, "pip-test-package.egg-link")) result3 = script.pip("uninstall", "-y", "pip-test-package") assert_all_changes( @@ -665,9 +665,16 @@ def test_uninstall_editable_and_pip_install( script.environ["SETUPTOOLS_SYS_PATH_TECHNIQUE"] = "raw" pkg_path = data.packages.joinpath("FSPkg") - script.pip("install", "-e", ".", expect_stderr=True, cwd=pkg_path) + script.run("python", "setup.py", "develop", expect_stderr=True, cwd=pkg_path) # ensure both are installed with --ignore-installed: - script.pip("install", "--ignore-installed", ".", expect_stderr=True, cwd=pkg_path) + script.pip( + "install", + "--no-build-isolation", + "--ignore-installed", + ".", + expect_stderr=True, + cwd=pkg_path, + ) script.assert_installed(FSPkg="0.1.dev0") # Uninstall both develop and install uninstall = script.pip("uninstall", "FSPkg", "-y") @@ -702,7 +709,7 @@ def test_uninstall_editable_and_pip_install_easy_install_remove( # Install FSPkg pkg_path = data.packages.joinpath("FSPkg") - script.pip("install", "-e", ".", expect_stderr=True, cwd=pkg_path) + script.run("python", "setup.py", "develop", expect_stderr=True, cwd=pkg_path) # Rename easy-install.pth to pip-test-fspkg.pth easy_install_pth = join(script.site_packages_path, "easy-install.pth") diff --git a/tests/functional/test_uninstall_user.py b/tests/functional/test_uninstall_user.py index 63ba5e581d0..25b7512e12c 100644 --- a/tests/functional/test_uninstall_user.py +++ b/tests/functional/test_uninstall_user.py @@ -92,7 +92,9 @@ def test_uninstall_editable_from_usersite( # install to_install = data.packages.joinpath("FSPkg") - result1 = script.pip("install", "--user", "-e", to_install) + result1 = script.run( + "python", "setup.py", "develop", "--user", "--prefix=", cwd=to_install + ) egg_link = script.user_site / "FSPkg.egg-link" result1.did_create(egg_link) diff --git a/tests/functional/test_wheel.py b/tests/functional/test_wheel.py index e1ede880496..66099dbebd1 100644 --- a/tests/functional/test_wheel.py +++ b/tests/functional/test_wheel.py @@ -53,6 +53,7 @@ def test_pip_wheel_success(script: PipTestEnvironment, data: TestData) -> None: """ result = script.pip( "wheel", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -87,6 +88,7 @@ def test_pip_wheel_success_with_dependency_group( ) result = script.pip( "wheel", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -111,6 +113,7 @@ def test_pip_wheel_build_cache(script: PipTestEnvironment, data: TestData) -> No """ result = script.pip( "wheel", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -162,6 +165,7 @@ def test_pip_wheel_build_relative_cachedir( """ result = script.pip( "wheel", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -179,6 +183,7 @@ def test_pip_wheel_builds_when_no_binary_set( # Check that the wheel package is ignored res = script.pip( "wheel", + "--no-build-isolation", "--no-index", "--no-binary", ":all:", @@ -199,6 +204,7 @@ def test_pip_wheel_readonly_cache( # Check that the wheel package is ignored res = script.pip( "wheel", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -219,7 +225,13 @@ def test_pip_wheel_builds_editable_deps( """ editable_path = os.path.join(data.src, "requires_simple") result = script.pip( - "wheel", "--no-index", "-f", data.find_links, "-e", editable_path + "wheel", + "--no-build-isolation", + "--no-index", + "-f", + data.find_links, + "-e", + editable_path, ) wheel_file_name = f"simple-1.0-py{pyversion[0]}-none-any.whl" wheel_file_path = script.scratch / wheel_file_name @@ -232,7 +244,13 @@ def test_pip_wheel_builds_editable(script: PipTestEnvironment, data: TestData) - """ editable_path = os.path.join(data.src, "simplewheel-1.0") result = script.pip( - "wheel", "--no-index", "-f", data.find_links, "-e", editable_path + "wheel", + "--no-build-isolation", + "--no-index", + "-f", + data.find_links, + "-e", + editable_path, ) wheel_file_name = f"simplewheel-1.0-py{pyversion[0]}-none-any.whl" wheel_file_path = script.scratch / wheel_file_name @@ -248,6 +266,7 @@ def test_pip_wheel_git_editable_keeps_clone( """ script.pip( "wheel", + "--no-build-isolation", "--no-deps", "-e", "git+https://github.com/pypa/pip-test-package#egg=pip-test-package", @@ -270,7 +289,15 @@ def test_pip_wheel_builds_editable_does_not_create_zip( wheel_dir = tmpdir / "wheel_dir" wheel_dir.mkdir() editable_path = os.path.join(data.src, "simplewheel-1.0") - script.pip("wheel", "--no-deps", "-e", editable_path, "-w", wheel_dir) + script.pip( + "wheel", + "--no-build-isolation", + "--no-deps", + "-e", + editable_path, + "-w", + wheel_dir, + ) wheels = os.listdir(wheel_dir) assert len(wheels) == 1 assert wheels[0].endswith(".whl") @@ -282,6 +309,7 @@ def test_pip_wheel_fail(script: PipTestEnvironment, data: TestData) -> None: """ result = script.pip( "wheel", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -304,6 +332,7 @@ def test_pip_wheel_source_deps(script: PipTestEnvironment, data: TestData) -> No # 'requires_source' is a wheel that depends on the 'source' project result = script.pip( "wheel", + "--no-build-isolation", "--no-index", "-f", data.find_links, @@ -321,7 +350,7 @@ def test_wheel_package_with_latin1_setup( """Create a wheel from a package with latin-1 encoded setup.py.""" pkg_to_wheel = data.packages.joinpath("SetupPyLatin1") - result = script.pip("wheel", pkg_to_wheel) + result = script.pip("wheel", "--no-build-isolation", pkg_to_wheel) assert "Successfully built SetupPyUTF8" in result.stdout @@ -419,7 +448,9 @@ def test_legacy_wheels_are_not_confused_with_other_files( pkg_to_wheel = data.src / "simplewheel-1.0" add_files_to_dist_directory(pkg_to_wheel) - result = script.pip("wheel", pkg_to_wheel, "-w", script.scratch_path) + result = script.pip( + "wheel", "--no-build-isolation", pkg_to_wheel, "-w", script.scratch_path + ) assert "Installing build dependencies" not in result.stdout, result.stdout wheel_file_name = f"simplewheel-1.0-py{pyversion[0]}-none-any.whl" diff --git a/tests/lib/__init__.py b/tests/lib/__init__.py index 78fe3604480..1b9d1b96350 100644 --- a/tests/lib/__init__.py +++ b/tests/lib/__init__.py @@ -14,6 +14,7 @@ from contextlib import contextmanager from hashlib import sha256 from io import BytesIO, StringIO +from pathlib import Path from textwrap import dedent from typing import Any, AnyStr, Callable, Literal, Protocol, Union, cast from urllib.request import pathname2url @@ -28,11 +29,11 @@ from pip._internal.index.collector import LinkCollector from pip._internal.index.package_finder import PackageFinder from pip._internal.locations import get_major_minor_version +from pip._internal.models.direct_url import DIRECT_URL_METADATA_NAME, DirectUrl from pip._internal.models.search_scope import SearchScope from pip._internal.models.selection_prefs import SelectionPreferences from pip._internal.models.target_python import TargetPython from pip._internal.network.session import PipSession -from pip._internal.utils.egg_link import _egg_link_names from tests.lib.venv import VirtualEnvironment from tests.lib.wheel import make_wheel @@ -50,10 +51,6 @@ _FilesState = dict[str, Union[FoundDir, FoundFile]] -def assert_paths_equal(actual: str, expected: str) -> None: - assert os.path.normpath(actual) == os.path.normpath(expected) - - def create_file(path: str, contents: str | None = None) -> None: """Create a file on the path, with the given contents""" from pip._internal.utils.misc import ensure_dir @@ -292,90 +289,71 @@ def files_updated(self) -> FoundFiles: def files_deleted(self) -> FoundFiles: return FoundFiles(self._impl.files_deleted) - def _get_egg_link_path_created(self, egg_link_paths: list[str]) -> str | None: - for egg_link_path in egg_link_paths: - if egg_link_path in self.files_created: - return egg_link_path + def get_created_direct_url_path(self, pkg: str) -> Path | None: + dist_info_prefix = canonicalize_name(pkg).replace("-", "_") + "-" + for filename in self.files_created: + if ( + filename.name == DIRECT_URL_METADATA_NAME + and filename.parent.name.endswith(".dist-info") + and filename.parent.name.startswith(dist_info_prefix) + ): + return self.test_env.base_path / filename + return None + + def get_created_direct_url(self, pkg: str) -> DirectUrl | None: + direct_url_path = self.get_created_direct_url_path(pkg) + if direct_url_path: + with open(direct_url_path) as f: + return DirectUrl.from_json(f.read()) return None def assert_installed( self, pkg_name: str, + *, + dist_name: str | None = None, editable: bool = True, + editable_vcs: bool = True, with_files: list[str] | None = None, without_files: list[str] | None = None, - without_egg_link: bool = False, - use_user_site: bool = False, sub_dir: str | None = None, ) -> None: + if dist_name is None: + dist_name = pkg_name with_files = with_files or [] without_files = without_files or [] e = self.test_env - if editable: - pkg_dir = e.venv / "src" / canonicalize_name(pkg_name) + if editable and editable_vcs: + pkg_dir = e.venv / "src" / canonicalize_name(dist_name) # If package was installed in a sub directory if sub_dir: pkg_dir = pkg_dir / sub_dir + elif editable and not editable_vcs: + pkg_dir = None + assert not with_files + assert not without_files else: - without_egg_link = True pkg_dir = e.site_packages / pkg_name - if use_user_site: - egg_link_paths = [ - e.user_site / egg_link_name - for egg_link_name in _egg_link_names(pkg_name) - ] - else: - egg_link_paths = [ - e.site_packages / egg_link_name - for egg_link_name in _egg_link_names(pkg_name) - ] - - egg_link_path_created = self._get_egg_link_path_created(egg_link_paths) - if without_egg_link: - if egg_link_path_created: + direct_url = self.get_created_direct_url(dist_name) + if not editable: + if direct_url and direct_url.is_local_editable(): raise TestFailure( - f"unexpected egg link file created: {egg_link_path_created!r}\n" + "unexpected editable direct_url.json created: " + f"{self.get_created_direct_url_path(dist_name)!r}\n" f"{self}" ) else: - if not egg_link_path_created: + if not direct_url or not direct_url.is_local_editable(): raise TestFailure( - f"expected egg link file missing: {egg_link_paths!r}\n{self}" - ) - - egg_link_file = self.files_created[egg_link_path_created] - egg_link_contents = egg_link_file.bytes.replace(os.linesep, "\n") - - # FIXME: I don't understand why there's a trailing . here - if not ( - egg_link_contents.endswith("\n.") - and egg_link_contents[:-2].endswith(os.fspath(pkg_dir)) - ): - expected_ending = f"{pkg_dir}\n." - raise TestFailure( - textwrap.dedent( - f""" - Incorrect egg_link file {egg_link_file!r} - Expected ending: {expected_ending!r} - ------- Actual contents ------- - {egg_link_contents!r} - ------------------------------- - """ - ).strip() + f"{dist_name!r} not installed as editable: direct_url.json " + "not found or not editable\n" + f"{self.get_created_direct_url_path(dist_name)!r}\n" + f"{self}" ) - if use_user_site: - pth_file = e.user_site / "easy-install.pth" - else: - pth_file = e.site_packages / "easy-install.pth" - - if (pth_file in self.files_updated) == without_egg_link: - maybe = "" if without_egg_link else "not " - raise TestFailure(f"{pth_file} unexpectedly {maybe}updated by install") - - if (pkg_dir in self.files_created) == (os.curdir in without_files): + if pkg_dir and (pkg_dir in self.files_created) == (os.curdir in without_files): maybe = "not " if os.curdir in without_files else "" files = sorted(p.as_posix() for p in self.files_created) raise TestFailure( @@ -728,6 +706,7 @@ def pip_install_local( ) -> TestPipResult: return self.pip( "install", + "--no-build-isolation", "--no-index", "--find-links", pathlib.Path(DATA_DIR, "packages").as_uri(), @@ -756,6 +735,17 @@ def assert_not_installed(self, *args: str) -> None: expected = {canonicalize_name(k) for k in args} assert not (expected & installed), f"{expected!r} contained in {installed!r}" + def assert_installed_editable(self, dist_name: str) -> None: + dist_name = canonicalize_name(dist_name) + ret = self.pip("list", "--format=json") + installed = json.loads(ret.stdout) + assert any( + x + for x in installed + if canonicalize_name(x["name"]) == dist_name + and x.get("editable_project_location") + ) + # FIXME ScriptTest does something similar, but only within a single # ProcResult; this generalizes it so states can be compared across @@ -1224,8 +1214,7 @@ def create_basic_sdist_for_package( version: str, extra_files: dict[str, str] | None = None, *, - fails_egg_info: bool = False, - fails_bdist_wheel: bool = False, + fails_build: bool = False, depends: list[str] | None = None, setup_py_prelude: str = "", ) -> pathlib.Path: @@ -1237,14 +1226,10 @@ def create_basic_sdist_for_package( {setup_py_prelude} - fails_bdist_wheel = {fails_bdist_wheel!r} - fails_egg_info = {fails_egg_info!r} - - if fails_egg_info and "egg_info" in sys.argv: - raise Exception("Simulated failure for generating metadata.") + fails_build = {fails_build!r} - if fails_bdist_wheel and "bdist_wheel" in sys.argv: - raise Exception("Simulated failure for building a wheel.") + if fails_build: + raise Exception("Simulated build failure.") setup(name={name!r}, version={version!r}, install_requires={depends!r}) @@ -1254,8 +1239,7 @@ def create_basic_sdist_for_package( version=version, depends=depends or [], setup_py_prelude=setup_py_prelude, - fails_bdist_wheel=fails_bdist_wheel, - fails_egg_info=fails_egg_info, + fails_build=fails_build, ), } diff --git a/tests/lib/direct_url.py b/tests/lib/direct_url.py deleted file mode 100644 index 3049da9c1d2..00000000000 --- a/tests/lib/direct_url.py +++ /dev/null @@ -1,27 +0,0 @@ -from __future__ import annotations - -import os -import re -from pathlib import Path - -from pip._internal.models.direct_url import DIRECT_URL_METADATA_NAME, DirectUrl - -from tests.lib import TestPipResult - - -def get_created_direct_url_path(result: TestPipResult, pkg: str) -> Path | None: - direct_url_metadata_re = re.compile( - pkg + r"-[\d\.]+\.dist-info." + DIRECT_URL_METADATA_NAME + r"$" - ) - for filename in result.files_created: - if direct_url_metadata_re.search(os.fspath(filename)): - return result.test_env.base_path / filename - return None - - -def get_created_direct_url(result: TestPipResult, pkg: str) -> DirectUrl | None: - direct_url_path = get_created_direct_url_path(result, pkg) - if direct_url_path: - with open(direct_url_path) as f: - return DirectUrl.from_json(f.read()) - return None diff --git a/tests/unit/resolution_resolvelib/conftest.py b/tests/unit/resolution_resolvelib/conftest.py index ee2633afac9..436abddbd4d 100644 --- a/tests/unit/resolution_resolvelib/conftest.py +++ b/tests/unit/resolution_resolvelib/conftest.py @@ -35,7 +35,7 @@ def finder(data: TestData) -> PackageFinder: def preparer(finder: PackageFinder) -> Iterator[RequirementPreparer]: session = PipSession() rc = InstallCommand("x", "y") - o = rc.parse_args([]) + o = rc.parse_args(["--no-build-isolation"]) with global_tempdir_manager(): with TempDirectory() as tmp: diff --git a/tests/unit/test_options.py b/tests/unit/test_options.py index c996bee8eca..1052558ab2f 100644 --- a/tests/unit/test_options.py +++ b/tests/unit/test_options.py @@ -198,91 +198,6 @@ def test_cache_dir__PIP_NO_CACHE_DIR_invalid__with_no_cache_dir( main(["--no-cache-dir", "fake"]) -class TestUsePEP517Options: - """ - Test options related to using --use-pep517. - """ - - def parse_args(self, args: list[str]) -> Values: - # We use DownloadCommand since that is one of the few Command - # classes with the use_pep517 options. - command = create_command("download") - options, args = command.parse_args(args) - - return options - - def test_no_option(self) -> None: - """ - Test passing no option. - """ - options = self.parse_args([]) - assert options.use_pep517 is None - - def test_use_pep517(self) -> None: - """ - Test passing --use-pep517. - """ - options = self.parse_args(["--use-pep517"]) - assert options.use_pep517 is True - - def test_no_use_pep517(self) -> None: - """ - Test passing --no-use-pep517. - """ - options = self.parse_args(["--no-use-pep517"]) - assert options.use_pep517 is False - - def test_PIP_USE_PEP517_true(self, monkeypatch: pytest.MonkeyPatch) -> None: - """ - Test setting PIP_USE_PEP517 to "true". - """ - monkeypatch.setenv("PIP_USE_PEP517", "true") - options = self.parse_args([]) - # This is an int rather than a boolean because strtobool() in pip's - # configuration code returns an int. - assert options.use_pep517 == 1 - - def test_PIP_USE_PEP517_false(self, monkeypatch: pytest.MonkeyPatch) -> None: - """ - Test setting PIP_USE_PEP517 to "false". - """ - monkeypatch.setenv("PIP_USE_PEP517", "false") - options = self.parse_args([]) - # This is an int rather than a boolean because strtobool() in pip's - # configuration code returns an int. - assert options.use_pep517 == 0 - - def test_use_pep517_and_PIP_USE_PEP517_false( - self, monkeypatch: pytest.MonkeyPatch - ) -> None: - """ - Test passing --use-pep517 and setting PIP_USE_PEP517 to "false". - """ - monkeypatch.setenv("PIP_USE_PEP517", "false") - options = self.parse_args(["--use-pep517"]) - assert options.use_pep517 is True - - def test_no_use_pep517_and_PIP_USE_PEP517_true( - self, monkeypatch: pytest.MonkeyPatch - ) -> None: - """ - Test passing --no-use-pep517 and setting PIP_USE_PEP517 to "true". - """ - monkeypatch.setenv("PIP_USE_PEP517", "true") - options = self.parse_args(["--no-use-pep517"]) - assert options.use_pep517 is False - - def test_PIP_NO_USE_PEP517( - self, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str] - ) -> None: - """ - Test setting PIP_NO_USE_PEP517, which isn't allowed. - """ - monkeypatch.setenv("PIP_NO_USE_PEP517", "true") - with assert_option_error(capsys, expected="--no-use-pep517 error"): - self.parse_args([]) - - class TestOptionsInterspersed(AddFakeCommandMixin): def test_general_option_after_subcommand(self) -> None: # FakeCommand intentionally returns the wrong type. diff --git a/tests/unit/test_pep517.py b/tests/unit/test_pep517.py index 27008de79c2..86e6ca70e34 100644 --- a/tests/unit/test_pep517.py +++ b/tests/unit/test_pep517.py @@ -4,72 +4,9 @@ import pytest -from pip._internal.exceptions import InstallationError, InvalidPyProjectBuildRequires +from pip._internal.exceptions import InvalidPyProjectBuildRequires from pip._internal.req import InstallRequirement -from tests.lib import TestData - - -@pytest.mark.parametrize( - "source, expected", - [ - ("pep517_setup_and_pyproject", True), - ("pep517_setup_only", False), - ("pep517_pyproject_only", True), - ], -) -def test_use_pep517(shared_data: TestData, source: str, expected: bool) -> None: - """ - Test that we choose correctly between PEP 517 and legacy code paths - """ - src = shared_data.src.joinpath(source) - req = InstallRequirement(None, None) - req.source_dir = os.fspath(src) # make req believe it has been unpacked - req.load_pyproject_toml() - assert req.use_pep517 is expected - - -def test_use_pep517_rejects_setup_cfg_only(shared_data: TestData) -> None: - """ - Test that projects with setup.cfg but no pyproject.toml are rejected. - """ - src = shared_data.src.joinpath("pep517_setup_cfg_only") - req = InstallRequirement(None, None) - req.source_dir = os.fspath(src) # make req believe it has been unpacked - with pytest.raises(InstallationError) as e: - req.load_pyproject_toml() - err_msg = e.value.args[0] - assert ( - "does not appear to be a Python project: " - "neither 'setup.py' nor 'pyproject.toml' found" in err_msg - ) - - -@pytest.mark.parametrize( - "source, msg", - [ - ("pep517_setup_and_pyproject", "specifies a build backend"), - ("pep517_pyproject_only", "does not have a setup.py"), - ], -) -def test_disabling_pep517_invalid(shared_data: TestData, source: str, msg: str) -> None: - """ - Test that we fail if we try to disable PEP 517 when it's not acceptable - """ - src = shared_data.src.joinpath(source) - req = InstallRequirement(None, None) - req.source_dir = os.fspath(src) # make req believe it has been unpacked - - # Simulate --no-use-pep517 - req.use_pep517 = False - - with pytest.raises(InstallationError) as e: - req.load_pyproject_toml() - - err_msg = e.value.args[0] - assert "Disabling PEP 517 processing is invalid" in err_msg - assert msg in err_msg - @pytest.mark.parametrize( "spec", [("./foo",), ("git+https://example.com/pkg@dev#egg=myproj",)] diff --git a/tests/unit/test_req.py b/tests/unit/test_req.py index 0a245fab6a3..38f9207de82 100644 --- a/tests/unit/test_req.py +++ b/tests/unit/test_req.py @@ -90,11 +90,11 @@ def _basic_resolver( finder: PackageFinder, require_hashes: bool = False, wheel_cache: WheelCache | None = None, + build_isolation: bool = True, ) -> Iterator[Resolver]: make_install_req = partial( install_req_from_req_string, isolated=False, - use_pep517=None, ) session = PipSession() @@ -104,7 +104,7 @@ def _basic_resolver( build_dir=os.path.join(self.tempdir, "build"), src_dir=os.path.join(self.tempdir, "src"), download_dir=None, - build_isolation=True, + build_isolation=build_isolation, build_isolation_installer=installer, check_build_deps=False, build_tracker=tracker, @@ -166,7 +166,7 @@ def test_environment_marker_extras(self, data: TestData) -> None: req.user_supplied = True reqset.add_unnamed_requirement(req) finder = make_test_finder(find_links=[data.find_links]) - with self._basic_resolver(finder) as resolver: + with self._basic_resolver(finder, build_isolation=False) as resolver: reqset = resolver.resolve(reqset.all_requirements, True) assert not reqset.has_requirement("simple") @@ -319,7 +319,9 @@ def test_unhashed_deps_on_require_hashes(self, data: TestData) -> None: ) ) - with self._basic_resolver(finder, require_hashes=True) as resolver: + with self._basic_resolver( + finder, require_hashes=True, build_isolation=False + ) as resolver: with pytest.raises( HashErrors, match=( @@ -360,7 +362,7 @@ def test_hashed_deps_on_require_hashes(self) -> None: def test_download_info_find_links(self, data: TestData) -> None: """Test that download_info is set for requirements via find_links.""" finder = make_test_finder(find_links=[data.find_links]) - with self._basic_resolver(finder) as resolver: + with self._basic_resolver(finder, build_isolation=False) as resolver: ireq = get_processed_req_from_line("simple") reqset = resolver.resolve([ireq], True) assert len(reqset.all_requirements) == 1 @@ -385,7 +387,7 @@ def test_download_info_index_url(self) -> None: def test_download_info_web_archive(self) -> None: """Test that download_info is set for requirements from a web archive.""" finder = make_test_finder() - with self._basic_resolver(finder) as resolver: + with self._basic_resolver(finder, build_isolation=False) as resolver: ireq = get_processed_req_from_line( "pip-test-package @ " "https://github.com/pypa/pip-test-package/tarball/0.1.1" @@ -495,7 +497,7 @@ def test_download_info_local_wheel(self, data: TestData) -> None: 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: + with self._basic_resolver(finder, build_isolation=False) as resolver: ireq_url = data.packages.joinpath("FSPkg").as_uri() ireq = get_processed_req_from_line(f"FSPkg @ {ireq_url}") reqset = resolver.resolve([ireq], True) @@ -508,7 +510,7 @@ def test_download_info_local_dir(self, data: TestData) -> None: 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: + with self._basic_resolver(finder, build_isolation=False) as resolver: 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) @@ -523,7 +525,7 @@ def test_download_info_local_editable_dir(self, data: TestData) -> None: def test_download_info_vcs(self) -> None: """Test that download_info is set for requirements from git.""" finder = make_test_finder() - with self._basic_resolver(finder) as resolver: + with self._basic_resolver(finder, build_isolation=False) as resolver: ireq = get_processed_req_from_line( "pip-test-package @ git+https://github.com/pypa/pip-test-package" ) @@ -792,9 +794,7 @@ def test_install_req_drop_extras(self, inp: str, out: str) -> None: # all else should be the same assert without_extras.link == req.link assert without_extras.markers == req.markers - assert without_extras.use_pep517 == req.use_pep517 assert without_extras.isolated == req.isolated - assert without_extras.global_options == req.global_options assert without_extras.hash_options == req.hash_options assert without_extras.constraint == req.constraint assert without_extras.config_settings == req.config_settings @@ -841,9 +841,7 @@ def test_install_req_extend_extras( # all else should be the same assert extended.link == req.link assert extended.markers == req.markers - assert extended.use_pep517 == req.use_pep517 assert extended.isolated == req.isolated - assert extended.global_options == req.global_options assert extended.hash_options == req.hash_options assert extended.constraint == req.constraint assert extended.config_settings == req.config_settings diff --git a/tests/unit/test_req_file.py b/tests/unit/test_req_file.py index 248171c7b5c..88fc4c58bb9 100644 --- a/tests/unit/test_req_file.py +++ b/tests/unit/test_req_file.py @@ -33,7 +33,7 @@ ) from pip._internal.req.req_install import InstallRequirement -from tests.lib import TestData, make_test_finder, requirements_file +from tests.lib import TestData, make_test_finder @pytest.fixture @@ -422,13 +422,9 @@ def test_recursive_relative_requirements_file( list(parse_requirements(filename=str(root_req_file), session=session)) def test_options_on_a_requirement_line(self, line_processor: LineProcessor) -> None: - line = ( - 'SomeProject --global-option="yo3" --global-option "yo4" ' - '--config-settings="yo3=yo4" --config-settings "yo1=yo2"' - ) + line = 'SomeProject --config-settings="yo3=yo4" --config-settings "yo1=yo2"' filename = "filename" req = line_processor(line, filename, 1)[0] - assert req.global_options == ["yo3", "yo4"] assert req.config_settings == {"yo3": "yo4", "yo1": "yo2"} def test_hash_options(self, line_processor: LineProcessor) -> None: @@ -937,29 +933,6 @@ def test_req_file_no_finder(self, tmpdir: Path) -> None: parse_reqfile(tmpdir.joinpath("req.txt"), session=PipSession()) - def test_install_requirements_with_options( - self, - tmpdir: Path, - finder: PackageFinder, - session: PipSession, - options: mock.Mock, - ) -> None: - global_option = "--dry-run" - - content = f""" - --only-binary :all: - INITools==2.0 --global-option="{global_option}" - """ - - with requirements_file(content, tmpdir) as reqs_file: - req = next( - parse_reqfile( - reqs_file.resolve(), finder=finder, options=options, session=session - ) - ) - - assert req.global_options == [global_option] - @pytest.mark.parametrize( "raw_req_file,expected_name,expected_spec", [ diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index 147728b4e97..a9f7beea296 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -51,7 +51,6 @@ split_auth_netloc_from_url, tabulate, ) -from pip._internal.utils.setuptools_build import make_setuptools_shim_args class Tests_EgglinkPath: @@ -932,59 +931,6 @@ def test_deprecated_message_reads_well_future() -> None: ) -def test_make_setuptools_shim_args() -> None: - # Test all arguments at once, including the overall ordering. - args = make_setuptools_shim_args( - "/dir/path/setup.py", - global_options=["--some", "--option"], - no_user_config=True, - unbuffered_output=True, - ) - - assert args[1:3] == ["-u", "-c"] - assert args[4:] == ["--some", "--option", "--no-user-cfg"] - - shim = args[3] - # Spot-check key aspects of the command string. - assert "import setuptools" in shim - assert "'/dir/path/setup.py'" in args[3] - assert "sys.argv[0] = __file__" in args[3] - - -@pytest.mark.parametrize("global_options", [None, [], ["--some", "--option"]]) -def test_make_setuptools_shim_args__global_options( - global_options: list[str] | None, -) -> None: - args = make_setuptools_shim_args( - "/dir/path/setup.py", - global_options=global_options, - ) - - if global_options: - assert len(args) == 5 - for option in global_options: - assert option in args - else: - assert len(args) == 3 - - -@pytest.mark.parametrize("no_user_config", [False, True]) -def test_make_setuptools_shim_args__no_user_config(no_user_config: bool) -> None: - args = make_setuptools_shim_args( - "/dir/path/setup.py", - no_user_config=no_user_config, - ) - assert ("--no-user-cfg" in args) == no_user_config - - -@pytest.mark.parametrize("unbuffered_output", [False, True]) -def test_make_setuptools_shim_args__unbuffered_output(unbuffered_output: bool) -> None: - args = make_setuptools_shim_args( - "/dir/path/setup.py", unbuffered_output=unbuffered_output - ) - assert ("-u" in args) == unbuffered_output - - @pytest.mark.parametrize( "isatty,no_stdin,expected", [ diff --git a/tests/unit/test_wheel.py b/tests/unit/test_wheel.py index 96dc424f1c4..e0ac6497b78 100644 --- a/tests/unit/test_wheel.py +++ b/tests/unit/test_wheel.py @@ -3,7 +3,6 @@ from __future__ import annotations import csv -import logging import os import pathlib import sys @@ -26,7 +25,6 @@ DirectUrl, ) from pip._internal.models.scheme import Scheme -from pip._internal.operations.build.wheel_legacy import get_legacy_build_wheel_path from pip._internal.operations.install import wheel from pip._internal.operations.install.wheel import ( InstalledCSVRow, @@ -37,68 +35,10 @@ 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 import DATA_DIR, TestData from tests.lib.wheel import make_wheel -def call_get_legacy_build_wheel_path( - caplog: pytest.LogCaptureFixture, names: list[str] -) -> str | None: - wheel_path = get_legacy_build_wheel_path( - names=names, - temp_dir="/tmp/abcd", - name="pendulum", - command_args=["arg1", "arg2"], - command_output="output line 1\noutput line 2\n", - ) - return wheel_path - - -def test_get_legacy_build_wheel_path(caplog: pytest.LogCaptureFixture) -> None: - actual = call_get_legacy_build_wheel_path(caplog, names=["name"]) - assert actual is not None - assert_paths_equal(actual, "/tmp/abcd/name") - assert not caplog.records - - -def test_get_legacy_build_wheel_path__no_names( - caplog: pytest.LogCaptureFixture, -) -> None: - caplog.set_level(logging.INFO) - actual = call_get_legacy_build_wheel_path(caplog, names=[]) - assert actual is None - assert len(caplog.records) == 1 - record = caplog.records[0] - assert record.levelname == "WARNING" - assert record.message.splitlines() == [ - "Legacy build of wheel for 'pendulum' created no files.", - "Command arguments: arg1 arg2", - "Command output: [use --verbose to show]", - ] - - -def test_get_legacy_build_wheel_path__multiple_names( - caplog: pytest.LogCaptureFixture, -) -> None: - caplog.set_level(logging.INFO) - # Deliberately pass the names in non-sorted order. - actual = call_get_legacy_build_wheel_path( - caplog, - names=["name2", "name1"], - ) - assert actual is not None - assert_paths_equal(actual, "/tmp/abcd/name1") - assert len(caplog.records) == 1 - record = caplog.records[0] - assert record.levelname == "WARNING" - assert record.message.splitlines() == [ - "Legacy build of wheel for 'pendulum' created more than one file.", - "Filenames (choosing first): ['name1', 'name2']", - "Command arguments: arg1 arg2", - "Command output: [use --verbose to show]", - ] - - @pytest.mark.parametrize( "console_scripts", [ diff --git a/tests/unit/test_wheel_builder.py b/tests/unit/test_wheel_builder.py index 0547ac818bc..1fc9e789256 100644 --- a/tests/unit/test_wheel_builder.py +++ b/tests/unit/test_wheel_builder.py @@ -1,6 +1,5 @@ from __future__ import annotations -import logging import os from dataclasses import dataclass from pathlib import Path @@ -10,7 +9,6 @@ from pip._internal import wheel_builder from pip._internal.models.link import Link -from pip._internal.operations.build.wheel_legacy import format_command_result from pip._internal.req.req_install import InstallRequirement from pip._internal.vcs.git import Git @@ -43,52 +41,13 @@ class ReqMock: link: Link | None = None constraint: bool = False source_dir: str | None = "/tmp/pip-install-123/pendulum" - use_pep517: bool = True supports_pyproject_editable: bool = False @pytest.mark.parametrize( "req, expected", [ - # We build, whether pep 517 is enabled or not. - (ReqMock(use_pep517=True), True), - (ReqMock(use_pep517=False), True), - # We don't build reqs that are already wheels. - (ReqMock(is_wheel=True), False), - # We build editables if the backend supports PEP 660. - (ReqMock(editable=True, use_pep517=False), False), - ( - ReqMock(editable=True, use_pep517=True, supports_pyproject_editable=True), - True, - ), - ( - ReqMock(editable=True, use_pep517=True, supports_pyproject_editable=False), - False, - ), - # By default (i.e. when binaries are allowed), VCS requirements - # should be built in install mode. - ( - ReqMock(link=Link("git+https://g.c/org/repo"), use_pep517=True), - True, - ), - ( - ReqMock(link=Link("git+https://g.c/org/repo"), use_pep517=False), - True, - ), - ], -) -def test_should_build_for_install_command(req: ReqMock, expected: bool) -> None: - should_build = wheel_builder.should_build_for_install_command( - cast(InstallRequirement, req), - ) - assert should_build is expected - - -@pytest.mark.parametrize( - "req, expected", - [ - (ReqMock(editable=True, use_pep517=False), False), - (ReqMock(editable=True, use_pep517=True), False), + (ReqMock(editable=True), False), (ReqMock(source_dir=None), False), (ReqMock(link=Link("git+https://g.c/org/repo")), False), (ReqMock(link=Link("https://g.c/dist.tgz")), False), @@ -112,56 +71,3 @@ def test_should_cache_git_sha(tmpdir: Path) -> None: url = "git+https://g.c/o/r@master#egg=mypkg" req = ReqMock(link=Link(url), source_dir=repo_path) assert not wheel_builder._should_cache(cast(InstallRequirement, req)) - - -def test_format_command_result__INFO(caplog: pytest.LogCaptureFixture) -> None: - caplog.set_level(logging.INFO) - actual = format_command_result( - # Include an argument with a space to test argument quoting. - command_args=["arg1", "second arg"], - command_output="output line 1\noutput line 2\n", - ) - assert actual.splitlines() == [ - "Command arguments: arg1 'second arg'", - "Command output: [use --verbose to show]", - ] - - -@pytest.mark.parametrize( - "command_output", - [ - # Test trailing newline. - "output line 1\noutput line 2\n", - # Test no trailing newline. - "output line 1\noutput line 2", - ], -) -def test_format_command_result__DEBUG( - caplog: pytest.LogCaptureFixture, command_output: str -) -> None: - caplog.set_level(logging.DEBUG) - actual = format_command_result( - command_args=["arg1", "arg2"], - command_output=command_output, - ) - assert actual.splitlines() == [ - "Command arguments: arg1 arg2", - "Command output:", - "output line 1", - "output line 2", - ] - - -@pytest.mark.parametrize("log_level", ["DEBUG", "INFO"]) -def test_format_command_result__empty_output( - caplog: pytest.LogCaptureFixture, log_level: str -) -> None: - caplog.set_level(log_level) - actual = format_command_result( - command_args=["arg1", "arg2"], - command_output="", - ) - assert actual.splitlines() == [ - "Command arguments: arg1 arg2", - "Command output: None", - ]