Deprecate install-location-related options in --install-option

This commit is contained in:
Chris Hunt 2019-11-16 20:42:27 -05:00
parent 55a943e556
commit b8f626ace6
4 changed files with 107 additions and 1 deletions

1
news/7309.removal Normal file
View File

@ -0,0 +1 @@
Deprecate passing install-location-related options via ``--install-option``.

View File

@ -32,6 +32,8 @@ from pip._internal.locations import distutils_scheme
from pip._internal.operations.check import check_install_conflicts
from pip._internal.req import RequirementSet, install_given_reqs
from pip._internal.req.req_tracker import get_requirement_tracker
from pip._internal.utils.deprecation import deprecated
from pip._internal.utils.distutils_args import parse_distutils_args
from pip._internal.utils.filesystem import check_path_owner, test_writable_dir
from pip._internal.utils.misc import (
ensure_dir,
@ -46,7 +48,7 @@ from pip._internal.wheel_builder import WheelBuilder
if MYPY_CHECK_RUNNING:
from optparse import Values
from typing import Any, List, Optional
from typing import Any, Iterable, List, Optional
from pip._internal.models.format_control import FormatControl
from pip._internal.req.req_install import InstallRequirement
@ -355,6 +357,11 @@ class InstallCommand(RequirementCommand):
requirement_set, args, options, finder, session,
wheel_cache
)
warn_deprecated_install_options(
requirement_set, options.install_options
)
preparer = self.make_requirement_preparer(
temp_build_dir=directory,
options=options,
@ -660,6 +667,61 @@ def decide_user_install(
return True
def warn_deprecated_install_options(requirement_set, options):
# type: (RequirementSet, Optional[List[str]]) -> None
"""If any location-changing --install-option arguments were passed for
requirements or on the command-line, then show a deprecation warning.
"""
def format_options(option_names):
# type: (Iterable[str]) -> List[str]
return ["--{}".format(name.replace("_", "-")) for name in option_names]
requirements = (
requirement_set.unnamed_requirements +
list(requirement_set.requirements.values())
)
offenders = []
for requirement in requirements:
install_options = requirement.options.get("install_options", [])
location_options = parse_distutils_args(install_options)
if location_options:
offenders.append(
"{!r} from {}".format(
format_options(location_options.keys()), requirement
)
)
if options:
location_options = parse_distutils_args(options)
if location_options:
offenders.append(
"{!r} from command line".format(
format_options(location_options.keys())
)
)
if not offenders:
return
deprecated(
reason=(
"Location-changing options found in --install-option: {}. "
"This configuration may cause unexpected behavior and is "
"unsupported.".format(
"; ".join(offenders)
)
),
replacement=(
"using pip-level options like --user, --prefix, --root, and "
"--target"
),
gone_in="20.2",
issue=7309,
)
def create_env_error_message(error, show_traceback, using_user_site):
"""Format an error message for an EnvironmentError

View File

@ -536,6 +536,7 @@ def test_install_options_local_to_package(script, data):
'install',
'--no-index', '-f', data.find_links,
'-r', reqs_file,
expect_stderr=True,
)
simple = test_simple / 'lib' / 'python' / 'simple'

View File

@ -2,12 +2,16 @@ import errno
import pytest
from mock import Mock, call, patch
from pip._vendor.packaging.requirements import Requirement
from pip._internal.commands.install import (
build_wheels,
create_env_error_message,
decide_user_install,
warn_deprecated_install_options,
)
from pip._internal.req.req_install import InstallRequirement
from pip._internal.req.req_set import RequirementSet
class TestWheelCache:
@ -102,6 +106,44 @@ class TestDecideUserInstall:
assert decide_user_install(use_user_site=None) is result
def test_deprecation_notice_for_pip_install_options(recwarn):
install_options = ["--prefix=/hello"]
req_set = RequirementSet()
warn_deprecated_install_options(req_set, install_options)
assert len(recwarn) == 1
message = recwarn[0].message.args[0]
assert "['--prefix'] from command line" in message
def test_deprecation_notice_for_requirement_options(recwarn):
install_options = []
req_set = RequirementSet()
bad_named_req_options = {"install_options": ["--home=/wow"]}
bad_named_req = InstallRequirement(
Requirement("hello"), "requirements.txt", options=bad_named_req_options
)
req_set.add_named_requirement(bad_named_req)
bad_unnamed_req_options = {"install_options": ["--install-lib=/lib"]}
bad_unnamed_req = InstallRequirement(
None, "requirements2.txt", options=bad_unnamed_req_options
)
req_set.add_unnamed_requirement(bad_unnamed_req)
warn_deprecated_install_options(req_set, install_options)
assert len(recwarn) == 1
message = recwarn[0].message.args[0]
assert (
"['--install-lib'] from <InstallRequirement> (from requirements2.txt)"
in message
)
assert "['--home'] from hello (from requirements.txt)" in message
@pytest.mark.parametrize('error, show_traceback, using_user_site, expected', [
# show_traceback = True, using_user_site = True
(EnvironmentError("Illegal byte sequence"), True, True, 'Could not install'