Skip to content

Commit 7a2cb8b

Browse files
committed
pylock: support requires-python
1 parent 80dda57 commit 7a2cb8b

File tree

2 files changed

+21
-3
lines changed

2 files changed

+21
-3
lines changed

src/pip/_internal/models/pylock.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from pip._vendor import tomli_w
2020
from pip._vendor.packaging.markers import InvalidMarker, Marker
21+
from pip._vendor.packaging.specifiers import InvalidSpecifier, SpecifierSet
2122
from pip._vendor.packaging.version import InvalidVersion, Version
2223
from pip._vendor.typing_extensions import Self
2324

@@ -49,7 +50,7 @@ def _toml_key(key: str) -> str:
4950

5051

5152
def _toml_value(value: T) -> Union[str, T]:
52-
if isinstance(value, (Version, Marker)):
53+
if isinstance(value, (Version, Marker, SpecifierSet)):
5354
return str(value)
5455
return value
5556

@@ -109,6 +110,16 @@ def _get_marker(d: Dict[str, Any], key: str) -> Optional[Marker]:
109110
raise PylockValidationError(f"invalid marker {value!r}")
110111

111112

113+
def _get_specifier_set(d: Dict[str, Any], key: str) -> Optional[SpecifierSet]:
114+
value = _get(d, str, key)
115+
if value is None:
116+
return None
117+
try:
118+
return SpecifierSet(value)
119+
except InvalidSpecifier:
120+
raise PylockValidationError(f"invalid version specifier {value!r}")
121+
122+
112123
def _get_object(
113124
d: Dict[str, Any], expected_type: Type[PylockDataClassT], key: str
114125
) -> Optional[PylockDataClassT]:
@@ -286,7 +297,7 @@ class Package:
286297
name: str
287298
version: Optional[Version] = None
288299
marker: Optional[Marker] = None
289-
# (not supported) requires_python: Optional[str]
300+
requires_python: Optional[SpecifierSet] = None
290301
# (not supported) dependencies
291302
vcs: Optional[PackageVcs] = None
292303
directory: Optional[PackageDirectory] = None
@@ -307,6 +318,7 @@ def from_dict(cls, d: Dict[str, Any]) -> Self:
307318
package = cls(
308319
name=_get_required(d, str, "name"),
309320
version=_get_version(d, "version"),
321+
requires_python=_get_specifier_set(d, "requires-python"),
310322
marker=_get_marker(d, "marker"),
311323
vcs=_get_object(d, PackageVcs, "vcs"),
312324
directory=_get_object(d, PackageDirectory, "directory"),
@@ -394,6 +406,7 @@ def from_install_requirement(cls, ireq: InstallRequirement, base_dir: Path) -> S
394406
name=dist.canonical_name,
395407
version=package_version,
396408
marker=None,
409+
requires_python=None,
397410
vcs=package_vcs,
398411
directory=package_directory,
399412
archive=package_archive,
@@ -406,7 +419,7 @@ def from_install_requirement(cls, ireq: InstallRequirement, base_dir: Path) -> S
406419
class Pylock:
407420
lock_version: Version = Version("1.0")
408421
# (not supported) environments: Optional[List[str]]
409-
# (not supported) requires_python: Optional[str]
422+
requires_python: Optional[SpecifierSet] = None
410423
# (not supported) extras: List[str] = []
411424
# (not supported) dependency_groups: List[str] = []
412425
created_by: str = "pip"
@@ -437,6 +450,7 @@ def from_dict(cls, d: Dict[str, Any]) -> Self:
437450
return cls(
438451
lock_version=_get_required_version(d, "lock-version"),
439452
created_by=_get_required(d, str, "created-by"),
453+
requires_python=_get_specifier_set(d, "requires-python"),
440454
packages=_get_required_list_of_objects(d, Package, "packages"),
441455
)
442456

tests/unit/test_pylock.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import pytest
22

33
from pip._vendor.packaging.markers import Marker
4+
from pip._vendor.packaging.specifiers import SpecifierSet
45
from pip._vendor.packaging.version import Version
56

67
from pip._internal.models.pylock import (
@@ -89,11 +90,13 @@ def test_pylock_basic_package() -> None:
8990
data = {
9091
"lock-version": "1.0",
9192
"created-by": "pip",
93+
"requires-python": ">=3.10",
9294
"packages": [
9395
{
9496
"name": "example",
9597
"version": "1.0",
9698
"marker": 'os_name == "posix"',
99+
"requires-python": "!=3.10.1,>=3.10",
97100
"directory": {
98101
"path": ".",
99102
"editable": False,
@@ -105,4 +108,5 @@ def test_pylock_basic_package() -> None:
105108
package = pylock.packages[0]
106109
assert package.version == Version("1.0")
107110
assert package.marker == Marker('os_name == "posix"')
111+
assert package.requires_python == SpecifierSet(">=3.10, !=3.10.1")
108112
assert pylock.to_dict() == data

0 commit comments

Comments
 (0)