diff --git a/src/univers/version_range.py b/src/univers/version_range.py index 69f84f24..bee601ef 100644 --- a/src/univers/version_range.py +++ b/src/univers/version_range.py @@ -21,6 +21,8 @@ from univers.utils import remove_spaces from univers.version_constraint import VersionConstraint from univers.version_constraint import contains_version +from univers.versions import AllVersion +from univers.versions import NoneVersion class InvalidVersionRange(Exception): @@ -220,6 +222,13 @@ def __contains__(self, version): object. A version is contained in a VersionRange if it satisfies its constraints according to ``vers`` rules. """ + + if self.version_class is AllVersion: + return True + + if self.version_class is NoneVersion: + return False + if not isinstance(version, self.version_class): raise TypeError( f"{version!r} is not of expected type: {self.version_class!r}", @@ -712,9 +721,9 @@ class PypiVersionRange(VersionRange): def from_native(cls, string): """ Return a VersionRange built from a PyPI PEP440 version specifiers ``string``. - Raise an a univers.versions.InvalidVersion + Raise a univers.versions.InvalidVersion """ - # TODO: environment markers are yet supported + # TODO: environment markers are not yet supported # TODO: handle .* version, ~= and === operators if ";" in string: @@ -1177,6 +1186,16 @@ class MattermostVersionRange(VersionRange): version_class = versions.SemverVersion +class AllVersionRange(VersionRange): + scheme = "all" + version_class = versions.AllVersion + + +class NoneVersionRange(VersionRange): + scheme = "none" + version_class = versions.NoneVersion + + def from_gitlab_native(gitlab_scheme, string): purl_scheme = gitlab_scheme if gitlab_scheme not in PURL_TYPE_BY_GITLAB_SCHEME.values(): @@ -1419,6 +1438,8 @@ def build_range_from_snyk_advisory_string(scheme: str, string: Union[str, List]) "openssl": OpensslVersionRange, "mattermost": MattermostVersionRange, "conan": ConanVersionRange, + "all": AllVersionRange, + "none": NoneVersionRange, } PURL_TYPE_BY_GITLAB_SCHEME = { diff --git a/src/univers/versions.py b/src/univers/versions.py index 14b3e007..c06f4ff0 100644 --- a/src/univers/versions.py +++ b/src/univers/versions.py @@ -123,7 +123,7 @@ def build_value(self, string): def satisfies(self, constraint): """ - Return True is this Version satisfies the ``constraint`` + Return True if this Version satisfies the ``constraint`` VersionConstraint. Satisfying means that this version is "within" the ``constraint``. """ @@ -133,6 +133,18 @@ def __str__(self): return str(self.value) +class AllVersion(Version): + @classmethod + def is_valid(cls, string): + return string == "vers:all/*" + + +class NoneVersion(Version): + @classmethod + def is_valid(cls, string): + return string == "vers:none/*" + + class GenericVersion(Version): @classmethod def is_valid(cls, string): diff --git a/tests/test_version_range.py b/tests/test_version_range.py index 2d3c4112..104646f8 100644 --- a/tests/test_version_range.py +++ b/tests/test_version_range.py @@ -28,6 +28,7 @@ from univers.versions import PypiVersion from univers.versions import RubygemsVersion from univers.versions import SemverVersion +from univers.versions import Version class TestVersionRange(TestCase): @@ -546,3 +547,25 @@ def test_version_range_normalize_case3(): nvr = vr.normalize(known_versions=known_versions) assert str(nvr) == "vers:pypi/>=1.0.0|<=1.3.0|3.0.0" + + +def test_version_range_all(): + all_vers = VersionRange.from_string("vers:all/*") + assert all_vers.contains(Version("1.2.3")) + assert PypiVersion("2.0.3") in all_vers + # test for invalid all range specification + with pytest.raises(Exception): + VersionRange.from_string("vers:all/>1.2.3") + with pytest.raises(Exception): + VersionRange.from_string("vers:all/*|>1.2.3") + + +def test_version_range_none(): + none_vers = VersionRange.from_string("vers:none/*") + assert not none_vers.contains(Version("1.2.3")) + assert PypiVersion("2.0.3") not in none_vers + # test for invalid all range specification + with pytest.raises(Exception): + VersionRange.from_string("vers:none/!1.2.3") + with pytest.raises(Exception): + VersionRange.from_string("vers:none/*|>1.2.3")