You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
83 lines
2.8 KiB
Python
83 lines
2.8 KiB
Python
2 years ago
|
import logging
|
||
|
from collections import OrderedDict
|
||
|
from typing import Dict, List
|
||
|
|
||
|
from pip._vendor.packaging.utils import canonicalize_name
|
||
|
|
||
|
from pip._internal.req.req_install import InstallRequirement
|
||
|
|
||
|
logger = logging.getLogger(__name__)
|
||
|
|
||
|
|
||
|
class RequirementSet:
|
||
|
def __init__(self, check_supported_wheels: bool = True) -> None:
|
||
|
"""Create a RequirementSet."""
|
||
|
|
||
|
self.requirements: Dict[str, InstallRequirement] = OrderedDict()
|
||
|
self.check_supported_wheels = check_supported_wheels
|
||
|
|
||
|
self.unnamed_requirements: List[InstallRequirement] = []
|
||
|
|
||
|
def __str__(self) -> str:
|
||
|
requirements = sorted(
|
||
|
(req for req in self.requirements.values() if not req.comes_from),
|
||
|
key=lambda req: canonicalize_name(req.name or ""),
|
||
|
)
|
||
|
return " ".join(str(req.req) for req in requirements)
|
||
|
|
||
|
def __repr__(self) -> str:
|
||
|
requirements = sorted(
|
||
|
self.requirements.values(),
|
||
|
key=lambda req: canonicalize_name(req.name or ""),
|
||
|
)
|
||
|
|
||
|
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),
|
||
|
)
|
||
|
|
||
|
def add_unnamed_requirement(self, install_req: InstallRequirement) -> None:
|
||
|
assert not install_req.name
|
||
|
self.unnamed_requirements.append(install_req)
|
||
|
|
||
|
def add_named_requirement(self, install_req: InstallRequirement) -> None:
|
||
|
assert install_req.name
|
||
|
|
||
|
project_name = canonicalize_name(install_req.name)
|
||
|
self.requirements[project_name] = install_req
|
||
|
|
||
|
def has_requirement(self, name: str) -> bool:
|
||
|
project_name = canonicalize_name(name)
|
||
|
|
||
|
return (
|
||
|
project_name in self.requirements
|
||
|
and not self.requirements[project_name].constraint
|
||
|
)
|
||
|
|
||
|
def get_requirement(self, name: str) -> InstallRequirement:
|
||
|
project_name = canonicalize_name(name)
|
||
|
|
||
|
if project_name in self.requirements:
|
||
|
return self.requirements[project_name]
|
||
|
|
||
|
raise KeyError(f"No project with the name {name!r}")
|
||
|
|
||
|
@property
|
||
|
def all_requirements(self) -> List[InstallRequirement]:
|
||
|
return self.unnamed_requirements + list(self.requirements.values())
|
||
|
|
||
|
@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
|
||
|
]
|