Skip to content

Commit 9038de0

Browse files
committed
pylock: use Version type instead of str
1 parent 99a078b commit 9038de0

File tree

1 file changed

+53
-22
lines changed

1 file changed

+53
-22
lines changed

src/pip/_internal/models/pylock.py

Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,18 @@
33
import re
44
from dataclasses import dataclass
55
from pathlib import Path
6-
from typing import Any, Dict, Iterable, List, Optional, Protocol, Tuple, Type, TypeVar
6+
from typing import (
7+
Any,
8+
Dict,
9+
Iterable,
10+
List,
11+
Optional,
12+
Protocol,
13+
Tuple,
14+
Type,
15+
TypeVar,
16+
Union,
17+
)
718

819
from pip._vendor import tomli_w
920
from pip._vendor.packaging.version import InvalidVersion, Version
@@ -32,8 +43,20 @@ def is_valid_pylock_file_name(path: Path) -> bool:
3243
return path.name == "pylock.toml" or bool(re.match(PYLOCK_FILE_NAME_RE, path.name))
3344

3445

46+
def _toml_key(key: str) -> str:
47+
return key.replace("_", "-")
48+
49+
50+
def _toml_value(value: T) -> Union[str, T]:
51+
if isinstance(value, Version):
52+
return str(value)
53+
return value
54+
55+
3556
def _toml_dict_factory(data: List[Tuple[str, Any]]) -> Dict[str, Any]:
36-
return {key.replace("_", "-"): value for key, value in data if value is not None}
57+
return {
58+
_toml_key(key): _toml_value(value) for key, value in data if value is not None
59+
}
3760

3861

3962
def _get(
@@ -58,6 +81,23 @@ def _get_required(d: Dict[str, Any], expected_type: Type[T], key: str) -> T:
5881
return value
5982

6083

84+
def _get_version(d: Dict[str, Any], key: str) -> Optional[Version]:
85+
value = _get(d, str, key)
86+
if value is None:
87+
return None
88+
try:
89+
return Version(value)
90+
except InvalidVersion:
91+
raise PylockUnsupportedVersionError(f"invalid version {value!r}")
92+
93+
94+
def _get_required_version(d: Dict[str, Any], key: str) -> Version:
95+
value = _get_version(d, key)
96+
if value is None:
97+
raise PylockRequiredKeyError(key)
98+
return value
99+
100+
61101
def _get_object(
62102
d: Dict[str, Any], expected_type: Type[PylockDataClassT], key: str
63103
) -> Optional[PylockDataClassT]:
@@ -233,7 +273,7 @@ def from_dict(cls, d: Dict[str, Any]) -> Self:
233273
@dataclass
234274
class Package:
235275
name: str
236-
version: Optional[str] = None
276+
version: Optional[Version] = None
237277
# (not supported) marker: Optional[str]
238278
# (not supported) requires_python: Optional[str]
239279
# (not supported) dependencies
@@ -255,7 +295,7 @@ def __post_init__(self) -> None:
255295
def from_dict(cls, d: Dict[str, Any]) -> Self:
256296
package = cls(
257297
name=_get_required(d, str, "name"),
258-
version=_get(d, str, "version"),
298+
version=_get_version(d, "version"),
259299
vcs=_get_object(d, PackageVcs, "vcs"),
260300
directory=_get_object(d, PackageDirectory, "directory"),
261301
archive=_get_object(d, PackageArchive, "archive"),
@@ -314,7 +354,7 @@ def from_install_requirement(cls, ireq: InstallRequirement, base_dir: Path) -> S
314354
# should never happen
315355
raise NotImplementedError()
316356
else:
317-
package_version = str(dist.version)
357+
package_version = dist.version
318358
if isinstance(download_info.info, ArchiveInfo):
319359
if not download_info.info.hashes:
320360
raise NotImplementedError()
@@ -351,7 +391,7 @@ def from_install_requirement(cls, ireq: InstallRequirement, base_dir: Path) -> S
351391

352392
@dataclass
353393
class Pylock:
354-
lock_version: str = "1.0"
394+
lock_version: Version = Version("1.0")
355395
# (not supported) environments: Optional[List[str]]
356396
# (not supported) requires_python: Optional[str]
357397
# (not supported) extras: List[str] = []
@@ -360,24 +400,15 @@ class Pylock:
360400
packages: List[Package] = dataclasses.field(default_factory=list)
361401
# (not supported) tool: Optional[Dict[str, Any]]
362402

363-
def _validate_version(self) -> None:
364-
if not self.lock_version:
365-
raise PylockRequiredKeyError("lock-version")
366-
try:
367-
lock_version = Version(self.lock_version)
368-
except InvalidVersion:
403+
def __post_init__(self) -> None:
404+
if self.lock_version < Version("1") or self.lock_version >= Version("2"):
369405
raise PylockUnsupportedVersionError(
370-
f"invalid pylock version {self.lock_version!r}"
406+
f"pylock version {self.lock_version} is not supported"
371407
)
372-
if lock_version < Version("1") or lock_version >= Version("2"):
373-
raise PylockUnsupportedVersionError(
374-
f"pylock version {lock_version} is not supported"
408+
if self.lock_version > Version("1.0"):
409+
logging.warning(
410+
"pylock minor version %s is not supported", self.lock_version
375411
)
376-
if lock_version > Version("1.0"):
377-
logging.warning("pylock minor version %s is not supported", lock_version)
378-
379-
def __post_init__(self) -> None:
380-
self._validate_version()
381412

382413
def as_toml(self) -> str:
383414
return tomli_w.dumps(self.to_dict())
@@ -388,7 +419,7 @@ def to_dict(self) -> Dict[str, Any]:
388419
@classmethod
389420
def from_dict(cls, d: Dict[str, Any]) -> Self:
390421
return cls(
391-
lock_version=_get_required(d, str, "lock-version"),
422+
lock_version=_get_required_version(d, "lock-version"),
392423
created_by=_get_required(d, str, "created-by"),
393424
packages=_get_required_list_of_objects(d, Package, "packages"),
394425
)

0 commit comments

Comments
 (0)