-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Resolves #489
- Loading branch information
Showing
2 changed files
with
117 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
"""VersionMap interface for managing package settings in plugins.""" | ||
|
||
import typing | ||
|
||
from packaging.requirements import Requirement | ||
from packaging.version import Version | ||
|
||
|
||
class VersionMap: | ||
def __init__(self, initial_content: dict | None = None) -> None: | ||
self._content: dict[Version, typing.Any] = {} | ||
for k, v in (initial_content or {}).items(): | ||
self.add(k, v) | ||
|
||
def add(self, key: Version | str, value: typing.Any) -> None: | ||
if not isinstance(key, Version): | ||
key = Version(key) | ||
self._content[key] = value | ||
|
||
def versions(self) -> typing.Iterable[Version]: | ||
# return the values sorted highest to lowest | ||
return reversed(sorted(self._content.keys())) | ||
|
||
def lookup( | ||
self, | ||
req: Requirement, | ||
constraint: Requirement | None = None, | ||
allow_prerelease: bool = False, | ||
) -> typing.Any: | ||
for version in self.versions(): | ||
if not req.specifier.contains(version, prereleases=allow_prerelease): | ||
continue | ||
if constraint and not constraint.specifier.contains( | ||
version, prereleases=allow_prerelease | ||
): | ||
continue | ||
return self._content[version] | ||
raise ValueError(f"No version matched {req} with constraint {constraint}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import pytest | ||
from packaging.requirements import Requirement | ||
from packaging.version import Version | ||
|
||
from fromager.versionmap import VersionMap | ||
|
||
|
||
def test_initialize(): | ||
m = VersionMap( | ||
{ | ||
"1.2": "value for 1.2", | ||
Version("1.3"): "value for 1.3", | ||
"1.0": "value for 1.0", | ||
} | ||
) | ||
assert list(m.versions()) == [Version("1.3"), Version("1.2"), Version("1.0")] | ||
|
||
|
||
def test_lookup(): | ||
m = VersionMap( | ||
{ | ||
"1.2": "value for 1.2", | ||
Version("1.3"): "value for 1.3", | ||
"1.0": "value for 1.0", | ||
} | ||
) | ||
assert m.lookup(Requirement("pkg")) == "value for 1.3" | ||
assert m.lookup(Requirement("pkg>1.0")) == "value for 1.3" | ||
assert m.lookup(Requirement("pkg<1.3")) == "value for 1.2" | ||
|
||
|
||
def test_prerelease(): | ||
m = VersionMap( | ||
{ | ||
Version("0.4.1b0"): "value for 0.4.1b", | ||
"1.2": "value for 1.2", | ||
Version("1.3"): "value for 1.3", | ||
"1.0": "value for 1.0", | ||
"1.5.0a0": "value for 1.5.0a0", | ||
} | ||
) | ||
assert m.lookup(Requirement("pkg")) == "value for 1.3" | ||
assert m.lookup(Requirement("pkg>1.0")) == "value for 1.3" | ||
assert m.lookup(Requirement("pkg<1.3")) == "value for 1.2" | ||
assert m.lookup(Requirement("pkg"), allow_prerelease=True) == "value for 1.5.0a0" | ||
with pytest.raises(ValueError): | ||
assert ( | ||
m.lookup(Requirement("pkg"), Requirement("pkg<1.0")) == "value for 0.4.1b" | ||
) | ||
assert ( | ||
m.lookup(Requirement("pkg"), Requirement("pkg<1.0"), allow_prerelease=True) | ||
== "value for 0.4.1b" | ||
) | ||
|
||
|
||
def test_with_constraint(): | ||
m = VersionMap( | ||
{ | ||
"1.2": "value for 1.2", | ||
Version("1.3"): "value for 1.3", | ||
"1.0": "value for 1.0", | ||
} | ||
) | ||
assert m.lookup(Requirement("pkg"), Requirement("pkg<1.3")) == "value for 1.2" | ||
assert m.lookup(Requirement("pkg>1.0"), Requirement("pkg==1.2")) == "value for 1.2" | ||
|
||
|
||
def test_no_match(): | ||
m = VersionMap( | ||
{ | ||
"1.2": "value for 1.2", | ||
Version("1.3"): "value for 1.3", | ||
"1.0": "value for 1.0", | ||
} | ||
) | ||
with pytest.raises(ValueError): | ||
m.lookup(Requirement("pkg"), Requirement("pkg<1.0")) | ||
with pytest.raises(ValueError): | ||
m.lookup(Requirement("pkg>1.0"), Requirement("pkg<1.0")) |