Skip to content

Commit 8f0d727

Browse files
committed
Add function to parse bracket notation constraints
Signed-off-by: Keshav Priyadarshi <[email protected]>
1 parent c833b97 commit 8f0d727

File tree

2 files changed

+78
-27
lines changed

2 files changed

+78
-27
lines changed

src/univers/version_range.py

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ def from_native(cls, string):
480480
return cls(constraints=constraints)
481481

482482

483-
def split_req(string, comparators, comparators_rear={}, default=None, strip=""):
483+
def split_req(string, comparators, default=None, strip=""):
484484
"""
485485
Return a tuple of (vers comparator, version) strings given an common version
486486
requirement``string`` such as "> 2.3" or "<= 2.3" using the ``comparators``
@@ -501,8 +501,6 @@ def split_req(string, comparators, comparators_rear={}, default=None, strip=""):
501501
>>> assert split_req(">= 2.3", comparators=comps) == (">=", "2.3",)
502502
>>> assert split_req("<= 2.3", comparators=comps) == ("<=", "2.3",)
503503
>>> assert split_req("(< = 2.3 )", comparators=comps, strip=")(") == ("<=", "2.3",)
504-
>>> comps_rear = {")": "<", "]": "<="}
505-
>>> assert split_req(" 2.3 ]", comparators=comps, comparators_rear=comps_rear) == ("<=", "2.3",)
506504
507505
With a default, we return the default comparator::
508506
@@ -523,12 +521,6 @@ def split_req(string, comparators, comparators_rear={}, default=None, strip=""):
523521
version = constraint_string.lstrip(native_comparator)
524522
return vers_comparator, version
525523

526-
# Some bracket notation comparators starts from end.
527-
for native_comparator, vers_comparator in comparators_rear.items():
528-
if constraint_string.endswith(native_comparator):
529-
version = constraint_string.rstrip(native_comparator)
530-
return vers_comparator, version
531-
532524
if default:
533525
return default, constraint_string
534526

@@ -1300,14 +1292,35 @@ def build_range_from_github_advisory_constraint(scheme: str, string: Union[str,
13001292
">=": ">=",
13011293
"<": "<",
13021294
">": ">",
1303-
"(": ">",
1304-
"[": ">=",
13051295
}
13061296

1307-
vers_by_snyk_native_comparators_rear = {
1308-
")": "<",
1309-
"]": "<=",
1310-
}
1297+
1298+
def split_req_bracket_notation(string):
1299+
"""
1300+
Return a tuple of (vers comparator, version) strings given an bracket notation
1301+
version requirement ``string`` such as "(2.3" or "3.9]"
1302+
1303+
For example::
1304+
1305+
>>> assert split_req_bracket_notation(" 2.3 ]") == ("<=", "2.3")
1306+
>>> assert split_req_bracket_notation("( 3.9") == (">", "3.9")
1307+
"""
1308+
comparators_front = {"(": ">", "[": ">="}
1309+
comparators_rear = {")": "<", "]": "<="}
1310+
1311+
constraint_string = remove_spaces(string).strip()
1312+
1313+
for native_comparator, vers_comparator in comparators_front.items():
1314+
if constraint_string.startswith(native_comparator):
1315+
version = constraint_string.lstrip(native_comparator)
1316+
return vers_comparator, version
1317+
1318+
for native_comparator, vers_comparator in comparators_rear.items():
1319+
if constraint_string.endswith(native_comparator):
1320+
version = constraint_string.rstrip(native_comparator)
1321+
return vers_comparator, version
1322+
1323+
raise ValueError(f"Unknown comparator in version requirement: {string!r} ")
13111324

13121325

13131326
def build_range_from_snyk_advisory_string(scheme: str, string: Union[str, List]):
@@ -1346,11 +1359,13 @@ def build_range_from_snyk_advisory_string(scheme: str, string: Union[str, List])
13461359
constraints = snyk_constraints.split(" ")
13471360

13481361
for constraint in constraints:
1349-
comparator, version = split_req(
1350-
string=constraint,
1351-
comparators=vers_by_snyk_native_comparators,
1352-
comparators_rear=vers_by_snyk_native_comparators_rear,
1353-
)
1362+
if any(comp in constraint for comp in "[]()"):
1363+
comparator, version = split_req_bracket_notation(string=constraint)
1364+
else:
1365+
comparator, version = split_req(
1366+
string=constraint,
1367+
comparators=vers_by_snyk_native_comparators,
1368+
)
13541369
if comparator and version:
13551370
version = vrc.version_class(version)
13561371
version_constraints.append(
@@ -1382,10 +1397,7 @@ def build_range_from_discrete_version_string(scheme: str, string: Union[str, Lis
13821397
string = [string]
13831398

13841399
for item in string:
1385-
version = item.strip().lstrip("vV")
1386-
if version == "0":
1387-
continue
1388-
1400+
version = item.strip()
13891401
version = vrc.version_class(version)
13901402
version_constraints.append(
13911403
VersionConstraint(

tests/test_version_range.py

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
from univers.version_range import OpensslVersionRange
2121
from univers.version_range import PypiVersionRange
2222
from univers.version_range import VersionRange
23+
from univers.version_range import build_range_from_discrete_version_string
24+
from univers.version_range import build_range_from_snyk_advisory_string
2325
from univers.version_range import from_gitlab_native
2426
from univers.versions import InvalidVersion
2527
from univers.versions import NugetVersion
@@ -85,6 +87,11 @@ def test_VersionRange_contains_version_in_between(self):
8587
version_range = VersionRange.from_string(vers)
8688
assert version_range.contains(PypiVersion("1.5"))
8789

90+
def test_VersionRange_contains_filterd_constraint_edge_case(self):
91+
vers = "vers:pypi/<=1.3.0|3.0.0"
92+
version_range = VersionRange.from_string(vers)
93+
assert version_range.contains(PypiVersion("1.0.0"))
94+
8895
def test_VersionRange_from_string_pypi(self):
8996
vers = "vers:pypi/0.0.2|0.0.6|0.0.0|0.0.1|0.0.4|0.0.5|0.0.3"
9097
version_range = VersionRange.from_string(vers)
@@ -458,8 +465,40 @@ def test_mattermost_version_range():
458465
) == VersionRange.from_string("vers:mattermost/>=5.0")
459466

460467

468+
def test_build_range_from_snyk_advisory_string():
469+
expression = [">=4.0.0, <4.0.10", ">7.0.0, <8.0.1"]
470+
vr = build_range_from_snyk_advisory_string("pypi", expression)
471+
expected = "vers:pypi/>=4.0.0|<4.0.10|>7.0.0|<8.0.1"
472+
473+
assert str(vr) == expected
474+
475+
476+
def test_build_range_from_snyk_advisory_string_bracket():
477+
expression = ["[3.0.0,3.1.25)", "[1.0.0,1.0.5)"]
478+
vr = build_range_from_snyk_advisory_string("nuget", expression)
479+
expected = "vers:nuget/>=1.0.0|<1.0.5|>=3.0.0|<3.1.25"
480+
481+
assert str(vr) == expected
482+
483+
484+
def test_build_range_from_snyk_advisory_string_spaced():
485+
expression = [">=4.1.0 <4.4.1", ">2.1.0 <=3.2.7"]
486+
vr = build_range_from_snyk_advisory_string("composer", expression)
487+
expected = "vers:composer/>2.1.0|<=3.2.7|>=4.1.0|<4.4.1"
488+
489+
assert str(vr) == expected
490+
491+
492+
def test_build_range_from_discrete_version_string():
493+
expression = ["4.1.0", " 4.4.1", "2.1.0 ", " 3.2.7 "]
494+
vr = build_range_from_discrete_version_string("pypi", expression)
495+
expected = "vers:pypi/2.1.0|3.2.7|4.1.0|4.4.1"
496+
497+
assert str(vr) == expected
498+
499+
461500
def test_version_range_normalize_case1():
462-
known_versions = ["3.0.0", "1.0.0", "2.0.0", "1.3.0", "1.1.0", "1.2.0"]
501+
known_versions = ["4.0.0", "3.0.0", "1.0.0", "2.0.0", "1.3.0", "1.1.0", "1.2.0"]
463502

464503
vr = VersionRange.from_string("vers:pypi/<=1.1.0|>=1.2.0|<=1.3.0|3.0.0")
465504
nvr = vr.normalize(known_versions=known_versions)
@@ -468,7 +507,7 @@ def test_version_range_normalize_case1():
468507

469508

470509
def test_version_range_normalize_case2():
471-
known_versions = ["3.0.0", "1.0.0", "2.0.0", "1.3.0", "1.1.0", "1.2.0"]
510+
known_versions = ["4.0.0", "3.0.0", "1.0.0", "2.0.0", "1.3.0", "1.1.0", "1.2.0"]
472511

473512
vr = VersionRange.from_string("vers:pypi/<=1.3.0|3.0.0")
474513
nvr = vr.normalize(known_versions=known_versions)
@@ -477,7 +516,7 @@ def test_version_range_normalize_case2():
477516

478517

479518
def test_version_range_normalize_case3():
480-
known_versions = ["3.0.0", "1.0.0", "2.0.0", "1.3.0", "1.1.0", "1.2.0"]
519+
known_versions = ["4.0.0", "3.0.0", "1.0.0", "2.0.0", "1.3.0", "1.1.0", "1.2.0"]
481520

482521
vr = VersionRange.from_string("vers:pypi/<2.0.0|3.0.0")
483522
nvr = vr.normalize(known_versions=known_versions)

0 commit comments

Comments
 (0)