Skip to content

Commit f9c76e0

Browse files
committed
Fix __contains__ for vers:ANY/* and add test
Fixes: #30 Signed-off-by: Hritik Vijay <hritikxx8@gmail.com>
1 parent 4dccdfb commit f9c76e0

4 files changed

Lines changed: 57 additions & 33 deletions

File tree

src/univers/semver.py

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44
#
55
# Visit https://aboutcode.org and https://github.com/nexB/univers for support and download.
66

7-
import semantic_version
8-
97
from univers.utils import remove_spaces
108
from univers.version_constraint import VersionConstraint
9+
from univers.versions import SemverVersion
1110

1211
"""
1312
node-semver and Rubygems semver-like related utilities.
@@ -16,14 +15,15 @@
1615

1716
def get_caret_constraints(string):
1817
"""
19-
Return a tuple of two VersionConstraint representing the lower and upper
20-
bound of version constraint ``string`` that contains a caret node-semver-
21-
like range. Raise a ValueError if this is not a caret range.
18+
Return a tuple of two VersionConstraint of ``SemverVersion`` representing
19+
the lower and upper bound of version constraint ``string`` that contains a
20+
caret node-semver- like range. Raise a ValueError if this is not a caret
21+
range.
2222
2323
For example:
2424
>>> lower_bound, upper_bound = get_caret_constraints("^1.0.2")
25-
>>> vlow = semantic_version.Version("1.0.2")
26-
>>> vup = semantic_version.Version("2.0.0")
25+
>>> vlow = SemverVersion("1.0.2")
26+
>>> vup = SemverVersion("2.0.0")
2727
>>> assert lower_bound == VersionConstraint(comparator=">=", version=vlow)
2828
>>> assert upper_bound == VersionConstraint(comparator="<", version=vup)
2929
"""
@@ -32,8 +32,8 @@ def get_caret_constraints(string):
3232
raise ValueError(f"Invalid caret version range: {string!r}")
3333

3434
version = string.lstrip("^")
35-
lower_bound = semantic_version.Version(version)
36-
upper_bound = lower_bound.next_major()
35+
lower_bound = SemverVersion(version)
36+
upper_bound = SemverVersion(str(lower_bound.value.next_major()))
3737

3838
return (
3939
VersionConstraint(comparator=">=", version=lower_bound),
@@ -43,14 +43,15 @@ def get_caret_constraints(string):
4343

4444
def get_tilde_constraints(string, operator="~"):
4545
"""
46-
Return a tuple of two VersionConstraint representing the lower and upper
47-
bound of a version range ``string`` that contains a tilde node-semver-like
48-
range. Raise a ValueError if this is not a tilde range.
46+
Return a tuple of two VersionConstraint of ``SemverVersion`` representing
47+
the lower and upper bound of a version range ``string`` that contains a
48+
tilde node-semver-like range.
49+
Raise a ValueError if this is not a tilde range.
4950
5051
For example:
5152
>>> lower_bound, upper_bound = get_tilde_constraints("~1.0.2")
52-
>>> vlow = semantic_version.Version("1.0.2")
53-
>>> vup = semantic_version.Version("1.1.0")
53+
>>> vlow = SemverVersion("1.0.2")
54+
>>> vup = SemverVersion("1.1.0")
5455
>>> assert lower_bound == VersionConstraint(comparator=">=", version=vlow)
5556
>>> assert upper_bound == VersionConstraint(comparator="<", version=vup)
5657
"""
@@ -59,8 +60,8 @@ def get_tilde_constraints(string, operator="~"):
5960
raise ValueError(f"Invalid version range: {string!r} " f"does not start with {operator!r}")
6061

6162
version = string.lstrip(operator)
62-
lower_bound = semantic_version.Version(version)
63-
upper_bound = lower_bound.next_minor()
63+
lower_bound = SemverVersion(version)
64+
upper_bound = SemverVersion(str(lower_bound.value.next_minor()))
6465

6566
return (
6667
VersionConstraint(comparator=">=", version=lower_bound),
@@ -71,14 +72,15 @@ def get_tilde_constraints(string, operator="~"):
7172
# FIXME: this is unlikely correct https://github.com/npm/node-semver/issues/112
7273
def get_pessimistic_constraints(string):
7374
"""
74-
Return a tuple of two VersionConstraint representing the lower and upper
75-
bound of version range ``string`` that contains a pessimistic Ruby range.
76-
Raise a ValueError if this is not a pessimistic Rubygems range.
75+
Return a tuple of two VersionConstraint of ``SemverVersion`` representing
76+
the lower and upper bound of version range ``string`` that contains a
77+
pessimistic Ruby range. Raise a ValueError if this is not a pessimistic
78+
Rubygems range.
7779
7880
For example:
7981
>>> lower_bound, upper_bound = get_pessimistic_constraints("~>2.0.8")
80-
>>> vlow = semantic_version.Version("2.0.8")
81-
>>> vup = semantic_version.Version("2.1.0")
82+
>>> vlow = SemverVersion("2.0.8")
83+
>>> vup = SemverVersion("2.1.0")
8284
>>> assert lower_bound == VersionConstraint(comparator=">=", version=vlow)
8385
>>> assert upper_bound == VersionConstraint(comparator="<", version=vup)
8486
"""

src/univers/version_constraint.py

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,15 @@ class VersionConstraint:
6666
# one of the COMPARATORS
6767
comparator = attr.ib(type=str, default="=")
6868

69-
# a Version subclass instance or None
69+
# a Version subclass instance
7070
version = attr.ib(type=Version, default=None)
7171

7272
# a function for the comparator
7373
comp_operator = attr.ib(default=None, repr=False)
7474

75+
# a Version subclass
76+
version_class = attr.ib(type=Version, default=None, repr=False)
77+
7578
def __attrs_post_init__(self):
7679
# Notes: setattr is used because this is an immutable frozen instance.
7780
# See https://www.attrs.org/en/stable/init.html?#post-init
@@ -80,15 +83,26 @@ def __attrs_post_init__(self):
8083
except KeyError as e:
8184
raise ValueError(f"Unknown comparator: {self.comparator}") from e
8285

86+
if self.version and not isinstance(self.version, Version):
87+
raise TypeError(
88+
f"version must be a 'Version' instance and not: {self.version.__class__!r}"
89+
)
90+
91+
if not self.version_class:
92+
if self.version:
93+
object.__setattr__(self, "version_class", self.version.__class__)
94+
else:
95+
raise ValueError("Cannot build a VersionConstraint without a version class")
96+
8397
def __str__(self):
8498
"""
8599
Return a string representing this constraint.
86100
For example::
87-
>>> assert str(VersionConstraint(comparator=">=", version="2.3")) == ">=2.3"
88-
>>> assert str(VersionConstraint(comparator="*")) == "*"
89-
>>> assert str(VersionConstraint(comparator="<", version="2.3")) == "<2.3"
90-
>>> assert str(VersionConstraint(comparator="=", version="2.3.0")) == "2.3.0"
91-
>>> assert str(VersionConstraint(version="2.3.0")) == "2.3.0"
101+
>>> assert str(VersionConstraint(comparator=">=", version=Version("2.3"))) == ">=2.3"
102+
>>> assert str(VersionConstraint(comparator="*", version_class=Version)) == "*"
103+
>>> assert str(VersionConstraint(comparator="<", version=Version("2.3"))) == "<2.3"
104+
>>> assert str(VersionConstraint(comparator="=", version=Version("2.3.0"))) == "2.3.0"
105+
>>> assert str(VersionConstraint(version=Version("2.3.0"))) == "2.3.0"
92106
"""
93107
if self.comparator == "*":
94108
return "*"
@@ -143,7 +157,7 @@ def from_string(cls, string, version_class):
143157
version = None
144158
else:
145159
version = version_class(version)
146-
return cls(comparator, version)
160+
return cls(comparator=comparator, version=version, version_class=version_class)
147161

148162
@staticmethod
149163
def split(string):
@@ -210,11 +224,10 @@ def __contains__(self, version):
210224
>>> assert v24 in VersionConstraint(comparator="<=", version=v24)
211225
>>> assert v24 not in VersionConstraint(comparator="<", version=v24)
212226
"""
213-
214-
if not isinstance(version, self.version.__class__):
227+
if not isinstance(version, self.version_class):
215228
raise ValueError(
216229
f"Cannot compare {version.__class__!r} instance "
217-
f"with {self.version.__class__!r} instance."
230+
f"with {self.version_class!r} instance."
218231
)
219232
return self.comp_operator(version, self.version)
220233

src/univers/version_range.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,9 @@ def from_string(cls, vers, simplify=False, validate=False):
114114
if constraints.startswith("*"):
115115
if constraints != "*":
116116
raise ValueError(f"{vers!r} contains an invalid '*' constraint.")
117-
return range_class([VersionConstraint.from_string(string="*", version_class=None)])
117+
return range_class(
118+
[VersionConstraint.from_string(string="*", version_class=version_class)]
119+
)
118120

119121
parsed_constraints = []
120122

@@ -774,7 +776,9 @@ def from_native(cls, string):
774776
"""
775777
cleaned = remove_spaces(string).lower()
776778
if cleaned == "all":
777-
return cls(constraints=[VersionConstraint(comparator="*")])
779+
return cls(
780+
constraints=[VersionConstraint(comparator="*", version_class=cls.version_class)]
781+
)
778782

779783
constraints = []
780784

tests/test_version_range.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,3 +150,8 @@ def test_GemVersionRange_from_native_range_with_pessimistic_operator(self):
150150
VersionConstraint(comparator=">=", version=RubygemsVersion(string="2.0.8")),
151151
VersionConstraint(comparator="<", version=RubygemsVersion(string="2.1")),
152152
)
153+
154+
def test_VersionRange_contains_works_for_star_range(self):
155+
from univers.versions import SemverVersion
156+
157+
SemverVersion("1.0.0") in VersionRange.from_string("vers:nginx/*")

0 commit comments

Comments
 (0)