|
1 | 1 | import logging
|
| 2 | +import sys |
2 | 3 |
|
| 4 | +from pip._vendor.packaging.specifiers import InvalidSpecifier, SpecifierSet |
3 | 5 | from pip._vendor.packaging.utils import canonicalize_name
|
| 6 | +from pip._vendor.packaging.version import Version |
4 | 7 |
|
5 | 8 | from pip._internal.req.constructors import install_req_from_line
|
6 | 9 | from pip._internal.req.req_install import InstallRequirement
|
| 10 | +from pip._internal.utils.misc import normalize_version_info |
| 11 | +from pip._internal.utils.packaging import get_requires_python |
7 | 12 | from pip._internal.utils.typing import MYPY_CHECK_RUNNING
|
8 | 13 |
|
9 | 14 | from .base import Candidate, format_name
|
10 | 15 |
|
11 | 16 | if MYPY_CHECK_RUNNING:
|
12 |
| - from typing import Any, Optional, Sequence, Set |
13 |
| - |
14 |
| - from pip._internal.models.link import Link |
| 17 | + from typing import Any, Optional, Sequence, Set, Tuple |
15 | 18 |
|
16 | 19 | from pip._vendor.packaging.version import _BaseVersion
|
17 | 20 | from pip._vendor.pkg_resources import Distribution
|
18 | 21 |
|
| 22 | + from pip._internal.models.link import Link |
| 23 | + |
19 | 24 | from .base import Requirement
|
20 | 25 | from .factory import Factory
|
21 | 26 |
|
@@ -95,12 +100,32 @@ def dist(self):
|
95 | 100 | self._version == self.dist.parsed_version)
|
96 | 101 | return self._dist
|
97 | 102 |
|
| 103 | + def _get_requires_python_specifier(self): |
| 104 | + # type: () -> Optional[SpecifierSet] |
| 105 | + requires_python = get_requires_python(self.dist) |
| 106 | + if requires_python is None: |
| 107 | + return None |
| 108 | + try: |
| 109 | + spec = SpecifierSet(requires_python) |
| 110 | + except InvalidSpecifier as e: |
| 111 | + logger.warning( |
| 112 | + "Package %r has an invalid Requires-Python: %s", self.name, e, |
| 113 | + ) |
| 114 | + return None |
| 115 | + return spec |
| 116 | + |
98 | 117 | def get_dependencies(self):
|
99 | 118 | # type: () -> Sequence[Requirement]
|
100 |
| - return [ |
| 119 | + deps = [ |
101 | 120 | self._factory.make_requirement_from_spec(str(r), self._ireq)
|
102 | 121 | for r in self.dist.requires()
|
103 | 122 | ]
|
| 123 | + python_dep = self._factory.make_requires_python_requirement( |
| 124 | + self._get_requires_python_specifier(), |
| 125 | + ) |
| 126 | + if python_dep: |
| 127 | + deps.append(python_dep) |
| 128 | + return deps |
104 | 129 |
|
105 | 130 | def get_install_requirement(self):
|
106 | 131 | # type: () -> Optional[InstallRequirement]
|
@@ -179,3 +204,32 @@ def get_install_requirement(self):
|
179 | 204 | # depend on the base candidate, and we'll get the
|
180 | 205 | # install requirement from that.
|
181 | 206 | return None
|
| 207 | + |
| 208 | + |
| 209 | +class RequiresPythonCandidate(Candidate): |
| 210 | + def __init__(self, py_version_info): |
| 211 | + # type: (Optional[Tuple[int, ...]]) -> None |
| 212 | + if py_version_info is not None: |
| 213 | + version_info = normalize_version_info(py_version_info) |
| 214 | + else: |
| 215 | + version_info = sys.version_info[:3] |
| 216 | + self._version = Version(".".join(str(c) for c in version_info)) |
| 217 | + |
| 218 | + @property |
| 219 | + def name(self): |
| 220 | + # type: () -> str |
| 221 | + # Avoid conflicting with the PyPI package "Python". |
| 222 | + return "<Python fom Requires-Python>" |
| 223 | + |
| 224 | + @property |
| 225 | + def version(self): |
| 226 | + # type: () -> _BaseVersion |
| 227 | + return self._version |
| 228 | + |
| 229 | + def get_dependencies(self): |
| 230 | + # type: () -> Sequence[Requirement] |
| 231 | + return [] |
| 232 | + |
| 233 | + def get_install_requirement(self): |
| 234 | + # type: () -> Optional[InstallRequirement] |
| 235 | + return None |
0 commit comments