mirror of https://github.com/pypa/pip
Merge branch 'master' into remove-obsolete-git-urls
This commit is contained in:
commit
d166adaee5
|
@ -384,18 +384,18 @@ where ``setup.py`` is not in the root of project, the "subdirectory" component
|
||||||
is used. The value of the "subdirectory" component should be a path starting
|
is used. The value of the "subdirectory" component should be a path starting
|
||||||
from the root of the project to where ``setup.py`` is located.
|
from the root of the project to where ``setup.py`` is located.
|
||||||
|
|
||||||
So if your repository layout is:
|
If your repository layout is::
|
||||||
|
|
||||||
- pkg_dir/
|
pkg_dir
|
||||||
|
├── setup.py # setup.py for package "pkg"
|
||||||
|
└── some_module.py
|
||||||
|
other_dir
|
||||||
|
└── some_file
|
||||||
|
some_other_file
|
||||||
|
|
||||||
- setup.py # setup.py for package ``pkg``
|
Then, to install from this repository, the syntax would be::
|
||||||
- some_module.py
|
|
||||||
- other_dir/
|
|
||||||
|
|
||||||
- some_file
|
$ pip install -e "vcs+protocol://repo_url/#egg=pkg&subdirectory=pkg_dir"
|
||||||
- some_other_file
|
|
||||||
|
|
||||||
You'll need to use ``pip install -e "vcs+protocol://repo_url/#egg=pkg&subdirectory=pkg_dir"``.
|
|
||||||
|
|
||||||
|
|
||||||
Git
|
Git
|
||||||
|
@ -940,6 +940,17 @@ Examples
|
||||||
|
|
||||||
$ pip install --pre SomePackage
|
$ pip install --pre SomePackage
|
||||||
|
|
||||||
|
|
||||||
|
#. Install packages from source.
|
||||||
|
|
||||||
|
Do not use any binary packages::
|
||||||
|
|
||||||
|
$ pip install SomePackage1 SomePackage2 --no-binary :all:
|
||||||
|
|
||||||
|
Specify ``SomePackage1`` to be installed from source::
|
||||||
|
|
||||||
|
$ pip install SomePackage1 SomePackage2 --no-binary SomePackage1
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
.. [1] This is true with the exception that pip v7.0 and v7.0.1 required quotes
|
.. [1] This is true with the exception that pip v7.0 and v7.0.1 required quotes
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Clarify the usage of --no-binary command.
|
|
@ -0,0 +1 @@
|
||||||
|
Reject VCS URLs with an empty revision.
|
|
@ -0,0 +1 @@
|
||||||
|
Uninstallation no longer fails on trying to remove non-existent files.
|
|
@ -1 +0,0 @@
|
||||||
Catch ``subprocess.CalledProcessError`` when checking for the presence of executable within ``need_executable`` using pytest.
|
|
|
@ -475,12 +475,12 @@ def no_binary():
|
||||||
"--no-binary", dest="format_control", action="callback",
|
"--no-binary", dest="format_control", action="callback",
|
||||||
callback=_handle_no_binary, type="str",
|
callback=_handle_no_binary, type="str",
|
||||||
default=format_control,
|
default=format_control,
|
||||||
help="Do not use binary packages. Can be supplied multiple times, and "
|
help='Do not use binary packages. Can be supplied multiple times, and '
|
||||||
"each time adds to the existing value. Accepts either :all: to "
|
'each time adds to the existing value. Accepts either ":all:" to '
|
||||||
"disable all binary packages, :none: to empty the set, or one or "
|
'disable all binary packages, ":none:" to empty the set (notice '
|
||||||
"more package names with commas between them (no colons). Note "
|
'the colons), or one or more package names with commas between '
|
||||||
"that some packages are tricky to compile and may fail to "
|
'them (no colons). Note that some packages are tricky to compile '
|
||||||
"install when this option is used on them.",
|
'and may fail to install when this option is used on them.',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -491,12 +491,12 @@ def only_binary():
|
||||||
"--only-binary", dest="format_control", action="callback",
|
"--only-binary", dest="format_control", action="callback",
|
||||||
callback=_handle_only_binary, type="str",
|
callback=_handle_only_binary, type="str",
|
||||||
default=format_control,
|
default=format_control,
|
||||||
help="Do not use source packages. Can be supplied multiple times, and "
|
help='Do not use source packages. Can be supplied multiple times, and '
|
||||||
"each time adds to the existing value. Accepts either :all: to "
|
'each time adds to the existing value. Accepts either ":all:" to '
|
||||||
"disable all source packages, :none: to empty the set, or one or "
|
'disable all source packages, ":none:" to empty the set, or one '
|
||||||
"more package names with commas between them. Packages without "
|
'or more package names with commas between them. Packages '
|
||||||
"binary distributions will fail to install when this option is "
|
'without binary distributions will fail to install when this '
|
||||||
"used on them.",
|
'option is used on them.',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -255,7 +255,6 @@ class RequirementCommand(IndexGroupCommand):
|
||||||
make_install_req = partial(
|
make_install_req = partial(
|
||||||
install_req_from_req_string,
|
install_req_from_req_string,
|
||||||
isolated=options.isolated_mode,
|
isolated=options.isolated_mode,
|
||||||
wheel_cache=wheel_cache,
|
|
||||||
use_pep517=use_pep517,
|
use_pep517=use_pep517,
|
||||||
)
|
)
|
||||||
# The long import name and duplicated invocation is needed to convince
|
# The long import name and duplicated invocation is needed to convince
|
||||||
|
@ -266,6 +265,7 @@ class RequirementCommand(IndexGroupCommand):
|
||||||
return pip._internal.resolution.resolvelib.resolver.Resolver(
|
return pip._internal.resolution.resolvelib.resolver.Resolver(
|
||||||
preparer=preparer,
|
preparer=preparer,
|
||||||
finder=finder,
|
finder=finder,
|
||||||
|
wheel_cache=wheel_cache,
|
||||||
make_install_req=make_install_req,
|
make_install_req=make_install_req,
|
||||||
use_user_site=use_user_site,
|
use_user_site=use_user_site,
|
||||||
ignore_dependencies=options.ignore_dependencies,
|
ignore_dependencies=options.ignore_dependencies,
|
||||||
|
@ -279,6 +279,7 @@ class RequirementCommand(IndexGroupCommand):
|
||||||
return pip._internal.resolution.legacy.resolver.Resolver(
|
return pip._internal.resolution.legacy.resolver.Resolver(
|
||||||
preparer=preparer,
|
preparer=preparer,
|
||||||
finder=finder,
|
finder=finder,
|
||||||
|
wheel_cache=wheel_cache,
|
||||||
make_install_req=make_install_req,
|
make_install_req=make_install_req,
|
||||||
use_user_site=use_user_site,
|
use_user_site=use_user_site,
|
||||||
ignore_dependencies=options.ignore_dependencies,
|
ignore_dependencies=options.ignore_dependencies,
|
||||||
|
@ -295,7 +296,6 @@ class RequirementCommand(IndexGroupCommand):
|
||||||
options, # type: Values
|
options, # type: Values
|
||||||
finder, # type: PackageFinder
|
finder, # type: PackageFinder
|
||||||
session, # type: PipSession
|
session, # type: PipSession
|
||||||
wheel_cache, # type: Optional[WheelCache]
|
|
||||||
check_supported_wheels=True, # type: bool
|
check_supported_wheels=True, # type: bool
|
||||||
):
|
):
|
||||||
# type: (...) -> List[InstallRequirement]
|
# type: (...) -> List[InstallRequirement]
|
||||||
|
@ -313,7 +313,6 @@ class RequirementCommand(IndexGroupCommand):
|
||||||
req_to_add = install_req_from_parsed_requirement(
|
req_to_add = install_req_from_parsed_requirement(
|
||||||
parsed_req,
|
parsed_req,
|
||||||
isolated=options.isolated_mode,
|
isolated=options.isolated_mode,
|
||||||
wheel_cache=wheel_cache,
|
|
||||||
)
|
)
|
||||||
req_to_add.is_direct = True
|
req_to_add.is_direct = True
|
||||||
requirement_set.add_requirement(req_to_add)
|
requirement_set.add_requirement(req_to_add)
|
||||||
|
@ -322,7 +321,6 @@ class RequirementCommand(IndexGroupCommand):
|
||||||
req_to_add = install_req_from_line(
|
req_to_add = install_req_from_line(
|
||||||
req, None, isolated=options.isolated_mode,
|
req, None, isolated=options.isolated_mode,
|
||||||
use_pep517=options.use_pep517,
|
use_pep517=options.use_pep517,
|
||||||
wheel_cache=wheel_cache
|
|
||||||
)
|
)
|
||||||
req_to_add.is_direct = True
|
req_to_add.is_direct = True
|
||||||
requirement_set.add_requirement(req_to_add)
|
requirement_set.add_requirement(req_to_add)
|
||||||
|
@ -332,7 +330,6 @@ class RequirementCommand(IndexGroupCommand):
|
||||||
req,
|
req,
|
||||||
isolated=options.isolated_mode,
|
isolated=options.isolated_mode,
|
||||||
use_pep517=options.use_pep517,
|
use_pep517=options.use_pep517,
|
||||||
wheel_cache=wheel_cache
|
|
||||||
)
|
)
|
||||||
req_to_add.is_direct = True
|
req_to_add.is_direct = True
|
||||||
requirement_set.add_requirement(req_to_add)
|
requirement_set.add_requirement(req_to_add)
|
||||||
|
@ -345,7 +342,6 @@ class RequirementCommand(IndexGroupCommand):
|
||||||
req_to_add = install_req_from_parsed_requirement(
|
req_to_add = install_req_from_parsed_requirement(
|
||||||
parsed_req,
|
parsed_req,
|
||||||
isolated=options.isolated_mode,
|
isolated=options.isolated_mode,
|
||||||
wheel_cache=wheel_cache,
|
|
||||||
use_pep517=options.use_pep517
|
use_pep517=options.use_pep517
|
||||||
)
|
)
|
||||||
req_to_add.is_direct = True
|
req_to_add.is_direct = True
|
||||||
|
|
|
@ -107,13 +107,7 @@ class DownloadCommand(RequirementCommand):
|
||||||
globally_managed=True,
|
globally_managed=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
reqs = self.get_requirements(
|
reqs = self.get_requirements(args, options, finder, session)
|
||||||
args,
|
|
||||||
options,
|
|
||||||
finder,
|
|
||||||
session,
|
|
||||||
None
|
|
||||||
)
|
|
||||||
|
|
||||||
preparer = self.make_requirement_preparer(
|
preparer = self.make_requirement_preparer(
|
||||||
temp_build_dir=directory,
|
temp_build_dir=directory,
|
||||||
|
|
|
@ -299,7 +299,7 @@ class InstallCommand(RequirementCommand):
|
||||||
try:
|
try:
|
||||||
reqs = self.get_requirements(
|
reqs = self.get_requirements(
|
||||||
args, options, finder, session,
|
args, options, finder, session,
|
||||||
wheel_cache, check_supported_wheels=not options.target_dir,
|
check_supported_wheels=not options.target_dir,
|
||||||
)
|
)
|
||||||
|
|
||||||
warn_deprecated_install_options(
|
warn_deprecated_install_options(
|
||||||
|
|
|
@ -133,10 +133,7 @@ class WheelCommand(RequirementCommand):
|
||||||
globally_managed=True,
|
globally_managed=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
reqs = self.get_requirements(
|
reqs = self.get_requirements(args, options, finder, session)
|
||||||
args, options, finder, session,
|
|
||||||
wheel_cache
|
|
||||||
)
|
|
||||||
|
|
||||||
preparer = self.make_requirement_preparer(
|
preparer = self.make_requirement_preparer(
|
||||||
temp_build_dir=directory,
|
temp_build_dir=directory,
|
||||||
|
|
|
@ -147,7 +147,7 @@ class HashError(InstallationError):
|
||||||
triggering requirement.
|
triggering requirement.
|
||||||
|
|
||||||
:param req: The InstallRequirement that provoked this error, with
|
:param req: The InstallRequirement that provoked this error, with
|
||||||
populate_link() having already been called
|
its link already populated by the resolver's _populate_link().
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return ' {}'.format(self._requirement_name())
|
return ' {}'.format(self._requirement_name())
|
||||||
|
|
|
@ -120,13 +120,11 @@ def freeze(
|
||||||
line_req = install_req_from_editable(
|
line_req = install_req_from_editable(
|
||||||
line,
|
line,
|
||||||
isolated=isolated,
|
isolated=isolated,
|
||||||
wheel_cache=wheel_cache,
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
line_req = install_req_from_line(
|
line_req = install_req_from_line(
|
||||||
COMMENT_RE.sub('', line).strip(),
|
COMMENT_RE.sub('', line).strip(),
|
||||||
isolated=isolated,
|
isolated=isolated,
|
||||||
wheel_cache=wheel_cache,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if not line_req.name:
|
if not line_req.name:
|
||||||
|
|
|
@ -36,7 +36,6 @@ if MYPY_CHECK_RUNNING:
|
||||||
from typing import (
|
from typing import (
|
||||||
Any, Dict, Optional, Set, Tuple, Union,
|
Any, Dict, Optional, Set, Tuple, Union,
|
||||||
)
|
)
|
||||||
from pip._internal.cache import WheelCache
|
|
||||||
from pip._internal.req.req_file import ParsedRequirement
|
from pip._internal.req.req_file import ParsedRequirement
|
||||||
|
|
||||||
|
|
||||||
|
@ -223,7 +222,6 @@ def install_req_from_editable(
|
||||||
use_pep517=None, # type: Optional[bool]
|
use_pep517=None, # type: Optional[bool]
|
||||||
isolated=False, # type: bool
|
isolated=False, # type: bool
|
||||||
options=None, # type: Optional[Dict[str, Any]]
|
options=None, # type: Optional[Dict[str, Any]]
|
||||||
wheel_cache=None, # type: Optional[WheelCache]
|
|
||||||
constraint=False # type: bool
|
constraint=False # type: bool
|
||||||
):
|
):
|
||||||
# type: (...) -> InstallRequirement
|
# type: (...) -> InstallRequirement
|
||||||
|
@ -242,7 +240,6 @@ def install_req_from_editable(
|
||||||
install_options=options.get("install_options", []) if options else [],
|
install_options=options.get("install_options", []) if options else [],
|
||||||
global_options=options.get("global_options", []) if options else [],
|
global_options=options.get("global_options", []) if options else [],
|
||||||
hash_options=options.get("hashes", {}) if options else {},
|
hash_options=options.get("hashes", {}) if options else {},
|
||||||
wheel_cache=wheel_cache,
|
|
||||||
extras=parts.extras,
|
extras=parts.extras,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -387,7 +384,6 @@ def install_req_from_line(
|
||||||
use_pep517=None, # type: Optional[bool]
|
use_pep517=None, # type: Optional[bool]
|
||||||
isolated=False, # type: bool
|
isolated=False, # type: bool
|
||||||
options=None, # type: Optional[Dict[str, Any]]
|
options=None, # type: Optional[Dict[str, Any]]
|
||||||
wheel_cache=None, # type: Optional[WheelCache]
|
|
||||||
constraint=False, # type: bool
|
constraint=False, # type: bool
|
||||||
line_source=None, # type: Optional[str]
|
line_source=None, # type: Optional[str]
|
||||||
):
|
):
|
||||||
|
@ -406,7 +402,6 @@ def install_req_from_line(
|
||||||
install_options=options.get("install_options", []) if options else [],
|
install_options=options.get("install_options", []) if options else [],
|
||||||
global_options=options.get("global_options", []) if options else [],
|
global_options=options.get("global_options", []) if options else [],
|
||||||
hash_options=options.get("hashes", {}) if options else {},
|
hash_options=options.get("hashes", {}) if options else {},
|
||||||
wheel_cache=wheel_cache,
|
|
||||||
constraint=constraint,
|
constraint=constraint,
|
||||||
extras=parts.extras,
|
extras=parts.extras,
|
||||||
)
|
)
|
||||||
|
@ -416,7 +411,6 @@ def install_req_from_req_string(
|
||||||
req_string, # type: str
|
req_string, # type: str
|
||||||
comes_from=None, # type: Optional[InstallRequirement]
|
comes_from=None, # type: Optional[InstallRequirement]
|
||||||
isolated=False, # type: bool
|
isolated=False, # type: bool
|
||||||
wheel_cache=None, # type: Optional[WheelCache]
|
|
||||||
use_pep517=None # type: Optional[bool]
|
use_pep517=None # type: Optional[bool]
|
||||||
):
|
):
|
||||||
# type: (...) -> InstallRequirement
|
# type: (...) -> InstallRequirement
|
||||||
|
@ -439,15 +433,13 @@ def install_req_from_req_string(
|
||||||
)
|
)
|
||||||
|
|
||||||
return InstallRequirement(
|
return InstallRequirement(
|
||||||
req, comes_from, isolated=isolated, wheel_cache=wheel_cache,
|
req, comes_from, isolated=isolated, use_pep517=use_pep517
|
||||||
use_pep517=use_pep517
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def install_req_from_parsed_requirement(
|
def install_req_from_parsed_requirement(
|
||||||
parsed_req, # type: ParsedRequirement
|
parsed_req, # type: ParsedRequirement
|
||||||
isolated=False, # type: bool
|
isolated=False, # type: bool
|
||||||
wheel_cache=None, # type: Optional[WheelCache]
|
|
||||||
use_pep517=None # type: Optional[bool]
|
use_pep517=None # type: Optional[bool]
|
||||||
):
|
):
|
||||||
# type: (...) -> InstallRequirement
|
# type: (...) -> InstallRequirement
|
||||||
|
@ -458,7 +450,6 @@ def install_req_from_parsed_requirement(
|
||||||
use_pep517=use_pep517,
|
use_pep517=use_pep517,
|
||||||
constraint=parsed_req.constraint,
|
constraint=parsed_req.constraint,
|
||||||
isolated=isolated,
|
isolated=isolated,
|
||||||
wheel_cache=wheel_cache
|
|
||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -468,7 +459,6 @@ def install_req_from_parsed_requirement(
|
||||||
use_pep517=use_pep517,
|
use_pep517=use_pep517,
|
||||||
isolated=isolated,
|
isolated=isolated,
|
||||||
options=parsed_req.options,
|
options=parsed_req.options,
|
||||||
wheel_cache=wheel_cache,
|
|
||||||
constraint=parsed_req.constraint,
|
constraint=parsed_req.constraint,
|
||||||
line_source=parsed_req.line_source,
|
line_source=parsed_req.line_source,
|
||||||
)
|
)
|
||||||
|
|
|
@ -30,7 +30,6 @@ from pip._internal.operations.install.legacy import install as install_legacy
|
||||||
from pip._internal.operations.install.wheel import install_wheel
|
from pip._internal.operations.install.wheel import install_wheel
|
||||||
from pip._internal.pyproject import load_pyproject_toml, make_pyproject_path
|
from pip._internal.pyproject import load_pyproject_toml, make_pyproject_path
|
||||||
from pip._internal.req.req_uninstall import UninstallPathSet
|
from pip._internal.req.req_uninstall import UninstallPathSet
|
||||||
from pip._internal.utils import compatibility_tags
|
|
||||||
from pip._internal.utils.deprecation import deprecated
|
from pip._internal.utils.deprecation import deprecated
|
||||||
from pip._internal.utils.hashes import Hashes
|
from pip._internal.utils.hashes import Hashes
|
||||||
from pip._internal.utils.logging import indent_log
|
from pip._internal.utils.logging import indent_log
|
||||||
|
@ -55,8 +54,6 @@ if MYPY_CHECK_RUNNING:
|
||||||
Any, Dict, Iterable, List, Optional, Sequence, Union,
|
Any, Dict, Iterable, List, Optional, Sequence, Union,
|
||||||
)
|
)
|
||||||
from pip._internal.build_env import BuildEnvironment
|
from pip._internal.build_env import BuildEnvironment
|
||||||
from pip._internal.cache import WheelCache
|
|
||||||
from pip._internal.index.package_finder import PackageFinder
|
|
||||||
from pip._vendor.pkg_resources import Distribution
|
from pip._vendor.pkg_resources import Distribution
|
||||||
from pip._vendor.packaging.specifiers import SpecifierSet
|
from pip._vendor.packaging.specifiers import SpecifierSet
|
||||||
from pip._vendor.packaging.markers import Marker
|
from pip._vendor.packaging.markers import Marker
|
||||||
|
@ -111,7 +108,6 @@ class InstallRequirement(object):
|
||||||
install_options=None, # type: Optional[List[str]]
|
install_options=None, # type: Optional[List[str]]
|
||||||
global_options=None, # type: Optional[List[str]]
|
global_options=None, # type: Optional[List[str]]
|
||||||
hash_options=None, # type: Optional[Dict[str, List[str]]]
|
hash_options=None, # type: Optional[Dict[str, List[str]]]
|
||||||
wheel_cache=None, # type: Optional[WheelCache]
|
|
||||||
constraint=False, # type: bool
|
constraint=False, # type: bool
|
||||||
extras=() # type: Iterable[str]
|
extras=() # type: Iterable[str]
|
||||||
):
|
):
|
||||||
|
@ -126,7 +122,6 @@ class InstallRequirement(object):
|
||||||
self.source_dir = os.path.normpath(os.path.abspath(source_dir))
|
self.source_dir = os.path.normpath(os.path.abspath(source_dir))
|
||||||
self.editable = editable
|
self.editable = editable
|
||||||
|
|
||||||
self._wheel_cache = wheel_cache
|
|
||||||
if link is None and req and req.url:
|
if link is None and req and req.url:
|
||||||
# PEP 508 URL requirement
|
# PEP 508 URL requirement
|
||||||
link = Link(req.url)
|
link = Link(req.url)
|
||||||
|
@ -241,32 +236,6 @@ class InstallRequirement(object):
|
||||||
state=", ".join(state),
|
state=", ".join(state),
|
||||||
)
|
)
|
||||||
|
|
||||||
def populate_link(self, finder, upgrade, require_hashes):
|
|
||||||
# type: (PackageFinder, bool, bool) -> None
|
|
||||||
"""Ensure that if a link can be found for this, that it is found.
|
|
||||||
|
|
||||||
Note that self.link may still be None - if Upgrade is False and the
|
|
||||||
requirement is already installed.
|
|
||||||
|
|
||||||
If require_hashes is True, don't use the wheel cache, because cached
|
|
||||||
wheels, always built locally, have different hashes than the files
|
|
||||||
downloaded from the index server and thus throw false hash mismatches.
|
|
||||||
Furthermore, cached wheels at present have undeterministic contents due
|
|
||||||
to file modification times.
|
|
||||||
"""
|
|
||||||
if self.link is None:
|
|
||||||
self.link = finder.find_requirement(self, upgrade)
|
|
||||||
if self._wheel_cache is not None and not require_hashes:
|
|
||||||
old_link = self.link
|
|
||||||
supported_tags = compatibility_tags.get_supported()
|
|
||||||
self.link = self._wheel_cache.get(
|
|
||||||
link=self.link,
|
|
||||||
package_name=self.name,
|
|
||||||
supported_tags=supported_tags,
|
|
||||||
)
|
|
||||||
if old_link != self.link:
|
|
||||||
logger.debug('Using cached wheel link: %s', self.link)
|
|
||||||
|
|
||||||
# Things that are valid for all kinds of requirements?
|
# Things that are valid for all kinds of requirements?
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
|
|
|
@ -585,11 +585,6 @@ class UninstallPathSet(object):
|
||||||
class UninstallPthEntries(object):
|
class UninstallPthEntries(object):
|
||||||
def __init__(self, pth_file):
|
def __init__(self, pth_file):
|
||||||
# type: (str) -> None
|
# type: (str) -> None
|
||||||
if not os.path.isfile(pth_file):
|
|
||||||
raise UninstallationError(
|
|
||||||
"Cannot remove entries from nonexistent file {}".format(
|
|
||||||
pth_file)
|
|
||||||
)
|
|
||||||
self.file = pth_file
|
self.file = pth_file
|
||||||
self.entries = set() # type: Set[str]
|
self.entries = set() # type: Set[str]
|
||||||
self._saved_lines = None # type: Optional[List[bytes]]
|
self._saved_lines = None # type: Optional[List[bytes]]
|
||||||
|
@ -613,6 +608,14 @@ class UninstallPthEntries(object):
|
||||||
def remove(self):
|
def remove(self):
|
||||||
# type: () -> None
|
# type: () -> None
|
||||||
logger.debug('Removing pth entries from %s:', self.file)
|
logger.debug('Removing pth entries from %s:', self.file)
|
||||||
|
|
||||||
|
# If the file doesn't exist, log a warning and return
|
||||||
|
if not os.path.isfile(self.file):
|
||||||
|
logger.warning(
|
||||||
|
"Cannot remove entries from nonexistent file {}".format(
|
||||||
|
self.file)
|
||||||
|
)
|
||||||
|
return
|
||||||
with open(self.file, 'rb') as fh:
|
with open(self.file, 'rb') as fh:
|
||||||
# windows uses '\r\n' with py3k, but uses '\n' with py2.x
|
# windows uses '\r\n' with py3k, but uses '\n' with py2.x
|
||||||
lines = fh.readlines()
|
lines = fh.readlines()
|
||||||
|
|
|
@ -30,6 +30,7 @@ from pip._internal.exceptions import (
|
||||||
)
|
)
|
||||||
from pip._internal.req.req_set import RequirementSet
|
from pip._internal.req.req_set import RequirementSet
|
||||||
from pip._internal.resolution.base import BaseResolver
|
from pip._internal.resolution.base import BaseResolver
|
||||||
|
from pip._internal.utils.compatibility_tags import get_supported
|
||||||
from pip._internal.utils.logging import indent_log
|
from pip._internal.utils.logging import indent_log
|
||||||
from pip._internal.utils.misc import dist_in_usersite, normalize_version_info
|
from pip._internal.utils.misc import dist_in_usersite, normalize_version_info
|
||||||
from pip._internal.utils.packaging import (
|
from pip._internal.utils.packaging import (
|
||||||
|
@ -42,6 +43,7 @@ if MYPY_CHECK_RUNNING:
|
||||||
from typing import DefaultDict, List, Optional, Set, Tuple
|
from typing import DefaultDict, List, Optional, Set, Tuple
|
||||||
from pip._vendor import pkg_resources
|
from pip._vendor import pkg_resources
|
||||||
|
|
||||||
|
from pip._internal.cache import WheelCache
|
||||||
from pip._internal.distributions import AbstractDistribution
|
from pip._internal.distributions import AbstractDistribution
|
||||||
from pip._internal.index.package_finder import PackageFinder
|
from pip._internal.index.package_finder import PackageFinder
|
||||||
from pip._internal.operations.prepare import RequirementPreparer
|
from pip._internal.operations.prepare import RequirementPreparer
|
||||||
|
@ -112,6 +114,7 @@ class Resolver(BaseResolver):
|
||||||
self,
|
self,
|
||||||
preparer, # type: RequirementPreparer
|
preparer, # type: RequirementPreparer
|
||||||
finder, # type: PackageFinder
|
finder, # type: PackageFinder
|
||||||
|
wheel_cache, # type: Optional[WheelCache]
|
||||||
make_install_req, # type: InstallRequirementProvider
|
make_install_req, # type: InstallRequirementProvider
|
||||||
use_user_site, # type: bool
|
use_user_site, # type: bool
|
||||||
ignore_dependencies, # type: bool
|
ignore_dependencies, # type: bool
|
||||||
|
@ -134,6 +137,7 @@ class Resolver(BaseResolver):
|
||||||
|
|
||||||
self.preparer = preparer
|
self.preparer = preparer
|
||||||
self.finder = finder
|
self.finder = finder
|
||||||
|
self.wheel_cache = wheel_cache
|
||||||
|
|
||||||
self.upgrade_strategy = upgrade_strategy
|
self.upgrade_strategy = upgrade_strategy
|
||||||
self.force_reinstall = force_reinstall
|
self.force_reinstall = force_reinstall
|
||||||
|
@ -166,7 +170,7 @@ class Resolver(BaseResolver):
|
||||||
|
|
||||||
# Actually prepare the files, and collect any exceptions. Most hash
|
# Actually prepare the files, and collect any exceptions. Most hash
|
||||||
# exceptions cannot be checked ahead of time, because
|
# exceptions cannot be checked ahead of time, because
|
||||||
# req.populate_link() needs to be called before we can make decisions
|
# _populate_link() needs to be called before we can make decisions
|
||||||
# based on link type.
|
# based on link type.
|
||||||
discovered_reqs = [] # type: List[InstallRequirement]
|
discovered_reqs = [] # type: List[InstallRequirement]
|
||||||
hash_errors = HashErrors()
|
hash_errors = HashErrors()
|
||||||
|
@ -256,6 +260,35 @@ class Resolver(BaseResolver):
|
||||||
self._set_req_to_reinstall(req_to_install)
|
self._set_req_to_reinstall(req_to_install)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _populate_link(self, req):
|
||||||
|
# type: (InstallRequirement) -> None
|
||||||
|
"""Ensure that if a link can be found for this, that it is found.
|
||||||
|
|
||||||
|
Note that req.link may still be None - if the requirement is already
|
||||||
|
installed and not needed to be upgraded based on the return value of
|
||||||
|
_is_upgrade_allowed().
|
||||||
|
|
||||||
|
If preparer.require_hashes is True, don't use the wheel cache, because
|
||||||
|
cached wheels, always built locally, have different hashes than the
|
||||||
|
files downloaded from the index server and thus throw false hash
|
||||||
|
mismatches. Furthermore, cached wheels at present have undeterministic
|
||||||
|
contents due to file modification times.
|
||||||
|
"""
|
||||||
|
upgrade = self._is_upgrade_allowed(req)
|
||||||
|
if req.link is None:
|
||||||
|
req.link = self.finder.find_requirement(req, upgrade)
|
||||||
|
|
||||||
|
if self.wheel_cache is None or self.preparer.require_hashes:
|
||||||
|
return
|
||||||
|
cached_link = self.wheel_cache.get(
|
||||||
|
link=req.link,
|
||||||
|
package_name=req.name,
|
||||||
|
supported_tags=get_supported(),
|
||||||
|
)
|
||||||
|
if req.link != cached_link:
|
||||||
|
logger.debug('Using cached wheel link: %s', cached_link)
|
||||||
|
req.link = cached_link
|
||||||
|
|
||||||
def _get_abstract_dist_for(self, req):
|
def _get_abstract_dist_for(self, req):
|
||||||
# type: (InstallRequirement) -> AbstractDistribution
|
# type: (InstallRequirement) -> AbstractDistribution
|
||||||
"""Takes a InstallRequirement and returns a single AbstractDist \
|
"""Takes a InstallRequirement and returns a single AbstractDist \
|
||||||
|
@ -274,11 +307,8 @@ class Resolver(BaseResolver):
|
||||||
req, skip_reason
|
req, skip_reason
|
||||||
)
|
)
|
||||||
|
|
||||||
upgrade_allowed = self._is_upgrade_allowed(req)
|
|
||||||
|
|
||||||
# We eagerly populate the link, since that's our "legacy" behavior.
|
# We eagerly populate the link, since that's our "legacy" behavior.
|
||||||
require_hashes = self.preparer.require_hashes
|
self._populate_link(req)
|
||||||
req.populate_link(self.finder, upgrade_allowed, require_hashes)
|
|
||||||
abstract_dist = self.preparer.prepare_linked_requirement(req)
|
abstract_dist = self.preparer.prepare_linked_requirement(req)
|
||||||
|
|
||||||
# NOTE
|
# NOTE
|
||||||
|
|
|
@ -30,7 +30,6 @@ def make_install_req_from_link(link, parent):
|
||||||
comes_from=parent.comes_from,
|
comes_from=parent.comes_from,
|
||||||
use_pep517=parent.use_pep517,
|
use_pep517=parent.use_pep517,
|
||||||
isolated=parent.isolated,
|
isolated=parent.isolated,
|
||||||
wheel_cache=parent._wheel_cache,
|
|
||||||
constraint=parent.constraint,
|
constraint=parent.constraint,
|
||||||
options=dict(
|
options=dict(
|
||||||
install_options=parent.install_options,
|
install_options=parent.install_options,
|
||||||
|
|
|
@ -16,6 +16,7 @@ if MYPY_CHECK_RUNNING:
|
||||||
|
|
||||||
from pip._vendor.resolvelib.resolvers import Result
|
from pip._vendor.resolvelib.resolvers import Result
|
||||||
|
|
||||||
|
from pip._internal.cache import WheelCache
|
||||||
from pip._internal.index.package_finder import PackageFinder
|
from pip._internal.index.package_finder import PackageFinder
|
||||||
from pip._internal.operations.prepare import RequirementPreparer
|
from pip._internal.operations.prepare import RequirementPreparer
|
||||||
from pip._internal.req.req_install import InstallRequirement
|
from pip._internal.req.req_install import InstallRequirement
|
||||||
|
@ -27,6 +28,7 @@ class Resolver(BaseResolver):
|
||||||
self,
|
self,
|
||||||
preparer, # type: RequirementPreparer
|
preparer, # type: RequirementPreparer
|
||||||
finder, # type: PackageFinder
|
finder, # type: PackageFinder
|
||||||
|
wheel_cache, # type: Optional[WheelCache]
|
||||||
make_install_req, # type: InstallRequirementProvider
|
make_install_req, # type: InstallRequirementProvider
|
||||||
use_user_site, # type: bool
|
use_user_site, # type: bool
|
||||||
ignore_dependencies, # type: bool
|
ignore_dependencies, # type: bool
|
||||||
|
|
|
@ -11,7 +11,7 @@ import sys
|
||||||
from pip._vendor import pkg_resources
|
from pip._vendor import pkg_resources
|
||||||
from pip._vendor.six.moves.urllib import parse as urllib_parse
|
from pip._vendor.six.moves.urllib import parse as urllib_parse
|
||||||
|
|
||||||
from pip._internal.exceptions import BadCommand
|
from pip._internal.exceptions import BadCommand, InstallationError
|
||||||
from pip._internal.utils.compat import samefile
|
from pip._internal.utils.compat import samefile
|
||||||
from pip._internal.utils.misc import (
|
from pip._internal.utils.misc import (
|
||||||
ask_path_exists,
|
ask_path_exists,
|
||||||
|
@ -436,6 +436,12 @@ class VersionControl(object):
|
||||||
rev = None
|
rev = None
|
||||||
if '@' in path:
|
if '@' in path:
|
||||||
path, rev = path.rsplit('@', 1)
|
path, rev = path.rsplit('@', 1)
|
||||||
|
if not rev:
|
||||||
|
raise InstallationError(
|
||||||
|
"The URL {!r} has an empty revision (after @) "
|
||||||
|
"which is not supported. Include a revision after @ "
|
||||||
|
"or remove @ from the URL.".format(url)
|
||||||
|
)
|
||||||
url = urllib_parse.urlunsplit((scheme, netloc, path, query, ''))
|
url = urllib_parse.urlunsplit((scheme, netloc, path, query, ''))
|
||||||
return url, rev, user_pass
|
return url, rev, user_pass
|
||||||
|
|
||||||
|
|
|
@ -16,10 +16,9 @@ from setuptools.wheel import Wheel
|
||||||
from pip._internal.cli.main import main as pip_entry_point
|
from pip._internal.cli.main import main as pip_entry_point
|
||||||
from pip._internal.utils.temp_dir import global_tempdir_manager
|
from pip._internal.utils.temp_dir import global_tempdir_manager
|
||||||
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
|
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
|
||||||
from tests.lib import DATA_DIR, SRC_DIR, TestData
|
from tests.lib import DATA_DIR, SRC_DIR, PipTestEnvironment, TestData
|
||||||
from tests.lib.certs import make_tls_cert, serialize_cert, serialize_key
|
from tests.lib.certs import make_tls_cert, serialize_cert, serialize_key
|
||||||
from tests.lib.path import Path
|
from tests.lib.path import Path
|
||||||
from tests.lib.scripttest import PipTestEnvironment
|
|
||||||
from tests.lib.server import make_mock_server, server_running
|
from tests.lib.server import make_mock_server, server_running
|
||||||
from tests.lib.venv import VirtualEnvironment
|
from tests.lib.venv import VirtualEnvironment
|
||||||
|
|
||||||
|
@ -370,7 +369,7 @@ def script(tmpdir, virtualenv, script_factory):
|
||||||
Return a PipTestEnvironment which is unique to each test function and
|
Return a PipTestEnvironment which is unique to each test function and
|
||||||
will execute all commands inside of the unique virtual environment for this
|
will execute all commands inside of the unique virtual environment for this
|
||||||
test function. The returned object is a
|
test function. The returned object is a
|
||||||
``tests.lib.scripttest.PipTestEnvironment``.
|
``tests.lib.PipTestEnvironment``.
|
||||||
"""
|
"""
|
||||||
return script_factory(tmpdir.joinpath("workspace"), virtualenv)
|
return script_factory(tmpdir.joinpath("workspace"), virtualenv)
|
||||||
|
|
||||||
|
|
|
@ -553,6 +553,53 @@ def test_uninstall_editable_and_pip_install(script, data):
|
||||||
assert "FSPkg" not in {p["name"] for p in json.loads(list_result2.stdout)}
|
assert "FSPkg" not in {p["name"] for p in json.loads(list_result2.stdout)}
|
||||||
|
|
||||||
|
|
||||||
|
def test_uninstall_editable_and_pip_install_easy_install_remove(script, data):
|
||||||
|
"""Try uninstall after pip install -e after pip install
|
||||||
|
and removing easy-install.pth"""
|
||||||
|
# SETUPTOOLS_SYS_PATH_TECHNIQUE=raw removes the assumption that `-e`
|
||||||
|
# installs are always higher priority than regular installs.
|
||||||
|
# This becomes the default behavior in setuptools 25.
|
||||||
|
script.environ['SETUPTOOLS_SYS_PATH_TECHNIQUE'] = 'raw'
|
||||||
|
|
||||||
|
# Rename easy-install.pth to pip-test.pth
|
||||||
|
easy_install_pth = join(script.site_packages_path, 'easy-install.pth')
|
||||||
|
pip_test_pth = join(script.site_packages_path, 'pip-test.pth')
|
||||||
|
os.rename(easy_install_pth, pip_test_pth)
|
||||||
|
|
||||||
|
# Install FSPkg
|
||||||
|
pkg_path = data.packages.joinpath("FSPkg")
|
||||||
|
script.pip('install', '-e', '.',
|
||||||
|
expect_stderr=True, cwd=pkg_path)
|
||||||
|
|
||||||
|
# Rename easy-install.pth to pip-test-fspkg.pth
|
||||||
|
pip_test_fspkg_pth = join(script.site_packages_path, 'pip-test-fspkg.pth')
|
||||||
|
os.rename(easy_install_pth, pip_test_fspkg_pth)
|
||||||
|
|
||||||
|
# Confirm that FSPkg is installed
|
||||||
|
list_result = script.pip('list', '--format=json')
|
||||||
|
assert {"name": "FSPkg", "version": "0.1.dev0"} \
|
||||||
|
in json.loads(list_result.stdout)
|
||||||
|
|
||||||
|
# Remove pip-test-fspkg.pth
|
||||||
|
os.remove(pip_test_fspkg_pth)
|
||||||
|
|
||||||
|
# Uninstall will fail with given warning
|
||||||
|
uninstall = script.pip('uninstall', 'FSPkg', '-y')
|
||||||
|
assert "Cannot remove entries from nonexistent file" in uninstall.stderr
|
||||||
|
|
||||||
|
assert join(
|
||||||
|
script.site_packages, 'FSPkg.egg-link'
|
||||||
|
) in uninstall.files_deleted, list(uninstall.files_deleted.keys())
|
||||||
|
|
||||||
|
# Confirm that FSPkg is uninstalled
|
||||||
|
list_result = script.pip('list', '--format=json')
|
||||||
|
assert {"name": "FSPkg", "version": "0.1.dev0"} \
|
||||||
|
not in json.loads(list_result.stdout)
|
||||||
|
|
||||||
|
# Rename pip-test.pth back to easy-install.pth
|
||||||
|
os.rename(pip_test_pth, easy_install_pth)
|
||||||
|
|
||||||
|
|
||||||
def test_uninstall_ignores_missing_packages(script, data):
|
def test_uninstall_ignores_missing_packages(script, data):
|
||||||
"""Uninstall of a non existent package prints a warning and exits cleanly
|
"""Uninstall of a non existent package prints a warning and exits cleanly
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
"""Tests for the resolver
|
"""
|
||||||
|
Tests for the resolver
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
import yaml
|
||||||
|
|
||||||
from tests.lib import DATA_DIR, create_basic_wheel_for_package, path_to_url
|
from tests.lib import DATA_DIR, create_basic_wheel_for_package, path_to_url
|
||||||
from tests.lib.yaml_helpers import generate_yaml_tests, id_func
|
|
||||||
|
|
||||||
_conflict_finder_re = re.compile(
|
_conflict_finder_pat = re.compile(
|
||||||
# Conflicting Requirements: \
|
# Conflicting Requirements: \
|
||||||
# A 1.0.0 requires B == 2.0.0, C 1.0.0 requires B == 1.0.0.
|
# A 1.0.0 requires B == 2.0.0, C 1.0.0 requires B == 1.0.0.
|
||||||
r"""
|
r"""
|
||||||
|
@ -24,7 +25,49 @@ _conflict_finder_re = re.compile(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _convert_to_dict(string):
|
def generate_yaml_tests(directory):
|
||||||
|
"""
|
||||||
|
Generate yaml test cases from the yaml files in the given directory
|
||||||
|
"""
|
||||||
|
for yml_file in directory.glob("*/*.yml"):
|
||||||
|
data = yaml.safe_load(yml_file.read_text())
|
||||||
|
assert "cases" in data, "A fixture needs cases to be used in testing"
|
||||||
|
|
||||||
|
# Strip the parts of the directory to only get a name without
|
||||||
|
# extension and resolver directory
|
||||||
|
base_name = str(yml_file)[len(str(directory)) + 1:-4]
|
||||||
|
|
||||||
|
base = data.get("base", {})
|
||||||
|
cases = data["cases"]
|
||||||
|
|
||||||
|
for i, case_template in enumerate(cases):
|
||||||
|
case = base.copy()
|
||||||
|
case.update(case_template)
|
||||||
|
|
||||||
|
case[":name:"] = base_name
|
||||||
|
if len(cases) > 1:
|
||||||
|
case[":name:"] += "-" + str(i)
|
||||||
|
|
||||||
|
if case.pop("skip", False):
|
||||||
|
case = pytest.param(case, marks=pytest.mark.xfail)
|
||||||
|
|
||||||
|
yield case
|
||||||
|
|
||||||
|
|
||||||
|
def id_func(param):
|
||||||
|
"""
|
||||||
|
Give a nice parameter name to the generated function parameters
|
||||||
|
"""
|
||||||
|
if isinstance(param, dict) and ":name:" in param:
|
||||||
|
return param[":name:"]
|
||||||
|
|
||||||
|
retval = str(param)
|
||||||
|
if len(retval) > 25:
|
||||||
|
retval = retval[:20] + "..." + retval[-2:]
|
||||||
|
return retval
|
||||||
|
|
||||||
|
|
||||||
|
def convert_to_dict(string):
|
||||||
|
|
||||||
def stripping_split(my_str, splitwith, count=None):
|
def stripping_split(my_str, splitwith, count=None):
|
||||||
if count is None:
|
if count is None:
|
||||||
|
@ -89,7 +132,7 @@ def handle_install_request(script, requirement):
|
||||||
message = result.stderr.rsplit("\n", 1)[-1]
|
message = result.stderr.rsplit("\n", 1)[-1]
|
||||||
|
|
||||||
# XXX: There might be a better way than parsing the message
|
# XXX: There might be a better way than parsing the message
|
||||||
for match in re.finditer(message, _conflict_finder_re):
|
for match in re.finditer(message, _conflict_finder_pat):
|
||||||
di = match.groupdict()
|
di = match.groupdict()
|
||||||
retval["conflicting"].append(
|
retval["conflicting"].append(
|
||||||
{
|
{
|
||||||
|
@ -119,7 +162,7 @@ def test_yaml_based(script, case):
|
||||||
# XXX: This doesn't work because this isn't making an index of files.
|
# XXX: This doesn't work because this isn't making an index of files.
|
||||||
for package in available:
|
for package in available:
|
||||||
if isinstance(package, str):
|
if isinstance(package, str):
|
||||||
package = _convert_to_dict(package)
|
package = convert_to_dict(package)
|
||||||
|
|
||||||
assert isinstance(package, dict), "Needs to be a dictionary"
|
assert isinstance(package, dict), "Needs to be a dictionary"
|
||||||
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
from __future__ import absolute_import
|
|
||||||
|
|
||||||
from . import PipTestEnvironment # noqa
|
|
|
@ -1,43 +0,0 @@
|
||||||
"""
|
|
||||||
"""
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
|
|
||||||
def generate_yaml_tests(directory):
|
|
||||||
for yml_file in directory.glob("*/*.yml"):
|
|
||||||
data = yaml.safe_load(yml_file.read_text())
|
|
||||||
assert "cases" in data, "A fixture needs cases to be used in testing"
|
|
||||||
|
|
||||||
# Strip the parts of the directory to only get a name without
|
|
||||||
# extension and resolver directory
|
|
||||||
base_name = str(yml_file)[len(str(directory)) + 1:-4]
|
|
||||||
|
|
||||||
base = data.get("base", {})
|
|
||||||
cases = data["cases"]
|
|
||||||
|
|
||||||
for i, case_template in enumerate(cases):
|
|
||||||
case = base.copy()
|
|
||||||
case.update(case_template)
|
|
||||||
|
|
||||||
case[":name:"] = base_name
|
|
||||||
if len(cases) > 1:
|
|
||||||
case[":name:"] += "-" + str(i)
|
|
||||||
|
|
||||||
if case.pop("skip", False):
|
|
||||||
case = pytest.param(case, marks=pytest.mark.xfail)
|
|
||||||
|
|
||||||
yield case
|
|
||||||
|
|
||||||
|
|
||||||
def id_func(param):
|
|
||||||
"""Give a nice parameter name to the generated function parameters
|
|
||||||
"""
|
|
||||||
if isinstance(param, dict) and ":name:" in param:
|
|
||||||
return param[":name:"]
|
|
||||||
|
|
||||||
retval = str(param)
|
|
||||||
if len(retval) > 25:
|
|
||||||
retval = retval[:20] + "..." + retval[-2:]
|
|
||||||
return retval
|
|
|
@ -48,7 +48,7 @@ def test_cases(data):
|
||||||
yield test_cases
|
yield test_cases
|
||||||
|
|
||||||
|
|
||||||
def test_rlr_requirement_has_name(test_cases, factory):
|
def test_new_resolver_requirement_has_name(test_cases, factory):
|
||||||
"""All requirements should have a name"""
|
"""All requirements should have a name"""
|
||||||
for requirement, name, matches in test_cases:
|
for requirement, name, matches in test_cases:
|
||||||
ireq = install_req_from_line(requirement)
|
ireq = install_req_from_line(requirement)
|
||||||
|
@ -56,7 +56,7 @@ def test_rlr_requirement_has_name(test_cases, factory):
|
||||||
assert req.name == name
|
assert req.name == name
|
||||||
|
|
||||||
|
|
||||||
def test_rlr_correct_number_of_matches(test_cases, factory):
|
def test_new_resolver_correct_number_of_matches(test_cases, factory):
|
||||||
"""Requirements should return the correct number of candidates"""
|
"""Requirements should return the correct number of candidates"""
|
||||||
for requirement, name, matches in test_cases:
|
for requirement, name, matches in test_cases:
|
||||||
ireq = install_req_from_line(requirement)
|
ireq = install_req_from_line(requirement)
|
||||||
|
@ -64,7 +64,7 @@ def test_rlr_correct_number_of_matches(test_cases, factory):
|
||||||
assert len(req.find_matches()) == matches
|
assert len(req.find_matches()) == matches
|
||||||
|
|
||||||
|
|
||||||
def test_rlr_candidates_match_requirement(test_cases, factory):
|
def test_new_resolver_candidates_match_requirement(test_cases, factory):
|
||||||
"""Candidates returned from find_matches should satisfy the requirement"""
|
"""Candidates returned from find_matches should satisfy the requirement"""
|
||||||
for requirement, name, matches in test_cases:
|
for requirement, name, matches in test_cases:
|
||||||
ireq = install_req_from_line(requirement)
|
ireq = install_req_from_line(requirement)
|
||||||
|
@ -74,7 +74,7 @@ def test_rlr_candidates_match_requirement(test_cases, factory):
|
||||||
assert req.is_satisfied_by(c)
|
assert req.is_satisfied_by(c)
|
||||||
|
|
||||||
|
|
||||||
def test_rlr_full_resolve(factory, provider):
|
def test_new_resolver_full_resolve(factory, provider):
|
||||||
"""A very basic full resolve"""
|
"""A very basic full resolve"""
|
||||||
ireq = install_req_from_line("simplewheel")
|
ireq = install_req_from_line("simplewheel")
|
||||||
req = factory.make_requirement(ireq)
|
req = factory.make_requirement(ireq)
|
||||||
|
|
|
@ -14,6 +14,7 @@ def resolver(preparer, finder):
|
||||||
resolver = Resolver(
|
resolver = Resolver(
|
||||||
preparer=preparer,
|
preparer=preparer,
|
||||||
finder=finder,
|
finder=finder,
|
||||||
|
wheel_cache=None,
|
||||||
make_install_req=mock.Mock(),
|
make_install_req=mock.Mock(),
|
||||||
use_user_site="not-used",
|
use_user_site="not-used",
|
||||||
ignore_dependencies="not-used",
|
ignore_dependencies="not-used",
|
||||||
|
@ -57,7 +58,7 @@ def resolver(preparer, finder):
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_rlr_resolver_get_installation_order(resolver, edges, ordered_reqs):
|
def test_new_resolver_get_installation_order(resolver, edges, ordered_reqs):
|
||||||
# Build graph from edge declarations.
|
# Build graph from edge declarations.
|
||||||
graph = DirectedGraph()
|
graph = DirectedGraph()
|
||||||
for parent, child in edges:
|
for parent, child in edges:
|
||||||
|
|
|
@ -74,7 +74,6 @@ class TestRequirementSet(object):
|
||||||
make_install_req = partial(
|
make_install_req = partial(
|
||||||
install_req_from_req_string,
|
install_req_from_req_string,
|
||||||
isolated=False,
|
isolated=False,
|
||||||
wheel_cache=None,
|
|
||||||
use_pep517=None,
|
use_pep517=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -95,6 +94,7 @@ class TestRequirementSet(object):
|
||||||
preparer=preparer,
|
preparer=preparer,
|
||||||
make_install_req=make_install_req,
|
make_install_req=make_install_req,
|
||||||
finder=finder,
|
finder=finder,
|
||||||
|
wheel_cache=None,
|
||||||
use_user_site=False, upgrade_strategy="to-satisfy-only",
|
use_user_site=False, upgrade_strategy="to-satisfy-only",
|
||||||
ignore_dependencies=False, ignore_installed=False,
|
ignore_dependencies=False, ignore_installed=False,
|
||||||
ignore_requires_python=False, force_reinstall=False,
|
ignore_requires_python=False, force_reinstall=False,
|
||||||
|
@ -176,9 +176,7 @@ class TestRequirementSet(object):
|
||||||
command = create_command('install')
|
command = create_command('install')
|
||||||
with requirements_file('--require-hashes', tmpdir) as reqs_file:
|
with requirements_file('--require-hashes', tmpdir) as reqs_file:
|
||||||
options, args = command.parse_args(['-r', reqs_file])
|
options, args = command.parse_args(['-r', reqs_file])
|
||||||
command.get_requirements(
|
command.get_requirements(args, options, finder, session)
|
||||||
args, options, finder, session, wheel_cache=None,
|
|
||||||
)
|
|
||||||
assert options.require_hashes
|
assert options.require_hashes
|
||||||
|
|
||||||
def test_unsupported_hashes(self, data):
|
def test_unsupported_hashes(self, data):
|
||||||
|
|
|
@ -5,7 +5,7 @@ import pytest
|
||||||
from mock import patch
|
from mock import patch
|
||||||
from pip._vendor.packaging.version import parse as parse_version
|
from pip._vendor.packaging.version import parse as parse_version
|
||||||
|
|
||||||
from pip._internal.exceptions import BadCommand
|
from pip._internal.exceptions import BadCommand, InstallationError
|
||||||
from pip._internal.utils.misc import hide_url, hide_value
|
from pip._internal.utils.misc import hide_url, hide_value
|
||||||
from pip._internal.vcs import make_vcs_requirement_url
|
from pip._internal.vcs import make_vcs_requirement_url
|
||||||
from pip._internal.vcs.bazaar import Bazaar
|
from pip._internal.vcs.bazaar import Bazaar
|
||||||
|
@ -292,6 +292,21 @@ def test_version_control__get_url_rev_and_auth__missing_plus(url):
|
||||||
assert 'malformed VCS url' in str(excinfo.value)
|
assert 'malformed VCS url' in str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('url', [
|
||||||
|
# Test a URL with revision part as empty.
|
||||||
|
'git+https://github.com/MyUser/myProject.git@#egg=py_pkg',
|
||||||
|
])
|
||||||
|
def test_version_control__get_url_rev_and_auth__no_revision(url):
|
||||||
|
"""
|
||||||
|
Test passing a URL to VersionControl.get_url_rev_and_auth() with
|
||||||
|
empty revision
|
||||||
|
"""
|
||||||
|
with pytest.raises(InstallationError) as excinfo:
|
||||||
|
VersionControl.get_url_rev_and_auth(url)
|
||||||
|
|
||||||
|
assert 'an empty revision (after @)' in str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('url, expected', [
|
@pytest.mark.parametrize('url, expected', [
|
||||||
# Test http.
|
# Test http.
|
||||||
('bzr+http://bzr.myproject.org/MyProject/trunk/#egg=MyProject',
|
('bzr+http://bzr.myproject.org/MyProject/trunk/#egg=MyProject',
|
||||||
|
|
Loading…
Reference in New Issue