2014-08-31 01:52:28 +02:00
|
|
|
import logging
|
2017-12-16 14:54:57 +01:00
|
|
|
from collections import OrderedDict
|
2022-05-13 09:46:45 +02:00
|
|
|
from typing import Dict, List
|
2014-09-11 21:28:21 +02:00
|
|
|
|
2023-04-10 15:59:59 +02:00
|
|
|
from pip._vendor.packaging.specifiers import LegacySpecifier
|
2019-09-19 11:22:57 +02:00
|
|
|
from pip._vendor.packaging.utils import canonicalize_name
|
2023-04-10 15:59:59 +02:00
|
|
|
from pip._vendor.packaging.version import LegacyVersion
|
2019-09-19 11:22:57 +02:00
|
|
|
|
2021-02-19 13:56:59 +01:00
|
|
|
from pip._internal.req.req_install import InstallRequirement
|
2023-04-10 15:59:59 +02:00
|
|
|
from pip._internal.utils.deprecation import deprecated
|
2014-01-12 01:50:11 +01:00
|
|
|
|
2014-08-31 01:52:28 +02:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
2020-12-24 22:23:07 +01:00
|
|
|
class RequirementSet:
|
2021-07-23 16:38:27 +02:00
|
|
|
def __init__(self, check_supported_wheels: bool = True) -> None:
|
2015-04-07 23:47:13 +02:00
|
|
|
"""Create a RequirementSet."""
|
2014-05-07 01:25:44 +02:00
|
|
|
|
2021-07-23 16:38:27 +02:00
|
|
|
self.requirements: Dict[str, InstallRequirement] = OrderedDict()
|
2018-07-24 17:09:32 +02:00
|
|
|
self.check_supported_wheels = check_supported_wheels
|
2017-06-27 18:37:38 +02:00
|
|
|
|
2021-07-23 16:38:27 +02:00
|
|
|
self.unnamed_requirements: List[InstallRequirement] = []
|
2014-01-12 01:50:11 +01:00
|
|
|
|
2021-07-23 16:38:27 +02:00
|
|
|
def __str__(self) -> str:
|
2019-09-19 10:47:52 +02:00
|
|
|
requirements = sorted(
|
|
|
|
(req for req in self.requirements.values() if not req.comes_from),
|
2021-03-10 06:06:35 +01:00
|
|
|
key=lambda req: canonicalize_name(req.name or ""),
|
2019-09-19 10:47:52 +02:00
|
|
|
)
|
|
|
|
return " ".join(str(req.req) for req in requirements)
|
2014-01-12 01:50:11 +01:00
|
|
|
|
2021-07-23 16:38:27 +02:00
|
|
|
def __repr__(self) -> str:
|
2019-09-19 10:47:52 +02:00
|
|
|
requirements = sorted(
|
|
|
|
self.requirements.values(),
|
2021-03-10 06:06:35 +01:00
|
|
|
key=lambda req: canonicalize_name(req.name or ""),
|
2019-09-19 10:47:52 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
format_string = "<{classname} object; {count} requirement(s): {reqs}>"
|
|
|
|
return format_string.format(
|
|
|
|
classname=self.__class__.__name__,
|
|
|
|
count=len(requirements),
|
|
|
|
reqs=", ".join(str(req.req) for req in requirements),
|
|
|
|
)
|
Add RequirementSet.__repr__
This is useful when exploring with pdb -- e.g.:
(Pdb++) requirement_set
<RequirementSet object; 17 requirement(s): coverage==3.7.1, dj-database-url==0.2.2, dj-static==0.0.5, Django==1.6.2, django-nose==1.2, django-toolbelt==0.0.1, flake8==2.1.0, gunicorn==18.0, mccabe==0.2.1, nose==1.3.0, pep8==1.4.6, psycopg2==2.5.2, pyflakes==0.7.3, selenium==2.39.0, South==0.8.4, static==0.4, wsgiref==0.1.2>
2015-03-20 18:55:36 +01:00
|
|
|
|
2021-07-23 16:38:27 +02:00
|
|
|
def add_unnamed_requirement(self, install_req: InstallRequirement) -> None:
|
2019-08-20 09:10:35 +02:00
|
|
|
assert not install_req.name
|
|
|
|
self.unnamed_requirements.append(install_req)
|
|
|
|
|
2021-07-23 16:38:27 +02:00
|
|
|
def add_named_requirement(self, install_req: InstallRequirement) -> None:
|
2019-08-21 12:14:48 +02:00
|
|
|
assert install_req.name
|
|
|
|
|
2019-09-19 11:22:57 +02:00
|
|
|
project_name = canonicalize_name(install_req.name)
|
|
|
|
self.requirements[project_name] = install_req
|
2019-08-21 12:14:48 +02:00
|
|
|
|
2021-07-23 16:38:27 +02:00
|
|
|
def has_requirement(self, name: str) -> bool:
|
2019-09-19 11:22:57 +02:00
|
|
|
project_name = canonicalize_name(name)
|
|
|
|
|
|
|
|
return (
|
|
|
|
project_name in self.requirements
|
|
|
|
and not self.requirements[project_name].constraint
|
|
|
|
)
|
|
|
|
|
2021-07-23 16:38:27 +02:00
|
|
|
def get_requirement(self, name: str) -> InstallRequirement:
|
2019-09-19 11:22:57 +02:00
|
|
|
project_name = canonicalize_name(name)
|
|
|
|
|
|
|
|
if project_name in self.requirements:
|
|
|
|
return self.requirements[project_name]
|
|
|
|
|
2021-02-13 07:27:17 +01:00
|
|
|
raise KeyError(f"No project with the name {name!r}")
|
2020-02-06 03:21:53 +01:00
|
|
|
|
|
|
|
@property
|
2021-07-23 16:38:27 +02:00
|
|
|
def all_requirements(self) -> List[InstallRequirement]:
|
2020-02-06 03:21:53 +01:00
|
|
|
return self.unnamed_requirements + list(self.requirements.values())
|
2022-06-03 19:35:58 +02:00
|
|
|
|
|
|
|
@property
|
|
|
|
def requirements_to_install(self) -> List[InstallRequirement]:
|
|
|
|
"""Return the list of requirements that need to be installed.
|
|
|
|
|
|
|
|
TODO remove this property together with the legacy resolver, since the new
|
|
|
|
resolver only returns requirements that need to be installed.
|
|
|
|
"""
|
|
|
|
return [
|
|
|
|
install_req
|
|
|
|
for install_req in self.all_requirements
|
|
|
|
if not install_req.constraint and not install_req.satisfied_by
|
|
|
|
]
|
2023-04-10 15:59:59 +02:00
|
|
|
|
|
|
|
def warn_legacy_versions_and_specifiers(self) -> None:
|
|
|
|
for req in self.requirements_to_install:
|
|
|
|
version = req.get_dist().version
|
|
|
|
if isinstance(version, LegacyVersion):
|
|
|
|
deprecated(
|
|
|
|
reason=(
|
|
|
|
f"pip has selected the non standard version {version} "
|
|
|
|
f"of {req}. In the future this version will be "
|
|
|
|
f"ignored as it isn't standard compliant."
|
|
|
|
),
|
|
|
|
replacement=(
|
|
|
|
"set or update constraints to select another version "
|
|
|
|
"or contact the package author to fix the version number"
|
|
|
|
),
|
|
|
|
issue=12063,
|
2023-10-08 18:17:05 +02:00
|
|
|
gone_in="24.0",
|
2023-04-10 15:59:59 +02:00
|
|
|
)
|
|
|
|
for dep in req.get_dist().iter_dependencies():
|
|
|
|
if any(isinstance(spec, LegacySpecifier) for spec in dep.specifier):
|
|
|
|
deprecated(
|
|
|
|
reason=(
|
|
|
|
f"pip has selected {req} {version} which has non "
|
|
|
|
f"standard dependency specifier {dep}. "
|
|
|
|
f"In the future this version of {req} will be "
|
|
|
|
f"ignored as it isn't standard compliant."
|
|
|
|
),
|
|
|
|
replacement=(
|
|
|
|
"set or update constraints to select another version "
|
|
|
|
"or contact the package author to fix the version number"
|
|
|
|
),
|
|
|
|
issue=12063,
|
2023-10-08 18:17:05 +02:00
|
|
|
gone_in="24.0",
|
2023-04-10 15:59:59 +02:00
|
|
|
)
|