From ccaaf85355517ebd3a1de09eaa3ede748f1d97e6 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Morin Date: Sat, 16 Sep 2023 11:19:08 -0400 Subject: [PATCH 01/12] Move rez.vendor.version to rez.version. Not all imports are renamed yet. Only the minimum amount of changes required to run the version tests. Signed-off-by: Jean-Christophe Morin --- src/rez/package_filter.py | 2 +- src/rez/package_order.py | 2 +- src/rez/package_resources.py | 2 +- src/rez/package_serialise.py | 2 +- src/rez/packages.py | 4 +- src/rez/resolved_context.py | 4 +- src/rez/resolver.py | 2 +- src/rez/rex_bindings.py | 4 +- src/rez/solver.py | 4 +- src/rez/tests/test_version.py | 498 ++++++++++++++++++- src/rez/utils/formatting.py | 2 +- src/rez/utils/yaml.py | 4 +- src/rez/vendor/version/test.py | 505 -------------------- src/rez/{vendor => }/version/__init__.py | 0 src/rez/{vendor => }/version/requirement.py | 4 +- src/rez/{vendor => }/version/util.py | 0 src/rez/{vendor => }/version/version.py | 3 +- 17 files changed, 512 insertions(+), 530 deletions(-) delete mode 100644 src/rez/vendor/version/test.py rename src/rez/{vendor => }/version/__init__.py (100%) rename src/rez/{vendor => }/version/requirement.py (99%) rename src/rez/{vendor => }/version/util.py (100%) rename src/rez/{vendor => }/version/version.py (99%) diff --git a/src/rez/package_filter.py b/src/rez/package_filter.py index d76139b2e..9b2dae609 100644 --- a/src/rez/package_filter.py +++ b/src/rez/package_filter.py @@ -7,7 +7,7 @@ from rez.config import config from rez.utils.data_utils import cached_property, cached_class_property from rez.vendor.six import six -from rez.vendor.version.requirement import VersionedObject, Requirement +from rez.version.requirement import VersionedObject, Requirement from hashlib import sha1 import fnmatch import re diff --git a/src/rez/package_order.py b/src/rez/package_order.py index 9d3aaac65..9dcec3da2 100644 --- a/src/rez/package_order.py +++ b/src/rez/package_order.py @@ -7,7 +7,7 @@ from rez.config import config from rez.utils.data_utils import cached_class_property -from rez.vendor.version.version import Version +from rez.version.version import Version class PackageOrder(object): diff --git a/src/rez/package_resources.py b/src/rez/package_resources.py index f4b497249..3698663f4 100644 --- a/src/rez/package_resources.py +++ b/src/rez/package_resources.py @@ -12,7 +12,7 @@ from rez.utils.formatting import PackageRequest from rez.exceptions import PackageMetadataError, ResourceError from rez.config import config, Config, create_config -from rez.vendor.version.version import Version +from rez.version.version import Version from rez.vendor.schema.schema import Schema, SchemaError, Optional, Or, And, Use from rez.vendor.six import six diff --git a/src/rez/package_serialise.py b/src/rez/package_serialise.py index 04f6d6de6..0ff22a098 100644 --- a/src/rez/package_serialise.py +++ b/src/rez/package_serialise.py @@ -7,7 +7,7 @@ from rez.serialise import FileFormat from rez.package_resources import help_schema, late_bound from rez.vendor.schema.schema import Schema, Optional, And, Or, Use -from rez.vendor.version.version import Version +from rez.version.version import Version from rez.utils.schema import extensible_schema_dict from rez.utils.sourcecode import SourceCode from rez.utils.formatting import PackageRequest, indent, \ diff --git a/src/rez/packages.py b/src/rez/packages.py index fab8b292e..fb43914e3 100644 --- a/src/rez/packages.py +++ b/src/rez/packages.py @@ -14,8 +14,8 @@ from rez.utils.schema import schema_keys from rez.utils.resources import ResourceHandle, ResourceWrapper from rez.exceptions import PackageFamilyNotFoundError, ResourceError -from rez.vendor.version.version import Version, VersionRange -from rez.vendor.version.requirement import VersionedObject +from rez.version.version import Version, VersionRange +from rez.version.requirement import VersionedObject from rez.vendor.six import six from rez.serialise import FileFormat from rez.config import config diff --git a/src/rez/resolved_context.py b/src/rez/resolved_context.py index 4e41ca817..5aa879237 100644 --- a/src/rez/resolved_context.py +++ b/src/rez/resolved_context.py @@ -36,8 +36,8 @@ read_graph_from_string from rez.utils.resolve_graph import failure_detail_from_graph from rez.vendor.six import six -from rez.vendor.version.version import VersionRange -from rez.vendor.version.requirement import Requirement +from rez.version.version import VersionRange +from rez.version.requirement import Requirement from rez.vendor.enum import Enum from rez.vendor import yaml from rez.utils import json diff --git a/src/rez/resolver.py b/src/rez/resolver.py index 4acc624de..84eb416fa 100644 --- a/src/rez/resolver.py +++ b/src/rez/resolver.py @@ -10,7 +10,7 @@ from rez.utils.logging_ import log_duration from rez.config import config from rez.vendor.enum import Enum -from rez.vendor.version.requirement import Requirement +from rez.version.requirement import Requirement from contextlib import contextmanager from hashlib import sha1 diff --git a/src/rez/rex_bindings.py b/src/rez/rex_bindings.py index 9deca06f8..155d6d82e 100644 --- a/src/rez/rex_bindings.py +++ b/src/rez/rex_bindings.py @@ -11,8 +11,8 @@ unnecessary data from Rex, and provide APIs that will not change. """ from rez.vendor.six import six -from rez.vendor.version.version import VersionRange -from rez.vendor.version.requirement import Requirement +from rez.version.version import VersionRange +from rez.version.requirement import Requirement basestring = six.string_types[0] diff --git a/src/rez/solver.py b/src/rez/solver.py index c90b87328..0d1f34213 100644 --- a/src/rez/solver.py +++ b/src/rez/solver.py @@ -23,8 +23,8 @@ from rez.vendor.pygraph.algorithms.accessibility import accessibility from rez.exceptions import PackageNotFoundError, ResolveError, \ PackageFamilyNotFoundError, RezSystemError -from rez.vendor.version.version import VersionRange -from rez.vendor.version.requirement import VersionedObject, Requirement, \ +from rez.version.version import VersionRange +from rez.version.requirement import VersionedObject, Requirement, \ RequirementList from rez.vendor.enum import Enum from contextlib import contextmanager diff --git a/src/rez/tests/test_version.py b/src/rez/tests/test_version.py index ebffd3013..a602e5b4c 100644 --- a/src/rez/tests/test_version.py +++ b/src/rez/tests/test_version.py @@ -2,16 +2,504 @@ # Copyright Contributors to the Rez Project -""" -unit tests for 'version' module -""" +from rez.version.version import Version, AlphanumericVersionToken, \ + VersionRange, reverse_sort_key, _ReversedComparable +from rez.version.requirement import Requirement, RequirementList +from rez.version.util import VersionError +import random +import textwrap import unittest -from rez.vendor.version.test import TestVersionSchema -class TestVersions(TestVersionSchema): + +def _print(txt=''): + # uncomment for verbose output + #print txt pass +class TestVersionSchema(unittest.TestCase): + make_token = AlphanumericVersionToken + + def __init__(self, fn): + unittest.TestCase.__init__(self, fn) + + def _test_strict_weak_ordering(self, a, b): + self.assertTrue(a == a) + self.assertTrue(b == b) + + e = (a == b) + ne = (a != b) + lt = (a < b) + lte = (a <= b) + gt = (a > b) + gte = (a >= b) + + _print('\n' + textwrap.dedent( + """ + '%s' '%s' + ==: %s + !=: %s + <: %s + <=: %s + >: %s + >=: %s + """).strip() % (a, b, e, ne, lt, lte, gt, gte)) + + self.assertTrue(e != ne) + if e: + self.assertTrue(not lt) + self.assertTrue(not gt) + self.assertTrue(lte) + self.assertTrue(gte) + else: + self.assertTrue(lt != gt) + self.assertTrue(lte != gte) + self.assertTrue(lt == lte) + self.assertTrue(gt == gte) + + if not isinstance(a, _ReversedComparable): + self._test_strict_weak_ordering(reverse_sort_key(a), + reverse_sort_key(b)) + + def _test_ordered(self, items): + def _test(fn, items_, op_str): + for i, a in enumerate(items_): + for b in items_[i+1:]: + _print("'%s' %s '%s'" % (a, op_str, b)) + self.assertTrue(fn(a, b)) + + _test(lambda a, b: a < b, items, '<') + _test(lambda a, b: a <= b, items, '<=') + _test(lambda a, b: a != b, items, '!=') + _test(lambda a, b: a > b, list(reversed(items)), '>') + _test(lambda a, b: a >= b, list(reversed(items)), '>=') + _test(lambda a, b: a != b, list(reversed(items)), '!=') + + def _create_random_token(self): + s = self.make_token.create_random_token_string() + return self.make_token(s) + + def _create_random_version(self): + ver_str = '.'.join(self.make_token.create_random_token_string() + for i in range(random.randint(0, 6))) + return Version(ver_str, make_token=self.make_token) + + def test_misc(self): + self.assertEqual(Version("1.2.12").as_tuple(), ("1", "2", "12")) + + def test_token_strict_weak_ordering(self): + # test equal tokens + tok = self._create_random_token() + self._test_strict_weak_ordering(tok, tok) + + # test random tokens + for i in range(100): + tok1 = self._create_random_token() + tok2 = self._create_random_token() + self._test_strict_weak_ordering(tok1, tok2) + + def test_version_strict_weak_ordering(self): + # test equal versions + ver = self._create_random_version() + self._test_strict_weak_ordering(ver, ver) + + # test random versions + for i in range(100): + ver1 = self._create_random_version() + ver2 = self._create_random_version() + self._test_strict_weak_ordering(ver1, ver2) + + def test_token_comparisons(self): + def _lt(a, b): + _print("'%s' < '%s'" % (a, b)) + self.assertTrue(self.make_token(a) < self.make_token(b)) + self.assertTrue(Version(a) < Version(b)) + + _print() + _lt("3", "4") + _lt("01", "1") + _lt("beta", "1") + _lt("alpha3", "alpha4") + _lt("alpha", "alpha3") + _lt("gamma33", "33gamma") + + def test_version_comparisons(self): + def _eq(a, b): + _print("'%s' == '%s'" % (a, b)) + self.assertTrue(Version(a) == Version(b)) + + _print() + _eq("", "") + _eq("1", "1") + _eq("1.2", "1-2") + _eq("1.2-3", "1-2.3") + + ascending = ["", + "0.0.0", + "1", + "2", + "2.alpha1", + "2.alpha2", + "2.beta", + "2.0", + "2.0.8.8", + "2.1", + "2.1.0"] + self._test_ordered([Version(x) for x in ascending]) + + def _eq2(a, b): + _print("'%s' == '%s'" % (a, b)) + self.assertTrue(a == b) + + # test behaviour in sets + a = Version("1.0") + b = Version("1.0") + c = Version("1.0alpha") + d = Version("2.0.0") + + _eq2(set([a]) - set([a]), set()) + _eq2(set([a]) - set([b]), set()) + _eq2(set([a, a]) - set([a]), set()) + _eq2(set([b, c, d]) - set([a]), set([c, d])) + _eq2(set([b, c]) | set([c, d]), set([b, c, d])) + _eq2(set([b, c]) & set([c, d]), set([c])) + + def test_version_range(self): + def _eq(a, b): + _print("'%s' == '%s'" % (a, b)) + a_range = VersionRange(a) + b_range = VersionRange(b) + + self.assertTrue(a_range == b_range) + self.assertTrue(a_range.issuperset(a_range)) + self.assertTrue(a_range.issuperset(b_range)) + self.assertTrue(VersionRange(str(a_range)) == a_range) + self.assertTrue(VersionRange(str(b_range)) == a_range) + self.assertTrue(hash(a_range) == hash(b_range)) + + a_ = a.replace('.', '-') + a_ = a_.replace("--", "..") + a_range_ = VersionRange(a_) + self.assertTrue(a_range_ == a_range) + self.assertTrue(hash(a_range_) == hash(a_range)) + + range_strs = a.split('|') + ranges = [VersionRange(x) for x in range_strs] + ranges_ = ranges[0].union(ranges[1:]) + self.assertTrue(ranges_ == a_range) + + self.assertTrue(a_range | b_range == a_range) + self.assertTrue(a_range - b_range is None) + self.assertTrue(b_range - a_range is None) + self.assertTrue(VersionRange() & a_range == a_range) + self.assertTrue(b_range.span() & a_range == a_range) + + a_inv = a_range.inverse() + self.assertTrue(a_inv == ~b_range) + + if a_inv: + self.assertTrue(~a_inv == a_range) + self.assertTrue(a_range | a_inv == VersionRange()) + self.assertTrue(a_range & a_inv is None) + + a_ranges = a_range.split() + a_range_ = a_ranges[0].union(a_ranges[1:]) + self.assertTrue(a_range_ == b_range) + + def _and(a, b, c): + _print("'%s' & '%s' == '%s'" % (a, b, c)) + a_range = VersionRange(a) + b_range = VersionRange(b) + c_range = None if c is None else VersionRange(c) + self.assertTrue(a_range & b_range == c_range) + self.assertTrue(b_range & a_range == c_range) + + a_or_b = a_range | b_range + a_and_b = a_range & b_range + a_sub_b = a_range - b_range + b_sub_a = b_range - a_range + ranges = [a_and_b, a_sub_b, b_sub_a] + ranges = [x for x in ranges if x] + self.assertTrue(ranges[0].union(ranges[1:]) == a_or_b) + + def _inv(a, b): + a_range = VersionRange(a) + b_range = VersionRange(b) + self.assertTrue(~a_range == b_range) + self.assertTrue(~b_range == a_range) + self.assertTrue(a_range | b_range == VersionRange()) + self.assertTrue(a_range & b_range is None) + + # simple cases + _print() + _eq("", "") + _eq("1", "1") + _eq("1.0.0", "1.0.0") + _eq("3+<3_", "3") + _eq("_+<__", "_") + _eq("1.2+<=2.0", "1.2..2.0") + _eq("10+,<20", "10+<20") + _eq("1+<1.0", "1+<1.0") + _eq(">=2", "2+") + _eq(">=1.21.1,<1.23", ">=1.21.1<1.23") + _eq(">1.21.1,<1.23", ">1.21.1<1.23") + _eq(">1.21.1<1.23", ">1.21.1<1.23") + _eq(">1.21.1,<=1.23", ">1.21.1<=1.23") + + # Reverse order which is a syntax pip packages use more often now. + # Only allowed when separated by a comma. + _eq("<1.23,>=1.21.1", ">=1.21.1<1.23") + _eq("<1.23,>1.21.1", ">1.21.1<1.23") + + # optimised cases + _eq("3|3", "3") + _eq("3|1", "1|3") + _eq("5|3|1", "1|3|5") + _eq("1|1_", "1+<1__") + _eq("1|1_|1__", "1+,<1___") + _eq("|", "") + _eq("||", "||||||||") + _eq("1|1_+", "1+") + _eq("<1|1", "<1_") + _eq("1+<3|3+<5", "1+<5") + _eq(">4<6|1+<3", "1+<3|>4,<6") + _eq("4+<6|1+<3|", "") + _eq("4|2+", "2+") + _eq("3|<5", "<5") + _eq("<3|>3", ">3|<3") + _eq("3+|<3", "") + _eq("3+|<4", "") + _eq("2+<=6|3+<5", "2..6") + _eq("3+,<5|2+<=6", "2+<=6") + _eq("2|2+", "2+") + _eq("2|2.1+", "2+") + _eq("2|<2.1", "<2_") + _eq("3..3", "==3") + _eq(">=3,<=3", "==3") + + # AND'ing + _and("3", "3", "3") + _and("1", "==1", "==1") + _and("", "==1", "==1") + _and("3", "4", None) + _and("<3", "5+", None) + _and("4+<6", "6+<8", None) + _and("2+", "<=4", "2..4") + _and("1", "1.0", "1.0") + _and("4..6", "6+<8", "==6") + + # inverse + _inv("3+", "<3") + _inv("<=3", ">3") + _inv("3.5", "<3.5|3.5_+") + self.assertTrue(~VersionRange() is None) + + # odd (but valid) cases + _eq(">", ">") # greater than the empty version + _eq("+", "") # greater or equal to empty version (is all vers) + _eq(">=", "") # equivalent to above + _eq("<=", "==") # less or equal to empty version (is only empty) + _eq("..", "==") # from empty version to empty version + _eq("+<=", "==") # equivalent to above + + invalid_range = [ + "4+<2", # lower bound greater than upper + ">3<3", # both greater and less than same version + ">3<=3", # greater and less or equal to same version + "3+<3" # greater and equal to, and less than, same version + ] + + for s in invalid_range: + self.assertRaises(VersionError, VersionRange, s) + + invalid_syntax = [ + "<", # less than the empty version + "><", # both greater and less than empty version + ">3>4", # both are lower bounds + "<3<4", # both are upper bounds + "<4>3", # upper bound before lower without comma + ",<4", # leading comma + "4+,", # trailing comma + "1>=", # pre-lower-op in post + "+1", # post-lower-op in pre + "4<", # pre-upper-op in post + "1+<2<3" # more than two bounds + ] + + for s in invalid_syntax: + self.assertRaises(VersionError, VersionRange, s) + + # test simple logic + self.assertTrue(VersionRange("").is_any()) + self.assertTrue(VersionRange("2+<4").bounded()) + self.assertTrue(VersionRange("2+").lower_bounded()) + self.assertTrue(not VersionRange("2+").upper_bounded()) + self.assertTrue(not VersionRange("2+").bounded()) + self.assertTrue(VersionRange("<2").upper_bounded()) + self.assertTrue(not VersionRange("<2").lower_bounded()) + self.assertTrue(not VersionRange("<2").bounded()) + + # test range from version(s) + v = Version("3") + self.assertTrue(VersionRange.from_version(v, "eq") == VersionRange("==3")) + self.assertTrue(VersionRange.from_version(v, "gt") == VersionRange(">3")) + self.assertTrue(VersionRange.from_version(v, "gte") == VersionRange("3+")) + self.assertTrue(VersionRange.from_version(v, "lt") == VersionRange("<3")) + self.assertTrue(VersionRange.from_version(v, "lte") == VersionRange("<=3")) + + range1 = VersionRange.from_version(Version("2"), "gte") + range2 = VersionRange.from_version(Version("4"), "lte") + _eq(str(range1 & range2), "2..4") + + v2 = Version("6.0") + v3 = Version("4") + self.assertTrue(VersionRange.from_versions([v, v2, v3]) + == VersionRange("==3|==4|==6.0")) + + # test behaviour in sets + def _eq2(a, b): + _print("'%s' == '%s'" % (a, b)) + self.assertTrue(a == b) + + a = VersionRange("1+<=2.5") + b = VersionRange("1..2.5") + c = VersionRange(">=5") + d = VersionRange(">6.1.0") + e = VersionRange("3.2") + + _eq2(set([a]) - set([a]), set()) + _eq2(set([a]) - set([b]), set()) + _eq2(set([a, a]) - set([a]), set()) + _eq2(set([b, c, d, e]) - set([a]), set([c, d, e])) + _eq2(set([b, c, e]) | set([c, d]), set([b, c, d, e])) + _eq2(set([b, c]) & set([c, d]), set([c])) + + def test_containment(self): + # basic containment + self.assertTrue(Version("3") in VersionRange("3+")) + self.assertTrue(Version("5") in VersionRange("3..5")) + self.assertTrue(Version("5_") not in VersionRange("3..5")) + self.assertTrue(Version("3.0.0") in VersionRange("3+")) + self.assertTrue(Version("3.0.0") not in VersionRange("3.1+")) + self.assertTrue(Version("3") in VersionRange("<1|5|6|8|7|3|60+")) + self.assertTrue(Version("3") in VersionRange("<1|5|6|8|7|==3|60+")) + self.assertTrue(VersionRange("2.1+<4") in VersionRange("<4")) + self.assertTrue(VersionRange("2.1..4") not in VersionRange("<4")) + self.assertTrue(VersionRange("3") in VersionRange("3")) + self.assertTrue(VersionRange("==3") in VersionRange("3")) + self.assertTrue(VersionRange("3.5+<3_") in VersionRange("3")) + self.assertTrue(VersionRange("3") not in VersionRange("4+<6")) + self.assertTrue(VersionRange("3+<10") not in VersionRange("4+<6")) + + # iterating over sorted version list + numbers = [2, 3, 5, 10, 11, 13, 14] + versions = [Version(str(x)) for x in numbers] + rev_versions = list(reversed(versions)) + composite_range = VersionRange.from_versions(versions) + + entries = [(VersionRange(""), 7), + (VersionRange("0+"), 7), + (VersionRange("5+"), 5), + (VersionRange("6+"), 4), + (VersionRange("50+"), 0), + (VersionRange(">5"), 4), + (VersionRange("5"), 1), + (VersionRange("6"), 0), + (VersionRange("<5"), 2), + (VersionRange("<6"), 3), + (VersionRange("<50"), 7), + (VersionRange("<=5"), 3), + (VersionRange("<1"), 0), + (VersionRange("2|9+"), 5), + (VersionRange("3+<6|12+<13.5"), 3), + (VersionRange("<1|20+"), 0), + (VersionRange(">0<20"), 7)] + + for range_, count in entries: + # brute-force containment tests + matches = set(x for x in versions if x in range_) + self.assertEqual(len(matches), count) + + # more optimal containment tests + def _test_it(it): + matches_ = set(version for contains, version in it if contains) + self.assertEqual(matches_, matches) + + _test_it(range_.iter_intersect_test(versions)) + _test_it(range_.iter_intersect_test(rev_versions, descending=True)) + + # throw in an intersection test + self.assertEqual(composite_range.intersects(range_), (count != 0)) + int_range = composite_range & range_ + versions_ = [] if int_range is None else int_range.to_versions() + self.assertEqual(set(versions_), matches) + + # throw in a superset test as well + self.assertEqual(range_.issuperset(composite_range), (count == 7)) + if count: + self.assertTrue(composite_range.issuperset(int_range)) + + def test_requirement_list(self): + def _eq(reqs, expected_reqs): + _print("requirements(%s) == requirements(%s)" + % (' '.join(reqs), ' '.join(expected_reqs))) + reqs_ = [Requirement(x) for x in reqs] + reqlist = RequirementList(reqs_) + _print("result: %s" % str(reqlist)) + + exp_reqs_ = [Requirement(x) for x in expected_reqs] + self.assertTrue(reqlist.requirements == exp_reqs_) + + exp_names = set(x.name for x in exp_reqs_ if not x.conflict) + self.assertTrue(reqlist.names == exp_names) + + exp_confl_names = set(x.name for x in exp_reqs_ if x.conflict) + self.assertTrue(reqlist.conflict_names == exp_confl_names) + + def _confl(reqs, a, b): + _print("requirements(%s) == %s <--!--> %s" % (' '.join(reqs), a, b)) + reqs_ = [Requirement(x) for x in reqs] + reqlist = RequirementList(reqs_) + _print("result: %s" % str(reqlist)) + + a_req = Requirement(a) + b_req = Requirement(b) + self.assertTrue(reqlist.conflict == (a_req, b_req)) + + _print() + _eq(["foo"], + ["foo"]) + _eq(["foo", "bah"], + ["foo", "bah"]) + _eq(["bah", "foo"], + ["bah", "foo"]) + _eq(["foo-4+", "foo-4.5"], + ["foo-4.5"]) + _eq(["bah-2.4", "foo", "bah-2.4.1+"], + ["bah-2.4.1+<2.4_", "foo"]) + _eq(["foo-2+", "!foo-4+"], + ["foo-2+<4"]) + _eq(["!bah-1", "!bah-3"], + ["!bah-1|3"]) + _eq(["!bah-5", "foo-2.3", "!bah-5.6+"], + ["!bah-5+", "foo-2.3"]) + _eq(["~bah-4", "foo", "bah<4.2"], + ["bah-4+<4.2", "foo"]) + _eq(["~bah", "!foo", "bah<4.2"], + ["bah<4.2", "!foo"]) + _eq(["~bah-3+", "~bah-5"], + ["~bah-5"]) + + _confl(["foo-1", "foo-2"], + "foo-1", "foo-2") + _confl(["foo-2", "foo-1"], + "foo-2", "foo-1") + _confl(["foo", "~bah-5+", "bah-2"], + "~bah-5+", "bah-2") + _confl(["foo", "~bah-5+", "bah-7..12", "bah-2"], + "bah-7..12", "bah-2") + + if __name__ == '__main__': unittest.main() diff --git a/src/rez/utils/formatting.py b/src/rez/utils/formatting.py index 3b7db24d2..7a2c6c6f0 100644 --- a/src/rez/utils/formatting.py +++ b/src/rez/utils/formatting.py @@ -9,7 +9,7 @@ from string import Formatter from rez.vendor.enum import Enum -from rez.vendor.version.requirement import Requirement +from rez.version.requirement import Requirement from rez.exceptions import PackageRequestError from rez.vendor.six import six from pprint import pformat diff --git a/src/rez/utils/yaml.py b/src/rez/utils/yaml.py index f1e95c6f8..72ef0cdb2 100644 --- a/src/rez/utils/yaml.py +++ b/src/rez/utils/yaml.py @@ -5,8 +5,8 @@ from rez.utils.sourcecode import SourceCode from rez.vendor import yaml from rez.vendor.yaml.dumper import SafeDumper -from rez.vendor.version.version import Version -from rez.vendor.version.requirement import Requirement +from rez.version.version import Version +from rez.version.requirement import Requirement from types import FunctionType, BuiltinFunctionType from inspect import getsourcelines from textwrap import dedent diff --git a/src/rez/vendor/version/test.py b/src/rez/vendor/version/test.py deleted file mode 100644 index 8f8919fa5..000000000 --- a/src/rez/vendor/version/test.py +++ /dev/null @@ -1,505 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -# Copyright Contributors to the Rez Project - - -from rez.vendor.version.version import Version, AlphanumericVersionToken, \ - VersionRange, reverse_sort_key, _ReversedComparable -from rez.vendor.version.requirement import Requirement, RequirementList -from rez.vendor.version.util import VersionError -import random -import textwrap -import unittest - - - -def _print(txt=''): - # uncomment for verbose output - #print txt - pass - - -class TestVersionSchema(unittest.TestCase): - make_token = AlphanumericVersionToken - - def __init__(self, fn): - unittest.TestCase.__init__(self, fn) - - def _test_strict_weak_ordering(self, a, b): - self.assertTrue(a == a) - self.assertTrue(b == b) - - e = (a == b) - ne = (a != b) - lt = (a < b) - lte = (a <= b) - gt = (a > b) - gte = (a >= b) - - _print('\n' + textwrap.dedent( - """ - '%s' '%s' - ==: %s - !=: %s - <: %s - <=: %s - >: %s - >=: %s - """).strip() % (a, b, e, ne, lt, lte, gt, gte)) - - self.assertTrue(e != ne) - if e: - self.assertTrue(not lt) - self.assertTrue(not gt) - self.assertTrue(lte) - self.assertTrue(gte) - else: - self.assertTrue(lt != gt) - self.assertTrue(lte != gte) - self.assertTrue(lt == lte) - self.assertTrue(gt == gte) - - if not isinstance(a, _ReversedComparable): - self._test_strict_weak_ordering(reverse_sort_key(a), - reverse_sort_key(b)) - - def _test_ordered(self, items): - def _test(fn, items_, op_str): - for i, a in enumerate(items_): - for b in items_[i+1:]: - _print("'%s' %s '%s'" % (a, op_str, b)) - self.assertTrue(fn(a, b)) - - _test(lambda a, b: a < b, items, '<') - _test(lambda a, b: a <= b, items, '<=') - _test(lambda a, b: a != b, items, '!=') - _test(lambda a, b: a > b, list(reversed(items)), '>') - _test(lambda a, b: a >= b, list(reversed(items)), '>=') - _test(lambda a, b: a != b, list(reversed(items)), '!=') - - def _create_random_token(self): - s = self.make_token.create_random_token_string() - return self.make_token(s) - - def _create_random_version(self): - ver_str = '.'.join(self.make_token.create_random_token_string() - for i in range(random.randint(0, 6))) - return Version(ver_str, make_token=self.make_token) - - def test_misc(self): - self.assertEqual(Version("1.2.12").as_tuple(), ("1", "2", "12")) - - def test_token_strict_weak_ordering(self): - # test equal tokens - tok = self._create_random_token() - self._test_strict_weak_ordering(tok, tok) - - # test random tokens - for i in range(100): - tok1 = self._create_random_token() - tok2 = self._create_random_token() - self._test_strict_weak_ordering(tok1, tok2) - - def test_version_strict_weak_ordering(self): - # test equal versions - ver = self._create_random_version() - self._test_strict_weak_ordering(ver, ver) - - # test random versions - for i in range(100): - ver1 = self._create_random_version() - ver2 = self._create_random_version() - self._test_strict_weak_ordering(ver1, ver2) - - def test_token_comparisons(self): - def _lt(a, b): - _print("'%s' < '%s'" % (a, b)) - self.assertTrue(self.make_token(a) < self.make_token(b)) - self.assertTrue(Version(a) < Version(b)) - - _print() - _lt("3", "4") - _lt("01", "1") - _lt("beta", "1") - _lt("alpha3", "alpha4") - _lt("alpha", "alpha3") - _lt("gamma33", "33gamma") - - def test_version_comparisons(self): - def _eq(a, b): - _print("'%s' == '%s'" % (a, b)) - self.assertTrue(Version(a) == Version(b)) - - _print() - _eq("", "") - _eq("1", "1") - _eq("1.2", "1-2") - _eq("1.2-3", "1-2.3") - - ascending = ["", - "0.0.0", - "1", - "2", - "2.alpha1", - "2.alpha2", - "2.beta", - "2.0", - "2.0.8.8", - "2.1", - "2.1.0"] - self._test_ordered([Version(x) for x in ascending]) - - def _eq2(a, b): - _print("'%s' == '%s'" % (a, b)) - self.assertTrue(a == b) - - # test behaviour in sets - a = Version("1.0") - b = Version("1.0") - c = Version("1.0alpha") - d = Version("2.0.0") - - _eq2(set([a]) - set([a]), set()) - _eq2(set([a]) - set([b]), set()) - _eq2(set([a, a]) - set([a]), set()) - _eq2(set([b, c, d]) - set([a]), set([c, d])) - _eq2(set([b, c]) | set([c, d]), set([b, c, d])) - _eq2(set([b, c]) & set([c, d]), set([c])) - - def test_version_range(self): - def _eq(a, b): - _print("'%s' == '%s'" % (a, b)) - a_range = VersionRange(a) - b_range = VersionRange(b) - - self.assertTrue(a_range == b_range) - self.assertTrue(a_range.issuperset(a_range)) - self.assertTrue(a_range.issuperset(b_range)) - self.assertTrue(VersionRange(str(a_range)) == a_range) - self.assertTrue(VersionRange(str(b_range)) == a_range) - self.assertTrue(hash(a_range) == hash(b_range)) - - a_ = a.replace('.', '-') - a_ = a_.replace("--", "..") - a_range_ = VersionRange(a_) - self.assertTrue(a_range_ == a_range) - self.assertTrue(hash(a_range_) == hash(a_range)) - - range_strs = a.split('|') - ranges = [VersionRange(x) for x in range_strs] - ranges_ = ranges[0].union(ranges[1:]) - self.assertTrue(ranges_ == a_range) - - self.assertTrue(a_range | b_range == a_range) - self.assertTrue(a_range - b_range is None) - self.assertTrue(b_range - a_range is None) - self.assertTrue(VersionRange() & a_range == a_range) - self.assertTrue(b_range.span() & a_range == a_range) - - a_inv = a_range.inverse() - self.assertTrue(a_inv == ~b_range) - - if a_inv: - self.assertTrue(~a_inv == a_range) - self.assertTrue(a_range | a_inv == VersionRange()) - self.assertTrue(a_range & a_inv is None) - - a_ranges = a_range.split() - a_range_ = a_ranges[0].union(a_ranges[1:]) - self.assertTrue(a_range_ == b_range) - - def _and(a, b, c): - _print("'%s' & '%s' == '%s'" % (a, b, c)) - a_range = VersionRange(a) - b_range = VersionRange(b) - c_range = None if c is None else VersionRange(c) - self.assertTrue(a_range & b_range == c_range) - self.assertTrue(b_range & a_range == c_range) - - a_or_b = a_range | b_range - a_and_b = a_range & b_range - a_sub_b = a_range - b_range - b_sub_a = b_range - a_range - ranges = [a_and_b, a_sub_b, b_sub_a] - ranges = [x for x in ranges if x] - self.assertTrue(ranges[0].union(ranges[1:]) == a_or_b) - - def _inv(a, b): - a_range = VersionRange(a) - b_range = VersionRange(b) - self.assertTrue(~a_range == b_range) - self.assertTrue(~b_range == a_range) - self.assertTrue(a_range | b_range == VersionRange()) - self.assertTrue(a_range & b_range is None) - - # simple cases - _print() - _eq("", "") - _eq("1", "1") - _eq("1.0.0", "1.0.0") - _eq("3+<3_", "3") - _eq("_+<__", "_") - _eq("1.2+<=2.0", "1.2..2.0") - _eq("10+,<20", "10+<20") - _eq("1+<1.0", "1+<1.0") - _eq(">=2", "2+") - _eq(">=1.21.1,<1.23", ">=1.21.1<1.23") - _eq(">1.21.1,<1.23", ">1.21.1<1.23") - _eq(">1.21.1<1.23", ">1.21.1<1.23") - _eq(">1.21.1,<=1.23", ">1.21.1<=1.23") - - # Reverse order which is a syntax pip packages use more often now. - # Only allowed when separated by a comma. - _eq("<1.23,>=1.21.1", ">=1.21.1<1.23") - _eq("<1.23,>1.21.1", ">1.21.1<1.23") - - # optimised cases - _eq("3|3", "3") - _eq("3|1", "1|3") - _eq("5|3|1", "1|3|5") - _eq("1|1_", "1+<1__") - _eq("1|1_|1__", "1+,<1___") - _eq("|", "") - _eq("||", "||||||||") - _eq("1|1_+", "1+") - _eq("<1|1", "<1_") - _eq("1+<3|3+<5", "1+<5") - _eq(">4<6|1+<3", "1+<3|>4,<6") - _eq("4+<6|1+<3|", "") - _eq("4|2+", "2+") - _eq("3|<5", "<5") - _eq("<3|>3", ">3|<3") - _eq("3+|<3", "") - _eq("3+|<4", "") - _eq("2+<=6|3+<5", "2..6") - _eq("3+,<5|2+<=6", "2+<=6") - _eq("2|2+", "2+") - _eq("2|2.1+", "2+") - _eq("2|<2.1", "<2_") - _eq("3..3", "==3") - _eq(">=3,<=3", "==3") - - # AND'ing - _and("3", "3", "3") - _and("1", "==1", "==1") - _and("", "==1", "==1") - _and("3", "4", None) - _and("<3", "5+", None) - _and("4+<6", "6+<8", None) - _and("2+", "<=4", "2..4") - _and("1", "1.0", "1.0") - _and("4..6", "6+<8", "==6") - - # inverse - _inv("3+", "<3") - _inv("<=3", ">3") - _inv("3.5", "<3.5|3.5_+") - self.assertTrue(~VersionRange() is None) - - # odd (but valid) cases - _eq(">", ">") # greater than the empty version - _eq("+", "") # greater or equal to empty version (is all vers) - _eq(">=", "") # equivalent to above - _eq("<=", "==") # less or equal to empty version (is only empty) - _eq("..", "==") # from empty version to empty version - _eq("+<=", "==") # equivalent to above - - invalid_range = [ - "4+<2", # lower bound greater than upper - ">3<3", # both greater and less than same version - ">3<=3", # greater and less or equal to same version - "3+<3" # greater and equal to, and less than, same version - ] - - for s in invalid_range: - self.assertRaises(VersionError, VersionRange, s) - - invalid_syntax = [ - "<", # less than the empty version - "><", # both greater and less than empty version - ">3>4", # both are lower bounds - "<3<4", # both are upper bounds - "<4>3", # upper bound before lower without comma - ",<4", # leading comma - "4+,", # trailing comma - "1>=", # pre-lower-op in post - "+1", # post-lower-op in pre - "4<", # pre-upper-op in post - "1+<2<3" # more than two bounds - ] - - for s in invalid_syntax: - self.assertRaises(VersionError, VersionRange, s) - - # test simple logic - self.assertTrue(VersionRange("").is_any()) - self.assertTrue(VersionRange("2+<4").bounded()) - self.assertTrue(VersionRange("2+").lower_bounded()) - self.assertTrue(not VersionRange("2+").upper_bounded()) - self.assertTrue(not VersionRange("2+").bounded()) - self.assertTrue(VersionRange("<2").upper_bounded()) - self.assertTrue(not VersionRange("<2").lower_bounded()) - self.assertTrue(not VersionRange("<2").bounded()) - - # test range from version(s) - v = Version("3") - self.assertTrue(VersionRange.from_version(v, "eq") == VersionRange("==3")) - self.assertTrue(VersionRange.from_version(v, "gt") == VersionRange(">3")) - self.assertTrue(VersionRange.from_version(v, "gte") == VersionRange("3+")) - self.assertTrue(VersionRange.from_version(v, "lt") == VersionRange("<3")) - self.assertTrue(VersionRange.from_version(v, "lte") == VersionRange("<=3")) - - range1 = VersionRange.from_version(Version("2"), "gte") - range2 = VersionRange.from_version(Version("4"), "lte") - _eq(str(range1 & range2), "2..4") - - v2 = Version("6.0") - v3 = Version("4") - self.assertTrue(VersionRange.from_versions([v, v2, v3]) - == VersionRange("==3|==4|==6.0")) - - # test behaviour in sets - def _eq2(a, b): - _print("'%s' == '%s'" % (a, b)) - self.assertTrue(a == b) - - a = VersionRange("1+<=2.5") - b = VersionRange("1..2.5") - c = VersionRange(">=5") - d = VersionRange(">6.1.0") - e = VersionRange("3.2") - - _eq2(set([a]) - set([a]), set()) - _eq2(set([a]) - set([b]), set()) - _eq2(set([a, a]) - set([a]), set()) - _eq2(set([b, c, d, e]) - set([a]), set([c, d, e])) - _eq2(set([b, c, e]) | set([c, d]), set([b, c, d, e])) - _eq2(set([b, c]) & set([c, d]), set([c])) - - def test_containment(self): - # basic containment - self.assertTrue(Version("3") in VersionRange("3+")) - self.assertTrue(Version("5") in VersionRange("3..5")) - self.assertTrue(Version("5_") not in VersionRange("3..5")) - self.assertTrue(Version("3.0.0") in VersionRange("3+")) - self.assertTrue(Version("3.0.0") not in VersionRange("3.1+")) - self.assertTrue(Version("3") in VersionRange("<1|5|6|8|7|3|60+")) - self.assertTrue(Version("3") in VersionRange("<1|5|6|8|7|==3|60+")) - self.assertTrue(VersionRange("2.1+<4") in VersionRange("<4")) - self.assertTrue(VersionRange("2.1..4") not in VersionRange("<4")) - self.assertTrue(VersionRange("3") in VersionRange("3")) - self.assertTrue(VersionRange("==3") in VersionRange("3")) - self.assertTrue(VersionRange("3.5+<3_") in VersionRange("3")) - self.assertTrue(VersionRange("3") not in VersionRange("4+<6")) - self.assertTrue(VersionRange("3+<10") not in VersionRange("4+<6")) - - # iterating over sorted version list - numbers = [2, 3, 5, 10, 11, 13, 14] - versions = [Version(str(x)) for x in numbers] - rev_versions = list(reversed(versions)) - composite_range = VersionRange.from_versions(versions) - - entries = [(VersionRange(""), 7), - (VersionRange("0+"), 7), - (VersionRange("5+"), 5), - (VersionRange("6+"), 4), - (VersionRange("50+"), 0), - (VersionRange(">5"), 4), - (VersionRange("5"), 1), - (VersionRange("6"), 0), - (VersionRange("<5"), 2), - (VersionRange("<6"), 3), - (VersionRange("<50"), 7), - (VersionRange("<=5"), 3), - (VersionRange("<1"), 0), - (VersionRange("2|9+"), 5), - (VersionRange("3+<6|12+<13.5"), 3), - (VersionRange("<1|20+"), 0), - (VersionRange(">0<20"), 7)] - - for range_, count in entries: - # brute-force containment tests - matches = set(x for x in versions if x in range_) - self.assertEqual(len(matches), count) - - # more optimal containment tests - def _test_it(it): - matches_ = set(version for contains, version in it if contains) - self.assertEqual(matches_, matches) - - _test_it(range_.iter_intersect_test(versions)) - _test_it(range_.iter_intersect_test(rev_versions, descending=True)) - - # throw in an intersection test - self.assertEqual(composite_range.intersects(range_), (count != 0)) - int_range = composite_range & range_ - versions_ = [] if int_range is None else int_range.to_versions() - self.assertEqual(set(versions_), matches) - - # throw in a superset test as well - self.assertEqual(range_.issuperset(composite_range), (count == 7)) - if count: - self.assertTrue(composite_range.issuperset(int_range)) - - def test_requirement_list(self): - def _eq(reqs, expected_reqs): - _print("requirements(%s) == requirements(%s)" - % (' '.join(reqs), ' '.join(expected_reqs))) - reqs_ = [Requirement(x) for x in reqs] - reqlist = RequirementList(reqs_) - _print("result: %s" % str(reqlist)) - - exp_reqs_ = [Requirement(x) for x in expected_reqs] - self.assertTrue(reqlist.requirements == exp_reqs_) - - exp_names = set(x.name for x in exp_reqs_ if not x.conflict) - self.assertTrue(reqlist.names == exp_names) - - exp_confl_names = set(x.name for x in exp_reqs_ if x.conflict) - self.assertTrue(reqlist.conflict_names == exp_confl_names) - - def _confl(reqs, a, b): - _print("requirements(%s) == %s <--!--> %s" % (' '.join(reqs), a, b)) - reqs_ = [Requirement(x) for x in reqs] - reqlist = RequirementList(reqs_) - _print("result: %s" % str(reqlist)) - - a_req = Requirement(a) - b_req = Requirement(b) - self.assertTrue(reqlist.conflict == (a_req, b_req)) - - _print() - _eq(["foo"], - ["foo"]) - _eq(["foo", "bah"], - ["foo", "bah"]) - _eq(["bah", "foo"], - ["bah", "foo"]) - _eq(["foo-4+", "foo-4.5"], - ["foo-4.5"]) - _eq(["bah-2.4", "foo", "bah-2.4.1+"], - ["bah-2.4.1+<2.4_", "foo"]) - _eq(["foo-2+", "!foo-4+"], - ["foo-2+<4"]) - _eq(["!bah-1", "!bah-3"], - ["!bah-1|3"]) - _eq(["!bah-5", "foo-2.3", "!bah-5.6+"], - ["!bah-5+", "foo-2.3"]) - _eq(["~bah-4", "foo", "bah<4.2"], - ["bah-4+<4.2", "foo"]) - _eq(["~bah", "!foo", "bah<4.2"], - ["bah<4.2", "!foo"]) - _eq(["~bah-3+", "~bah-5"], - ["~bah-5"]) - - _confl(["foo-1", "foo-2"], - "foo-1", "foo-2") - _confl(["foo-2", "foo-1"], - "foo-2", "foo-1") - _confl(["foo", "~bah-5+", "bah-2"], - "~bah-5+", "bah-2") - _confl(["foo", "~bah-5+", "bah-7..12", "bah-2"], - "bah-7..12", "bah-2") - - -if __name__ == '__main__': - unittest.main() diff --git a/src/rez/vendor/version/__init__.py b/src/rez/version/__init__.py similarity index 100% rename from src/rez/vendor/version/__init__.py rename to src/rez/version/__init__.py diff --git a/src/rez/vendor/version/requirement.py b/src/rez/version/requirement.py similarity index 99% rename from src/rez/vendor/version/requirement.py rename to src/rez/version/requirement.py index 7c4cc6a9e..e5e4e20c2 100644 --- a/src/rez/vendor/version/requirement.py +++ b/src/rez/version/requirement.py @@ -2,8 +2,8 @@ # Copyright Contributors to the Rez Project -from rez.vendor.version.version import Version, VersionRange -from rez.vendor.version.util import _Common +from rez.version.version import Version, VersionRange +from rez.version.util import _Common import re diff --git a/src/rez/vendor/version/util.py b/src/rez/version/util.py similarity index 100% rename from src/rez/vendor/version/util.py rename to src/rez/version/util.py diff --git a/src/rez/vendor/version/version.py b/src/rez/version/version.py similarity index 99% rename from src/rez/vendor/version/version.py rename to src/rez/version/version.py index fb7a85c09..358970ff4 100644 --- a/src/rez/vendor/version/version.py +++ b/src/rez/version/version.py @@ -21,9 +21,8 @@ known as the 'any' range, is used to refer to any version of an object. """ from __future__ import print_function -from .util import VersionError, ParseException, _Common, \ +from rez.version.util import VersionError, ParseException, _Common, \ dedup -import rez.vendor.pyparsing.pyparsing as pp from bisect import bisect_left import copy import string From 1cf92b5c0455a0a7c1a2d22b141ada6ae2cf32f9 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Morin Date: Sat, 16 Sep 2023 11:33:24 -0400 Subject: [PATCH 02/12] Create a well defined public API for rez.version. Signed-off-by: Jean-Christophe Morin --- src/rez/package_filter.py | 2 +- src/rez/package_order.py | 2 +- src/rez/package_resources.py | 2 +- src/rez/package_serialise.py | 2 +- src/rez/packages.py | 4 ++-- src/rez/resolved_context.py | 4 ++-- src/rez/resolver.py | 2 +- src/rez/rex_bindings.py | 4 ++-- src/rez/solver.py | 5 ++--- src/rez/tests/test_version.py | 9 +++++---- src/rez/utils/formatting.py | 2 +- src/rez/utils/yaml.py | 4 ++-- src/rez/version/__init__.py | 10 ++++++++++ src/rez/version/{requirement.py => _requirement.py} | 4 ++-- src/rez/version/{util.py => _util.py} | 0 src/rez/version/{version.py => _version.py} | 2 +- 16 files changed, 34 insertions(+), 24 deletions(-) rename src/rez/version/{requirement.py => _requirement.py} (99%) rename src/rez/version/{util.py => _util.py} (100%) rename src/rez/version/{version.py => _version.py} (99%) diff --git a/src/rez/package_filter.py b/src/rez/package_filter.py index 9b2dae609..1e29066c9 100644 --- a/src/rez/package_filter.py +++ b/src/rez/package_filter.py @@ -7,7 +7,7 @@ from rez.config import config from rez.utils.data_utils import cached_property, cached_class_property from rez.vendor.six import six -from rez.version.requirement import VersionedObject, Requirement +from rez.version import VersionedObject, Requirement from hashlib import sha1 import fnmatch import re diff --git a/src/rez/package_order.py b/src/rez/package_order.py index 9dcec3da2..e00839fea 100644 --- a/src/rez/package_order.py +++ b/src/rez/package_order.py @@ -7,7 +7,7 @@ from rez.config import config from rez.utils.data_utils import cached_class_property -from rez.version.version import Version +from rez.version import Version class PackageOrder(object): diff --git a/src/rez/package_resources.py b/src/rez/package_resources.py index 3698663f4..53c566b83 100644 --- a/src/rez/package_resources.py +++ b/src/rez/package_resources.py @@ -12,7 +12,7 @@ from rez.utils.formatting import PackageRequest from rez.exceptions import PackageMetadataError, ResourceError from rez.config import config, Config, create_config -from rez.version.version import Version +from rez.version import Version from rez.vendor.schema.schema import Schema, SchemaError, Optional, Or, And, Use from rez.vendor.six import six diff --git a/src/rez/package_serialise.py b/src/rez/package_serialise.py index 0ff22a098..8d1f702c0 100644 --- a/src/rez/package_serialise.py +++ b/src/rez/package_serialise.py @@ -7,7 +7,7 @@ from rez.serialise import FileFormat from rez.package_resources import help_schema, late_bound from rez.vendor.schema.schema import Schema, Optional, And, Or, Use -from rez.version.version import Version +from rez.version import Version from rez.utils.schema import extensible_schema_dict from rez.utils.sourcecode import SourceCode from rez.utils.formatting import PackageRequest, indent, \ diff --git a/src/rez/packages.py b/src/rez/packages.py index fb43914e3..b9078688b 100644 --- a/src/rez/packages.py +++ b/src/rez/packages.py @@ -14,8 +14,8 @@ from rez.utils.schema import schema_keys from rez.utils.resources import ResourceHandle, ResourceWrapper from rez.exceptions import PackageFamilyNotFoundError, ResourceError -from rez.version.version import Version, VersionRange -from rez.version.requirement import VersionedObject +from rez.version import Version, VersionRange +from rez.version import VersionedObject from rez.vendor.six import six from rez.serialise import FileFormat from rez.config import config diff --git a/src/rez/resolved_context.py b/src/rez/resolved_context.py index 5aa879237..2c4a4fe49 100644 --- a/src/rez/resolved_context.py +++ b/src/rez/resolved_context.py @@ -36,8 +36,8 @@ read_graph_from_string from rez.utils.resolve_graph import failure_detail_from_graph from rez.vendor.six import six -from rez.version.version import VersionRange -from rez.version.requirement import Requirement +from rez.version import VersionRange +from rez.version import Requirement from rez.vendor.enum import Enum from rez.vendor import yaml from rez.utils import json diff --git a/src/rez/resolver.py b/src/rez/resolver.py index 84eb416fa..5fb999525 100644 --- a/src/rez/resolver.py +++ b/src/rez/resolver.py @@ -10,7 +10,7 @@ from rez.utils.logging_ import log_duration from rez.config import config from rez.vendor.enum import Enum -from rez.version.requirement import Requirement +from rez.version import Requirement from contextlib import contextmanager from hashlib import sha1 diff --git a/src/rez/rex_bindings.py b/src/rez/rex_bindings.py index 155d6d82e..cbfe53c61 100644 --- a/src/rez/rex_bindings.py +++ b/src/rez/rex_bindings.py @@ -11,8 +11,8 @@ unnecessary data from Rex, and provide APIs that will not change. """ from rez.vendor.six import six -from rez.version.version import VersionRange -from rez.version.requirement import Requirement +from rez.version import VersionRange +from rez.version import Requirement basestring = six.string_types[0] diff --git a/src/rez/solver.py b/src/rez/solver.py index 0d1f34213..9990e6457 100644 --- a/src/rez/solver.py +++ b/src/rez/solver.py @@ -23,9 +23,8 @@ from rez.vendor.pygraph.algorithms.accessibility import accessibility from rez.exceptions import PackageNotFoundError, ResolveError, \ PackageFamilyNotFoundError, RezSystemError -from rez.version.version import VersionRange -from rez.version.requirement import VersionedObject, Requirement, \ - RequirementList +from rez.version import VersionRange +from rez.version import VersionedObject, Requirement, RequirementList from rez.vendor.enum import Enum from contextlib import contextmanager from itertools import product, chain diff --git a/src/rez/tests/test_version.py b/src/rez/tests/test_version.py index a602e5b4c..e5d68c199 100644 --- a/src/rez/tests/test_version.py +++ b/src/rez/tests/test_version.py @@ -2,10 +2,11 @@ # Copyright Contributors to the Rez Project -from rez.version.version import Version, AlphanumericVersionToken, \ - VersionRange, reverse_sort_key, _ReversedComparable -from rez.version.requirement import Requirement, RequirementList -from rez.version.util import VersionError +from rez.version import Version, AlphanumericVersionToken, \ + VersionRange, reverse_sort_key +from rez.version._version import _ReversedComparable +from rez.version import Requirement, RequirementList +from rez.version import VersionError import random import textwrap import unittest diff --git a/src/rez/utils/formatting.py b/src/rez/utils/formatting.py index 7a2c6c6f0..e39708e4f 100644 --- a/src/rez/utils/formatting.py +++ b/src/rez/utils/formatting.py @@ -9,7 +9,7 @@ from string import Formatter from rez.vendor.enum import Enum -from rez.version.requirement import Requirement +from rez.version import Requirement from rez.exceptions import PackageRequestError from rez.vendor.six import six from pprint import pformat diff --git a/src/rez/utils/yaml.py b/src/rez/utils/yaml.py index 72ef0cdb2..5cef870f9 100644 --- a/src/rez/utils/yaml.py +++ b/src/rez/utils/yaml.py @@ -5,8 +5,8 @@ from rez.utils.sourcecode import SourceCode from rez.vendor import yaml from rez.vendor.yaml.dumper import SafeDumper -from rez.version.version import Version -from rez.version.requirement import Requirement +from rez.version import Version +from rez.version import Requirement from types import FunctionType, BuiltinFunctionType from inspect import getsourcelines from textwrap import dedent diff --git a/src/rez/version/__init__.py b/src/rez/version/__init__.py index ac31011e1..bddc0fbd3 100644 --- a/src/rez/version/__init__.py +++ b/src/rez/version/__init__.py @@ -1,2 +1,12 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright Contributors to the Rez Project +from rez.version._requirement import Requirement, RequirementList, VersionedObject +from rez.version._util import ParseException, VersionError +from rez.version._version import ( + AlphanumericVersionToken, + NumericToken, + Version, + VersionRange, + VersionToken, + reverse_sort_key, +) diff --git a/src/rez/version/requirement.py b/src/rez/version/_requirement.py similarity index 99% rename from src/rez/version/requirement.py rename to src/rez/version/_requirement.py index e5e4e20c2..d476e9ff1 100644 --- a/src/rez/version/requirement.py +++ b/src/rez/version/_requirement.py @@ -2,8 +2,8 @@ # Copyright Contributors to the Rez Project -from rez.version.version import Version, VersionRange -from rez.version.util import _Common +from rez.version._version import Version, VersionRange +from rez.version._util import _Common import re diff --git a/src/rez/version/util.py b/src/rez/version/_util.py similarity index 100% rename from src/rez/version/util.py rename to src/rez/version/_util.py diff --git a/src/rez/version/version.py b/src/rez/version/_version.py similarity index 99% rename from src/rez/version/version.py rename to src/rez/version/_version.py index 358970ff4..edfdb3f91 100644 --- a/src/rez/version/version.py +++ b/src/rez/version/_version.py @@ -21,7 +21,7 @@ known as the 'any' range, is used to refer to any version of an object. """ from __future__ import print_function -from rez.version.util import VersionError, ParseException, _Common, \ +from rez.version._util import VersionError, ParseException, _Common, \ dedup from bisect import bisect_left import copy From eb5e92a234e239e541489fb806f468f59a379ce9 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Morin Date: Sat, 16 Sep 2023 11:44:32 -0400 Subject: [PATCH 03/12] Rename all imports Signed-off-by: Jean-Christophe Morin --- docs/source/package_commands.rst | 4 ++-- src/rez/bind/_utils.py | 2 +- src/rez/bind/arch.py | 2 +- src/rez/bind/hello_world.py | 2 +- src/rez/bind/os.py | 2 +- src/rez/bind/platform.py | 2 +- src/rez/bind/rezgui.py | 2 +- src/rez/cli/mv.py | 2 +- src/rez/cli/pkg-ignore.py | 2 +- src/rez/cli/rm.py | 4 ++-- src/rez/package_maker.py | 2 +- src/rez/package_py_utils.py | 4 ++-- src/rez/package_remove.py | 2 +- src/rez/package_search.py | 2 +- src/rez/package_test.py | 2 +- src/rez/pip.py | 2 +- src/rez/tests/test_commands.py | 2 +- src/rez/tests/test_copy_package.py | 2 +- src/rez/tests/test_package_filter.py | 2 +- src/rez/tests/test_packages.py | 4 ++-- src/rez/tests/test_packages_order.py | 2 +- src/rez/tests/test_pip_utils.py | 4 ++-- src/rez/tests/test_rex.py | 4 ++-- src/rez/tests/test_solver.py | 2 +- src/rez/utils/patching.py | 2 +- src/rez/utils/pip.py | 4 ++-- src/rezgui/dialogs/AboutDialog.py | 2 +- src/rezgui/dialogs/ResolveDialog.py | 2 +- src/rezgui/widgets/BrowsePackageWidget.py | 2 +- src/rezgui/widgets/ContextTableWidget.py | 4 ++-- src/rezgui/widgets/PackageLineEdit.py | 2 +- src/rezgui/widgets/VariantCellWidget.py | 4 ++-- src/rezgui/widgets/VariantHelpWidget.py | 2 +- src/rezgui/widgets/VariantVersionsTable.py | 2 +- src/rezgui/widgets/VariantVersionsWidget.py | 2 +- src/rezplugins/package_repository/filesystem.py | 2 +- src/rezplugins/package_repository/memory.py | 2 +- 37 files changed, 46 insertions(+), 46 deletions(-) diff --git a/docs/source/package_commands.rst b/docs/source/package_commands.rst index 24b357d19..7e54f2b89 100644 --- a/docs/source/package_commands.rst +++ b/docs/source/package_commands.rst @@ -477,7 +477,7 @@ Following is a list of the objects and functions available. if "foo.cli" in ephemerals: info("Foo cli option is being specified!") -.. py:function:: ephemerals.get_range(name: str, range_: str) -> ~rez.vendor.version.version.VersionRange +.. py:function:: ephemerals.get_range(name: str, range_: str) -> ~rez.version.VersionRange Use ``get_range`` to test with the :func:`intersects` function. Here, we enable ``foo``'s commandline tools by default, unless explicitly disabled via @@ -539,7 +539,7 @@ Following is a list of the objects and functions available. info("floob version is %s" % resolve.floob.version) -.. py:function:: intersects(range1: str | ~rez.vendor.version.version.VersionRange | ~rez.rex_bindings.VariantBinding | ~rez.rex_bindings.VersionBinding, range2: str) -> bool +.. py:function:: intersects(range1: str | ~rez.version.VersionRange | ~rez.rex_bindings.VariantBinding | ~rez.rex_bindings.VersionBinding, range2: str) -> bool A boolean function that returns True if the version or version range of the given object, intersects with the given version range. Valid objects to query include: diff --git a/src/rez/bind/_utils.py b/src/rez/bind/_utils.py index 54e21be14..8630a7631 100644 --- a/src/rez/bind/_utils.py +++ b/src/rez/bind/_utils.py @@ -6,7 +6,7 @@ Utility functions for bind modules. """ from __future__ import absolute_import -from rez.vendor.version.version import Version +from rez.version import Version from rez.exceptions import RezBindError from rez.config import config from rez.util import which diff --git a/src/rez/bind/arch.py b/src/rez/bind/arch.py index 7bb55c706..146317694 100644 --- a/src/rez/bind/arch.py +++ b/src/rez/bind/arch.py @@ -7,7 +7,7 @@ """ from __future__ import absolute_import from rez.package_maker import make_package -from rez.vendor.version.version import Version +from rez.version import Version from rez.bind._utils import check_version from rez.system import system diff --git a/src/rez/bind/hello_world.py b/src/rez/bind/hello_world.py index 773e295be..170bf67f5 100644 --- a/src/rez/bind/hello_world.py +++ b/src/rez/bind/hello_world.py @@ -12,7 +12,7 @@ from __future__ import absolute_import, print_function from rez.package_maker import make_package -from rez.vendor.version.version import Version +from rez.version import Version from rez.utils.lint_helper import env from rez.utils.execution import create_executable_script, ExecutableScriptMode from rez.bind._utils import make_dirs, check_version diff --git a/src/rez/bind/os.py b/src/rez/bind/os.py index a6a88c280..28fe9d2e0 100644 --- a/src/rez/bind/os.py +++ b/src/rez/bind/os.py @@ -7,7 +7,7 @@ """ from __future__ import absolute_import from rez.package_maker import make_package -from rez.vendor.version.version import Version +from rez.version import Version from rez.bind._utils import check_version from rez.system import system diff --git a/src/rez/bind/platform.py b/src/rez/bind/platform.py index f0e2e1c1e..5aac37c7c 100644 --- a/src/rez/bind/platform.py +++ b/src/rez/bind/platform.py @@ -7,7 +7,7 @@ """ from __future__ import absolute_import from rez.package_maker import make_package -from rez.vendor.version.version import Version +from rez.version import Version from rez.bind._utils import check_version from rez.system import system diff --git a/src/rez/bind/rezgui.py b/src/rez/bind/rezgui.py index 1fcbb07d4..844c32ecc 100644 --- a/src/rez/bind/rezgui.py +++ b/src/rez/bind/rezgui.py @@ -10,7 +10,7 @@ from rez.package_maker import make_package from rez.bind._utils import check_version, make_dirs from rez.system import system -from rez.vendor.version.version import Version +from rez.version import Version from rez.utils.lint_helper import env from rez.utils.execution import create_executable_script import shutil diff --git a/src/rez/cli/mv.py b/src/rez/cli/mv.py index 3fe4287d2..e02688296 100644 --- a/src/rez/cli/mv.py +++ b/src/rez/cli/mv.py @@ -54,7 +54,7 @@ def list_repos_containing_pkg(pkg_name, pkg_version): def command(opts, parser, extra_arg_groups=None): - from rez.vendor.version.requirement import VersionedObject + from rez.version import VersionedObject from rez.packages import get_package_from_repository from rez.package_move import move_package import sys diff --git a/src/rez/cli/pkg-ignore.py b/src/rez/cli/pkg-ignore.py index 66a1dceab..557b1ca67 100644 --- a/src/rez/cli/pkg-ignore.py +++ b/src/rez/cli/pkg-ignore.py @@ -63,7 +63,7 @@ def list_repos_containing_pkg(pkg_name, pkg_version): def command(opts, parser, extra_arg_groups=None): from rez.package_repository import package_repository_manager - from rez.vendor.version.requirement import VersionedObject + from rez.version import VersionedObject import sys obj = VersionedObject(opts.PKG) diff --git a/src/rez/cli/rm.py b/src/rez/cli/rm.py index 31512e2d2..664152437 100644 --- a/src/rez/cli/rm.py +++ b/src/rez/cli/rm.py @@ -36,7 +36,7 @@ def setup_parser(parser, completions=False): def remove_package(opts, parser): - from rez.vendor.version.requirement import VersionedObject + from rez.version import VersionedObject from rez.package_remove import remove_package if opts.dry_run: @@ -55,7 +55,7 @@ def remove_package(opts, parser): def remove_package_family(opts, parser, force=False): - from rez.vendor.version.requirement import VersionedObject + from rez.version import VersionedObject from rez.package_remove import remove_package_family from rez.exceptions import PackageRepositoryError diff --git a/src/rez/package_maker.py b/src/rez/package_maker.py index 83dac81a1..bb14c0da8 100644 --- a/src/rez/package_maker.py +++ b/src/rez/package_maker.py @@ -16,7 +16,7 @@ from rez.package_py_utils import expand_requirement from rez.vendor.schema.schema import Schema, Optional, Or, Use, And from rez.vendor.six import six -from rez.vendor.version.version import Version +from rez.version import Version from contextlib import contextmanager import os diff --git a/src/rez/package_py_utils.py b/src/rez/package_py_utils.py index be493e0fb..23117bcdb 100644 --- a/src/rez/package_py_utils.py +++ b/src/rez/package_py_utils.py @@ -56,8 +56,8 @@ def expand_requirement(request, paths=None): if '*' not in request: return request - from rez.vendor.version.version import VersionRange - from rez.vendor.version.requirement import Requirement + from rez.version import VersionRange + from rez.version import Requirement from rez.packages import get_latest_package from uuid import uuid4 diff --git a/src/rez/package_remove.py b/src/rez/package_remove.py index 8ed6e3950..51192f36f 100644 --- a/src/rez/package_remove.py +++ b/src/rez/package_remove.py @@ -3,7 +3,7 @@ from rez.package_repository import package_repository_manager -from rez.vendor.version.version import Version +from rez.version import Version from rez.utils.logging_ import print_info from rez.vendor.six import six from rez.config import config diff --git a/src/rez/package_search.py b/src/rez/package_search.py index 6b5f09c4f..26b7f60dc 100644 --- a/src/rez/package_search.py +++ b/src/rez/package_search.py @@ -23,7 +23,7 @@ from rez.config import config -from rez.vendor.version.requirement import Requirement +from rez.version import Requirement def get_reverse_dependency_tree(package_name, depth=None, paths=None, diff --git a/src/rez/package_test.py b/src/rez/package_test.py index ddd475e8b..89b0c977e 100644 --- a/src/rez/package_test.py +++ b/src/rez/package_test.py @@ -10,7 +10,7 @@ from rez.utils.colorize import heading, Printer from rez.utils.logging_ import print_info, print_warning, print_error from rez.vendor.six import six -from rez.vendor.version.requirement import Requirement, RequirementList +from rez.version import Requirement, RequirementList from rez.utils.py23 import quote import time import sys diff --git a/src/rez/pip.py b/src/rez/pip.py index 5d74ab2e3..ece540535 100644 --- a/src/rez/pip.py +++ b/src/rez/pip.py @@ -5,7 +5,7 @@ from __future__ import print_function, absolute_import from rez.packages import get_latest_package -from rez.vendor.version.version import Version +from rez.version import Version from rez.vendor.distlib.database import DistributionPath from rez.vendor.enum.enum import Enum from rez.vendor.packaging.version import Version as PackagingVersion diff --git a/src/rez/tests/test_commands.py b/src/rez/tests/test_commands.py index 86cf85f2e..df545bc9a 100644 --- a/src/rez/tests/test_commands.py +++ b/src/rez/tests/test_commands.py @@ -5,7 +5,7 @@ """ test package commands """ -from rez.vendor.version.requirement import VersionedObject +from rez.version import VersionedObject from rez.rex import Comment, EnvAction, Shebang, Setenv, Alias, Appendenv from rez.resolved_context import ResolvedContext from rez.utils.filesystem import canonical_path diff --git a/src/rez/tests/test_copy_package.py b/src/rez/tests/test_copy_package.py index 95315a772..591c9de38 100644 --- a/src/rez/tests/test_copy_package.py +++ b/src/rez/tests/test_copy_package.py @@ -16,7 +16,7 @@ from rez.resolved_context import ResolvedContext from rez.packages import get_latest_package from rez.package_copy import copy_package -from rez.vendor.version.version import VersionRange +from rez.version import VersionRange from rez.tests.util import TestBase, TempdirMixin diff --git a/src/rez/tests/test_package_filter.py b/src/rez/tests/test_package_filter.py index 296eb891b..66d7481b4 100644 --- a/src/rez/tests/test_package_filter.py +++ b/src/rez/tests/test_package_filter.py @@ -7,7 +7,7 @@ """ from rez.tests.util import TestBase from rez.packages import iter_packages -from rez.vendor.version.requirement import Requirement +from rez.version import Requirement from rez.package_filter import PackageFilter, PackageFilterList, GlobRule, \ RegexRule, RangeRule, TimestampRule diff --git a/src/rez/tests/test_packages.py b/src/rez/tests/test_packages.py index 11dc60c1f..55f5254c6 100644 --- a/src/rez/tests/test_packages.py +++ b/src/rez/tests/test_packages.py @@ -20,8 +20,8 @@ from rez.utils.formatting import PackageRequest from rez.utils.sourcecode import SourceCode import unittest -from rez.vendor.version.version import Version -from rez.vendor.version.util import VersionError +from rez.version import Version +from rez.version import VersionError from rez.utils.filesystem import canonical_path import shutil import os.path diff --git a/src/rez/tests/test_packages_order.py b/src/rez/tests/test_packages_order.py index f90181eef..702963f5f 100644 --- a/src/rez/tests/test_packages_order.py +++ b/src/rez/tests/test_packages_order.py @@ -12,7 +12,7 @@ TimestampPackageOrder, SortedOrder, PackageOrderList, from_pod from rez.packages import iter_packages from rez.tests.util import TestBase, TempdirMixin -from rez.vendor.version.version import Version +from rez.version import Version class _BaseTestPackagesOrder(TestBase, TempdirMixin): diff --git a/src/rez/tests/test_pip_utils.py b/src/rez/tests/test_pip_utils.py index c5911fe06..c42bf6766 100644 --- a/src/rez/tests/test_pip_utils.py +++ b/src/rez/tests/test_pip_utils.py @@ -9,8 +9,8 @@ import rez.vendor.packaging.version import rez.vendor.distlib.database -from rez.vendor.version.version import VersionRange -from rez.vendor.version.requirement import Requirement +from rez.version import VersionRange +from rez.version import Requirement from rez.vendor.packaging.requirements import Requirement as packaging_Requirement from rez.vendor.packaging.specifiers import SpecifierSet from rez.exceptions import PackageRequestError diff --git a/src/rez/tests/test_rex.py b/src/rez/tests/test_rex.py index 6ae2601a7..32a37d495 100644 --- a/src/rez/tests/test_rex.py +++ b/src/rez/tests/test_rex.py @@ -13,8 +13,8 @@ from rez.exceptions import RexError, RexUndefinedVariableError from rez.config import config import unittest -from rez.vendor.version.version import Version -from rez.vendor.version.requirement import Requirement +from rez.version import Version +from rez.version import Requirement from rez.tests.util import TestBase from rez.utils.backcompat import convert_old_commands from rez.package_repository import package_repository_manager diff --git a/src/rez/tests/test_solver.py b/src/rez/tests/test_solver.py index 82ee932d1..1244dede5 100644 --- a/src/rez/tests/test_solver.py +++ b/src/rez/tests/test_solver.py @@ -8,7 +8,7 @@ from __future__ import print_function import rez.exceptions -from rez.vendor.version.requirement import Requirement +from rez.version import Requirement from rez.solver import Solver, Cycle, SolverStatus from rez.config import config import unittest diff --git a/src/rez/utils/patching.py b/src/rez/utils/patching.py index 6986b1c23..1252867bb 100644 --- a/src/rez/utils/patching.py +++ b/src/rez/utils/patching.py @@ -2,7 +2,7 @@ # Copyright Contributors to the Rez Project -from rez.vendor.version.requirement import Requirement +from rez.version import Requirement def get_patched_request(requires, patchlist): diff --git a/src/rez/utils/pip.py b/src/rez/utils/pip.py index 2df33c137..a4c70e08c 100644 --- a/src/rez/utils/pip.py +++ b/src/rez/utils/pip.py @@ -16,8 +16,8 @@ InvalidVersion as packaging_InvalidVersion ) from rez.vendor.packaging.requirements import Requirement as packaging_Requirement -from rez.vendor.version.requirement import Requirement -from rez.vendor.version.version import Version, VersionRange +from rez.version import Requirement +from rez.version import Version, VersionRange from rez.utils.logging_ import print_warning from rez.exceptions import PackageRequestError diff --git a/src/rezgui/dialogs/AboutDialog.py b/src/rezgui/dialogs/AboutDialog.py index e94cb311b..2e90c9d72 100644 --- a/src/rezgui/dialogs/AboutDialog.py +++ b/src/rezgui/dialogs/AboutDialog.py @@ -5,7 +5,7 @@ from Qt import QtCore, QtWidgets from rezgui.util import create_pane, get_icon from rez import __version__ -from rez.vendor.version.version import Version +from rez.version import Version class AboutDialog(QtWidgets.QDialog): diff --git a/src/rezgui/dialogs/ResolveDialog.py b/src/rezgui/dialogs/ResolveDialog.py index 9ca54e82d..ad0f66dd2 100644 --- a/src/rezgui/dialogs/ResolveDialog.py +++ b/src/rezgui/dialogs/ResolveDialog.py @@ -11,7 +11,7 @@ from rezgui.objects.ResolveThread import ResolveThread from rezgui.objects.App import app from rez.vendor.six.six import StringIO -from rez.vendor.version.requirement import Requirement +from rez.version import Requirement from rez.config import config diff --git a/src/rezgui/widgets/BrowsePackageWidget.py b/src/rezgui/widgets/BrowsePackageWidget.py index 334d1c263..39eff4dfe 100644 --- a/src/rezgui/widgets/BrowsePackageWidget.py +++ b/src/rezgui/widgets/BrowsePackageWidget.py @@ -9,7 +9,7 @@ from rezgui.widgets.PackageTabWidget import PackageTabWidget from rezgui.mixins.ContextViewMixin import ContextViewMixin from rezgui.objects.App import app -from rez.vendor.version.requirement import Requirement +from rez.version import Requirement class BrowsePackageWidget(QtWidgets.QWidget, ContextViewMixin): diff --git a/src/rezgui/widgets/ContextTableWidget.py b/src/rezgui/widgets/ContextTableWidget.py index 3b96b748e..c786af516 100644 --- a/src/rezgui/widgets/ContextTableWidget.py +++ b/src/rezgui/widgets/ContextTableWidget.py @@ -12,8 +12,8 @@ from rezgui.models.ContextModel import ContextModel from rezgui.objects.App import app from rez.packages import iter_packages -from rez.vendor.version.requirement import Requirement -from rez.vendor.version.version import VersionRange +from rez.version import Requirement +from rez.version import VersionRange from functools import partial import os.path diff --git a/src/rezgui/widgets/PackageLineEdit.py b/src/rezgui/widgets/PackageLineEdit.py index 9fc692c2a..82cf34841 100644 --- a/src/rezgui/widgets/PackageLineEdit.py +++ b/src/rezgui/widgets/PackageLineEdit.py @@ -6,7 +6,7 @@ from rezgui.models.ContextModel import ContextModel from rezgui.mixins.ContextViewMixin import ContextViewMixin from rez.packages import get_completions, iter_packages -from rez.vendor.version.requirement import Requirement +from rez.version import Requirement class PackageLineEdit(QtWidgets.QLineEdit, ContextViewMixin): diff --git a/src/rezgui/widgets/VariantCellWidget.py b/src/rezgui/widgets/VariantCellWidget.py index c2a86c6f1..3447c1ea0 100644 --- a/src/rezgui/widgets/VariantCellWidget.py +++ b/src/rezgui/widgets/VariantCellWidget.py @@ -9,8 +9,8 @@ from rez.packages import PackageSearchPath from rez.package_filter import PackageFilterList from rez.resolved_context import PatchLock, get_lock_request -from rez.vendor.version.requirement import RequirementList -from rez.vendor.version.version import VersionRange +from rez.version import RequirementList +from rez.version import VersionRange from functools import partial diff --git a/src/rezgui/widgets/VariantHelpWidget.py b/src/rezgui/widgets/VariantHelpWidget.py index 1bd63be00..baa803cc9 100644 --- a/src/rezgui/widgets/VariantHelpWidget.py +++ b/src/rezgui/widgets/VariantHelpWidget.py @@ -6,7 +6,7 @@ from rezgui.util import create_pane, get_icon_widget from rezgui.mixins.ContextViewMixin import ContextViewMixin from rezgui.widgets.PackageLoadingWidget import PackageLoadingWidget -from rez.vendor.version.version import VersionRange +from rez.version import VersionRange from rez.package_help import PackageHelp from functools import partial diff --git a/src/rezgui/widgets/VariantVersionsTable.py b/src/rezgui/widgets/VariantVersionsTable.py index 1b5fb00a3..2f323b7a5 100644 --- a/src/rezgui/widgets/VariantVersionsTable.py +++ b/src/rezgui/widgets/VariantVersionsTable.py @@ -7,7 +7,7 @@ from rez.package_filter import PackageFilterList from rezgui.util import get_timestamp_str, update_font, get_icon_widget, create_pane from rez.packages import iter_packages -from rez.vendor.version.version import VersionRange +from rez.version import VersionRange class VariantVersionsTable(QtWidgets.QTableWidget, ContextViewMixin): diff --git a/src/rezgui/widgets/VariantVersionsWidget.py b/src/rezgui/widgets/VariantVersionsWidget.py index d8c4b8287..2557f6f7b 100644 --- a/src/rezgui/widgets/VariantVersionsWidget.py +++ b/src/rezgui/widgets/VariantVersionsWidget.py @@ -9,7 +9,7 @@ from rezgui.widgets.ChangelogEdit import ChangelogEdit from rezgui.mixins.ContextViewMixin import ContextViewMixin from rez.utils.formatting import positional_number_string -from rez.vendor.version.version import VersionRange +from rez.version import VersionRange class VariantVersionsWidget(PackageLoadingWidget, ContextViewMixin): diff --git a/src/rezplugins/package_repository/filesystem.py b/src/rezplugins/package_repository/filesystem.py index 31f9d9e64..f506ad038 100644 --- a/src/rezplugins/package_repository/filesystem.py +++ b/src/rezplugins/package_repository/filesystem.py @@ -35,7 +35,7 @@ from rez.backport.lru_cache import lru_cache from rez.vendor.schema.schema import Schema, Optional, And, Use, Or from rez.vendor.six import six -from rez.vendor.version.version import Version, VersionRange +from rez.version import Version, VersionRange basestring = six.string_types[0] diff --git a/src/rezplugins/package_repository/memory.py b/src/rezplugins/package_repository/memory.py index e6b018173..74d50731e 100644 --- a/src/rezplugins/package_repository/memory.py +++ b/src/rezplugins/package_repository/memory.py @@ -10,7 +10,7 @@ PackageResourceHelper, package_pod_schema from rez.utils.formatting import is_valid_package_name from rez.utils.resources import ResourcePool, cached_property -from rez.vendor.version.requirement import VersionedObject +from rez.version import VersionedObject # This repository type is used when loading 'developer' packages (a package.yaml From 24fe1267032f9897cf3cff0f8367894950b2b0af Mon Sep 17 00:00:00 2001 From: Jean-Christophe Morin Date: Sat, 16 Sep 2023 11:59:01 -0400 Subject: [PATCH 04/12] Add docstring to test_version Signed-off-by: Jean-Christophe Morin --- src/rez/cli/selftest.py | 3 +++ src/rez/tests/test_version.py | 10 ++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/rez/cli/selftest.py b/src/rez/cli/selftest.py index ef9e8a5de..a4b6fcf52 100644 --- a/src/rez/cli/selftest.py +++ b/src/rez/cli/selftest.py @@ -59,6 +59,9 @@ def __call__(self, parser, namespace, values, option_string=None): # create argparse entry for each module's unit test for name, module in sorted(tests): + if not module.__doc__: + raise RuntimeError("Module {0!r} doesn't have a docstring. Please add one.".format(module.__file__)) + parser.add_argument( "--%s" % name, action=AddTestModuleAction, nargs=0, dest="module_tests", default=[], diff --git a/src/rez/tests/test_version.py b/src/rez/tests/test_version.py index e5d68c199..0b49c774e 100644 --- a/src/rez/tests/test_version.py +++ b/src/rez/tests/test_version.py @@ -1,16 +1,18 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright Contributors to the Rez Project +""" +unit tests for 'rez.version' module +""" +import random +import textwrap +import unittest from rez.version import Version, AlphanumericVersionToken, \ VersionRange, reverse_sort_key from rez.version._version import _ReversedComparable from rez.version import Requirement, RequirementList from rez.version import VersionError -import random -import textwrap -import unittest - def _print(txt=''): From c679bc9cc6cee9af1cc032a438eb34a6710c4538 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Morin Date: Sat, 16 Sep 2023 12:14:39 -0400 Subject: [PATCH 05/12] Fix copyrights Signed-off-by: Jean-Christophe Morin --- src/build_utils/license/apply_copyright | 1 - src/rez/tests/test_version.py | 1 + src/rez/version/__init__.py | 2 ++ 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/build_utils/license/apply_copyright b/src/build_utils/license/apply_copyright index 6d5d1edbd..880cfa583 100755 --- a/src/build_utils/license/apply_copyright +++ b/src/build_utils/license/apply_copyright @@ -15,7 +15,6 @@ find ./src/rez/bind -name '*.py' > .lic.tmp find ./src/rez/cli -name '*.py' >> .lic.tmp find ./src/rez/tests -name '*.py' >> .lic.tmp find ./src/rez/utils -name '*.py' >> .lic.tmp -find ./src/rez/vendor/version -name '*.py' >> .lic.tmp find ./src/rez/bind -name '*.py' >> .lic.tmp find ./src/rezgui -name '*.py' >> .lic.tmp find ./src/rezplugins -name '*.py' >> .lic.tmp diff --git a/src/rez/tests/test_version.py b/src/rez/tests/test_version.py index 0b49c774e..3449e66da 100644 --- a/src/rez/tests/test_version.py +++ b/src/rez/tests/test_version.py @@ -1,6 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright Contributors to the Rez Project + """ unit tests for 'rez.version' module """ diff --git a/src/rez/version/__init__.py b/src/rez/version/__init__.py index bddc0fbd3..6be60ef81 100644 --- a/src/rez/version/__init__.py +++ b/src/rez/version/__init__.py @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright Contributors to the Rez Project + + from rez.version._requirement import Requirement, RequirementList, VersionedObject from rez.version._util import ParseException, VersionError from rez.version._version import ( From 6e3d7e1b7510c3db4bb9cbbe2fb92646de1d3118 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Morin Date: Sat, 16 Sep 2023 12:46:58 -0400 Subject: [PATCH 06/12] Fix flake8 warnings Signed-off-by: Jean-Christophe Morin --- src/rez/tests/test_version.py | 14 +++++----- src/rez/version/__init__.py | 6 ++-- src/rez/version/_version.py | 52 +++++++++++++++++++++-------------- 3 files changed, 41 insertions(+), 31 deletions(-) diff --git a/src/rez/tests/test_version.py b/src/rez/tests/test_version.py index 3449e66da..72c26b612 100644 --- a/src/rez/tests/test_version.py +++ b/src/rez/tests/test_version.py @@ -32,12 +32,12 @@ def _test_strict_weak_ordering(self, a, b): self.assertTrue(a == a) self.assertTrue(b == b) - e = (a == b) - ne = (a != b) - lt = (a < b) - lte = (a <= b) - gt = (a > b) - gte = (a >= b) + e = (a == b) + ne = (a != b) + lt = (a < b) + lte = (a <= b) + gt = (a > b) + gte = (a >= b) _print('\n' + textwrap.dedent( """ @@ -69,7 +69,7 @@ def _test_strict_weak_ordering(self, a, b): def _test_ordered(self, items): def _test(fn, items_, op_str): for i, a in enumerate(items_): - for b in items_[i+1:]: + for b in items_[i + 1:]: _print("'%s' %s '%s'" % (a, op_str, b)) self.assertTrue(fn(a, b)) diff --git a/src/rez/version/__init__.py b/src/rez/version/__init__.py index 6be60ef81..7280b9853 100644 --- a/src/rez/version/__init__.py +++ b/src/rez/version/__init__.py @@ -2,9 +2,9 @@ # Copyright Contributors to the Rez Project -from rez.version._requirement import Requirement, RequirementList, VersionedObject -from rez.version._util import ParseException, VersionError -from rez.version._version import ( +from rez.version._requirement import Requirement, RequirementList, VersionedObject # noqa: F401 +from rez.version._util import ParseException, VersionError # noqa: F401 +from rez.version._version import ( # noqa: F401 AlphanumericVersionToken, NumericToken, Version, diff --git a/src/rez/version/_version.py b/src/rez/version/_version.py index edfdb3f91..25b667184 100644 --- a/src/rez/version/_version.py +++ b/src/rez/version/_version.py @@ -448,6 +448,7 @@ def contains_version(self, version): return (version > self.version) \ or (self.inclusive and (version == self.version)) + _LowerBound.min = _LowerBound(Version(), True) @@ -480,6 +481,7 @@ def contains_version(self, version): return (version < self.version) \ or (self.inclusive and (version == self.version)) + _UpperBound.inf = _UpperBound(Version.inf, True) @@ -490,10 +492,13 @@ def __init__(self, lower=None, upper=None, invalid_bound_error=True): self.lower = lower or _LowerBound.min self.upper = upper or _UpperBound.inf - if (invalid_bound_error and - (self.lower.version > self.upper.version - or ((self.lower.version == self.upper.version) - and not (self.lower.inclusive and self.upper.inclusive)))): + if invalid_bound_error and ( + self.lower.version > self.upper.version + or ( + (self.lower.version == self.upper.version) + and not (self.lower.inclusive and self.upper.inclusive) + ) + ): raise VersionError("Invalid bound") def __str__(self): @@ -544,21 +549,22 @@ def intersects(self, other): lower = max(self.lower, other.lower) upper = min(self.upper, other.upper) - return (lower.version < upper.version) or \ - ((lower.version == upper.version) and - (lower.inclusive and upper.inclusive)) + return (lower.version < upper.version) or ( + (lower.version == upper.version) and (lower.inclusive and upper.inclusive) + ) def intersection(self, other): lower = max(self.lower, other.lower) upper = min(self.upper, other.upper) - if (lower.version < upper.version) or \ - ((lower.version == upper.version) and - (lower.inclusive and upper.inclusive)): + if (lower.version < upper.version) or ( + (lower.version == upper.version) and (lower.inclusive and upper.inclusive) + ): return _Bound(lower, upper) else: return None + _Bound.any = _Bound() @@ -597,7 +603,7 @@ class _VersionRangeParser(object): # Or match an inclusive bound (e.g. 1.0.0..2.0.0) " ^(?P" " (?P{version_group})?" - " \.\." # Required .. operator + r" \.\." # Required .. operator " (?P{version_group})?" " )$" "|" @@ -605,7 +611,7 @@ class _VersionRangeParser(object): " ^(?P" " (?P>|>=)?" # Bound is exclusive? " (?P{version_group})?" - " (?(lower_bound_prefix)|\+)" # + only if bound is not exclusive + r" (?(lower_bound_prefix)|\+)" # + only if bound is not exclusive " )$" "|" # Or match an upper bound (e.g. <=1.0.0) @@ -619,7 +625,7 @@ class _VersionRangeParser(object): " (?P" " (?P>|>=)?" # Lower bound is exclusive? " (?P{version_group})?" - " (?(range_lower_asc_prefix)|\+)?" # + only if lower bound is not exclusive + r" (?(range_lower_asc_prefix)|\+)?" # + only if lower bound is not exclusive " )(?P" " (?(range_lower_asc_version),?|)" # , only if lower bound is found " (?P<(?={version_group})|<=)" # <= only if followed by a version group @@ -632,10 +638,12 @@ class _VersionRangeParser(object): " (?P" " (?P<|<=)?" # Upper bound is exclusive? " (?P{version_group})?" - " (?(range_upper_desc_prefix)|\+)?" # + only if upper bound is not exclusive + r" (?(range_upper_desc_prefix)|\+)?" # + only if upper bound is not exclusive " )(?P" - " (?(range_upper_desc_version),|)" # Comma is not optional because we don't want to recognize something like "<4>3" - " (?P<(?={version_group})|>=?)" # >= or > only if followed by a version group + " (?(range_upper_desc_version),|)" # Comma is not optional because we don't want + # to recognize something like "<4>3" + " (?P<(?={version_group})|>=?)" # >= or > only if followed + # by a version group " (?P{version_group})?" " )" " )$" @@ -1131,8 +1139,9 @@ def iter_intersecting(self, iterable, key=None, descending=False): Returns: An iterator that returns items from `iterable` that intersect. """ - return _ContainsVersionIterator(self, iterable, key, descending, - mode=_ContainsVersionIterator.MODE_INTERSECTING) + return _ContainsVersionIterator( + self, iterable, key, descending, mode=_ContainsVersionIterator.MODE_INTERSECTING + ) def iter_non_intersecting(self, iterable, key=None, descending=False): """Like `iter_intersect_test`, but returns non-intersections only. @@ -1140,8 +1149,9 @@ def iter_non_intersecting(self, iterable, key=None, descending=False): Returns: An iterator that returns items from `iterable` that don't intersect. """ - return _ContainsVersionIterator(self, iterable, key, descending, - mode=_ContainsVersionIterator.MODE_NON_INTERSECTING) + return _ContainsVersionIterator( + self, iterable, key, descending, mode=_ContainsVersionIterator.MODE_NON_INTERSECTING + ) def span(self): """Return a contiguous range that is a superset of this range. @@ -1352,7 +1362,7 @@ def __init__(self, range_, iterable, key=None, descending=False, mode=MODE_ALL): self.fn = self._descending if descending else self._ascending self.it = iter(iterable) if key is None: - key = lambda x: x + key = lambda x: x # noqa: E731 self.keyfunc = key if mode == self.MODE_ALL: From b80d55246f35052db23d798a2e624140f761109a Mon Sep 17 00:00:00 2001 From: Jean-Christophe Morin Date: Sat, 16 Sep 2023 20:32:44 -0400 Subject: [PATCH 07/12] First documentation pass Signed-off-by: Jean-Christophe Morin --- docs/source/api.rst | 2 +- src/rez/version/__init__.py | 39 ++++- src/rez/version/_requirement.py | 161 +++++++++++------ src/rez/version/_version.py | 300 ++++++++++++++++++-------------- 4 files changed, 317 insertions(+), 185 deletions(-) diff --git a/docs/source/api.rst b/docs/source/api.rst index ad4c76fca..c58f7b36a 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -43,5 +43,5 @@ Python API rez.system rez.util rez.utils - rez.vendor.version + rez.version rez.wrapper diff --git a/src/rez/version/__init__.py b/src/rez/version/__init__.py index 7280b9853..dafa532d8 100644 --- a/src/rez/version/__init__.py +++ b/src/rez/version/__init__.py @@ -2,9 +2,28 @@ # Copyright Contributors to the Rez Project -from rez.version._requirement import Requirement, RequirementList, VersionedObject # noqa: F401 -from rez.version._util import ParseException, VersionError # noqa: F401 -from rez.version._version import ( # noqa: F401 +""" +Implements a well defined versioning schema. + +There are three class types: :class:`VersionToken`, :class:`Version` and :class:`VersionRange`. +A :class:`Version` is a set of zero or more :class:`VersionToken`\\s, separate by ``.``\\s or ``-``\\s (eg ``1.2-3``). +A :class:`VersionToken` is a string containing alphanumerics, and default implemenations +:class:`NumericToken` and :class:`AlphanumericVersionToken` are supplied. You can implement +your own if you want stricter tokens or different sorting behaviour. + +A :class:`VersionRange` is a set of one or more contiguous version ranges. For example, +``3+<5`` contains any version >=3 but less than 5. Version ranges can be used to +define dependency requirements between objects. They can be OR'd together, AND'd +and inverted. + +The empty version ``''``, and empty version range ``''``, are also handled. The empty +version is used to denote unversioned objects. The empty version range, also +known as the 'any' range, is used to refer to any version of an object. +""" + +from rez.version._requirement import Requirement, RequirementList, VersionedObject +from rez.version._util import ParseException, VersionError +from rez.version._version import ( AlphanumericVersionToken, NumericToken, Version, @@ -12,3 +31,17 @@ VersionToken, reverse_sort_key, ) + +__all__ = ( + "Version", + "VersionRange", + "Requirement", + "RequirementList", + "VersionedObject", + "VersionToken", + "NumericToken", + "AlphanumericVersionToken", + "reverse_sort_key", + "ParseException", + "VersionError", +) diff --git a/src/rez/version/_requirement.py b/src/rez/version/_requirement.py index d476e9ff1..9e72a1133 100644 --- a/src/rez/version/_requirement.py +++ b/src/rez/version/_requirement.py @@ -8,18 +8,23 @@ class VersionedObject(_Common): - """Definition of a versioned object, eg "foo-1.0". + """Definition of a versioned object, eg ``foo-1.0``. - "foo" is also a valid object definiton - when there is no version part, we + ``foo`` is also a valid object definiton. When there is no version part, we are defining an unversioned object. - Note that '-', '@' or '#' can be used as the seperator between object name - and version, however this is purely cosmetic - "foo-1" is the same as "foo@1". + .. note:: + Note that ``-``, ``@`` or ``#`` can be used as the seperator between object name + and version, however this is purely cosmetic. ``foo-1`` is the same as ``foo@1``. """ sep_regex_str = r'[-@#]' sep_regex = re.compile(sep_regex_str) def __init__(self, s): + """ + Args: + s (str): + """ self.name_ = None self.version_ = None self.sep_ = '-' @@ -42,8 +47,8 @@ def construct(cls, name, version=None): """Create a VersionedObject directly from an object name and version. Args: - name: Object name string. - version: Version object. + name (str): Object name string. + version (typing.Optional[Version]): Version object. """ other = VersionedObject(None) other.name_ = name @@ -52,19 +57,27 @@ def construct(cls, name, version=None): @property def name(self): - """Name of the object.""" + """Name of the object. + + Returns: + str: + """ return self.name_ @property def version(self): - """Version of the object.""" + """Version of the object. + + Returns: + Version: + """ return self.version_ def as_exact_requirement(self): """Get the versioned object, as an exact requirement string. Returns: - Equivalent requirement string, eg "maya==2016.1" + str: Equivalent requirement string, eg ``maya==2016.1`` """ sep_str = '' ver_str = '' @@ -91,42 +104,46 @@ def __str__(self): class Requirement(_Common): - """Requirement for a versioned object. - - Examples of valid requirement strings: - - foo-1.0 - foo@1.0 - foo#1.0 - foo-1+ - foo-1+<4.3 - foo<3 - foo==1.0.1 - - Defines a requirement for an object. For example, "foo-5+" means that you - require any version of "foo", version 5 or greater. An unversioned - requirement can also be used ("foo"), this means you require any version of + """ + Defines a requirement for an object. For example, ``foo-5+`` means that you + require any version of ``foo``, version 5 or greater. An unversioned + requirement can also be used (``foo``), this means you require any version of foo. You can drop the hyphen between object name and version range if the - version range starts with a non-alphanumeric character - eg "foo<2". + version range starts with a non-alphanumeric character - eg ``foo<2``. There are two different prefixes that can be applied to a requirement: - - "!": The conflict requirement. This means that you require this version + - ``!``: The conflict requirement. This means that you require this version range of an object NOT to be present. To conflict with all versions of an object, use "!foo". - - - "~": This is known as a "weak reference", and means, "I do not require this + - ``~``: This is known as a "weak reference", and means, "I do not require this object, but if present, it must be within this range." It is equivalent to the *conflict of the inverse* of the given version range. - There is one subtle case to be aware of. "~foo" is a requirement that has no - effect - ie, it means "I do not require foo, but if foo is present, it can + There is one subtle case to be aware of. ``~foo`` is a requirement that has no + effect. It means "I do not require foo, but if foo is present, it can be any version." This statement is still valid, but will produce a Requirement object with a None range. + + Examples of valid requirement strings: + + - ``foo-1.0`` + - ``foo@1.0`` + - ``foo#1.0`` + - ``foo-1+`` + - ``foo-1+<4.3`` + - ``foo<3`` + - ``foo==1.0.1`` """ sep_regex = re.compile(r'[-@#=<>]') def __init__(self, s, invalid_bound_error=True): + """ + Args: + s (str): Requirement string + invalid_bound_error (bool): If True, raise :exc:`VersionError` if an + impossible range is given, such as ``3+<2``. + """ self.name_ = None self.range_ = None self.negate_ = False @@ -170,8 +187,8 @@ def construct(cls, name, range=None): """Create a requirement directly from an object name and VersionRange. Args: - name: Object name string. - range: VersionRange object. If None, an unversioned requirement is + name (str): Object name string. + range (typing.Optional[VersionRange]): If None, an unversioned requirement is created. """ other = Requirement(None) @@ -181,17 +198,28 @@ def construct(cls, name, range=None): @property def name(self): - """Name of the required object.""" + """Name of the required object. + + Returns: + str: + """ return self.name_ @property def range(self): - """VersionRange of the requirement.""" + """Version range of the requirement. + + Returns: + VersionRange: + """ return self.range_ @property def conflict(self): """True if the requirement is a conflict requirement, eg "!foo", "~foo-1". + + Returns: + bool: """ return self.conflict_ @@ -199,20 +227,32 @@ def conflict(self): def weak(self): """True if the requirement is weak, eg "~foo". - Note that weak requirements are also conflict requirements, but not - necessarily the other way around. + .. note:: + Note that weak requirements are also conflict requirements, but not + necessarily the other way around. + + Returns: + bool: """ return self.negate_ def safe_str(self): """Return a string representation that is safe for the current filesystem, and guarantees that no two different Requirement objects will encode to - the same value.""" + the same value. + + Returns: + str: + """ return str(self) def conflicts_with(self, other): - """Returns True if this requirement conflicts with another `Requirement` - or `VersionedObject`.""" + """Returns True if this requirement conflicts with another :class:`Requirement` + or :class:`VersionedObject`. + + Returns: + bool: + """ if isinstance(other, Requirement): if (self.name_ != other.name_) or (self.range is None) \ or (other.range is None): @@ -233,16 +273,20 @@ def conflicts_with(self, other): return (other.version_ not in self.range_) def merged(self, other): - """Returns the merged result of two requirements. + """Merge two requirements. Two requirements can be in conflict and if so, this function returns - None. For example, requests for "foo-4" and "foo-6" are in conflict, + None. For example, requests for ``foo-4`` and ``foo-6`` are in conflict, since both cannot be satisfied with a single version of foo. Some example successful requirements merges are: - - "foo-3+" and "!foo-5+" == "foo-3+<5" - - "foo-1" and "foo-1.5" == "foo-1.5" - - "!foo-2" and "!foo-5" == "!foo-2|5" + + - ``foo-3+`` and ``!foo-5+`` == ``foo-3+<5`` + - ``foo-1`` and ``foo-1.5`` == ``foo-1.5`` + - ``!foo-2`` and ``!foo-5`` == ``!foo-2|5`` + + Returns: + Requirement: the merged result of two requirements. """ if self.name_ != other.name_: return None # cannot merge across object names @@ -327,10 +371,9 @@ class RequirementList(_Common): is retained. """ def __init__(self, requirements): - """Create a RequirementList. - + """ Args: - requirements: List of Requirement objects. + requirements (list[Requirement]): List of requirements. """ self.requirements_ = [] self.conflict_ = None @@ -370,6 +413,9 @@ def __init__(self, requirements): def requirements(self): """Returns optimised list of requirements, or None if there are conflicts. + + Returns: + list[Requirement]: """ return self.requirements_ @@ -378,20 +424,27 @@ def conflict(self): """Get the requirement conflict, if any. Returns: - None if there is no conflict, otherwise a 2-tuple containing the - conflicting Requirement objects. + typing.Optional[tuple[Requirement]]: None if there is no conflict, otherwise a + 2-tuple containing the conflicting requirement objects. """ return self.conflict_ @property def names(self): """Set of names of requirements, not including conflict requirements. + + Returns: + set[str]: """ return self.names_ @property def conflict_names(self): - """Set of conflict requirement names.""" + """Set of conflict requirement names. + + Returns: + set[str]: + """ return self.conflict_names_ def __iter__(self): @@ -399,7 +452,13 @@ def __iter__(self): yield requirement def get(self, name): - """Returns the Requirement for the given object, or None. + """Returns the requirement for the given object, or None. + + Args: + name (str): requirement to get. + + Returns: + Requirement: """ return self.requirements_dict.get(name) diff --git a/src/rez/version/_version.py b/src/rez/version/_version.py index 25b667184..75d3b4397 100644 --- a/src/rez/version/_version.py +++ b/src/rez/version/_version.py @@ -2,24 +2,6 @@ # Copyright Contributors to the Rez Project -""" -Implements a well defined versioning schema. - -There are three class types - VersionToken, Version and VersionRange. A Version -is a set of zero or more VersionTokens, separate by '.'s or '-'s (eg "1.2-3"). -A VersionToken is a string containing alphanumerics, and default implemenations -'NumericToken' and 'AlphanumericVersionToken' are supplied. You can implement -your own if you want stricter tokens or different sorting behaviour. - -A VersionRange is a set of one or more contiguous version ranges - for example, -"3+<5" contains any version >=3 but less than 5. Version ranges can be used to -define dependency requirements between objects. They can be OR'd together, AND'd -and inverted. - -The empty version '', and empty version range '', are also handled. The empty -version is used to denote unversioned objects. The empty version range, also -known as the 'any' range, is used to refer to any version of an object. -""" from __future__ import print_function from rez.version._util import VersionError, ParseException, _Common, \ dedup @@ -70,33 +52,35 @@ class VersionToken(_Comparable): """Token within a version number. A version token is that part of a version number that appears between a - delimiter, typically '.' or '-'. For example, the version number '2.3.07b' - contains the tokens '2', '3' and '07b' respectively. + delimiter, typically ``.`` or ``-``. For example, the version number ``2.3.07b`` + contains the tokens ``2``, ``3`` and ``07b`` respectively. Version tokens are only allowed to contain alphanumerics (any case) and underscores. """ def __init__(self, token): - """Create a VersionToken. - + """ Args: - token: Token string, eg "rc02" + token (str): Token string, eg "rc02" """ raise NotImplementedError @classmethod def create_random_token_string(cls): - """Create a random token string. For testing purposes only.""" + """Create a random token string. For testing purposes only. + + :meta private: + """ raise NotImplementedError def less_than(self, other): - """Compare to another VersionToken. + """Compare to another :class:`VersionToken`. Args: - other: The VersionToken object to compare against. + other (VersionToken): The VersionToken object to compare against. Returns: - True if this token is less than other, False otherwise. + bool: True if this token is less than other, False otherwise. """ raise NotImplementedError @@ -174,23 +158,26 @@ class AlphanumericVersionToken(VersionToken): """Alphanumeric version token. These tokens compare as follows: + - each token is split into alpha and numeric groups (subtokens); - the resulting subtoken list is compared. - alpha comparison is case-sensitive, numeric comparison is padding-sensitive. Subtokens compare as follows: + - alphas come before numbers; - - alphas are compared alphabetically (_, then A-Z, then a-z); - - numbers are compared numerically. If numbers are equivalent but zero- - padded differently, they are then compared alphabetically. Thus "01" < "1". + - alphas are compared alphabetically (``_``, then A-Z, then a-z); + - numbers are compared numerically. If numbers are equivalent but zero-padded + differently, they are then compared alphabetically. Thus ``01`` < ``1``. Some example comparisons that equate to true: - - "3" < "4" - - "01" < "1" - - "beta" < "1" - - "alpha3" < "alpha4" - - "alpha" < "alpha3" - - "gamma33" < "33gamma" + + - ``3`` < ``4`` + - ``01`` < ``1`` + - ``beta`` < ``1`` + - ``alpha3`` < ``alpha4`` + - ``alpha`` < ``alpha3`` + - ``gamma33`` < ``33gamma`` """ numeric_regex = re.compile("[0-9]+") regex = re.compile(r"[a-zA-Z0-9_]+\Z") @@ -265,33 +252,31 @@ def reverse_sort_key(comparable): False Args: - comparable (`Version` or `VesionRange`): Object to wrap. + comparable (Version or VersionRange): Object to wrap. Returns: - `_ReversedComparable`: Wrapper object that reverses comparisons. + _ReversedComparable: Wrapper object that reverses comparisons. """ return _ReversedComparable(comparable) class Version(_Comparable): - """Version object. - + """ A Version is a sequence of zero or more version tokens, separated by either - a dot '.' or hyphen '-' delimiters. Note that separators only affect Version - objects cosmetically - in other words, the version '1.0.0' is equivalent to - '1-0-0'. + a dot ``.`` or hyphen ``-`` delimiters. Note that separators only affect Version + objects cosmetically. In other words, the version ``1.0.0`` is equivalent to + ``1-0-0``. - The empty version '' is the smallest possible version, and can be used to + The empty version ``''`` is the smallest possible version, and can be used to represent an unversioned resource. """ inf = None def __init__(self, ver_str='', make_token=AlphanumericVersionToken): - """Create a Version object. - + """ Args: - ver_str: Version string. - make_token: Callable that creates a VersionToken subclass from a + ver_str (str): Version string. + make_token (typing.Callable[[str], None]): Callable that creates a VersionToken subclass from a string. """ self.tokens = [] @@ -318,7 +303,12 @@ def __init__(self, ver_str='', make_token=AlphanumericVersionToken): self.seps = seps[1:-1] def copy(self): - """Returns a copy of the version.""" + """ + Returns a copy of the version. + + Returns: + Version: + """ other = Version(None) other.tokens = self.tokens[:] other.seps = self.seps[:] @@ -330,6 +320,9 @@ def trim(self, len_): Args: len_ (int): New version length. If >= current length, an unchanged copy of the version is returned. + + Returns: + Version: """ other = Version(None) other.tokens = self.tokens[:len_] @@ -337,7 +330,7 @@ def trim(self, len_): return other def __next__(self): - """Return 'next' version. Eg, next(1.2) is 1.2_""" + """Return :meth:`next` version. Eg, ``next(1.2)`` is ``1.2_``""" if self.tokens: other = self.copy() tok = other.tokens.pop() @@ -351,17 +344,29 @@ def next(self): @property def major(self): - """Semantic versioning major version.""" + """Semantic versioning major version. + + Returns: + VersionToken: A VersionToken or a subclass of a VersionToken. + """ return self[0] @property def minor(self): - """Semantic versioning minor version.""" + """Semantic versioning minor version. + + Returns: + VersionToken: A VersionToken or a subclass of a VersionToken. + """ return self[1] @property def patch(self): - """Semantic versioning patch version.""" + """Semantic versioning patch version. + + Returns: + VersionToken: A VersionToken or a subclass of a VersionToken. + """ return self[2] def as_tuple(self): @@ -371,6 +376,9 @@ def as_tuple(self): >>> print Version("1.2.12").as_tuple() ('1', '2', '12') + + Returns: + tuple[str]: """ return tuple(map(str, self.tokens)) @@ -803,17 +811,16 @@ def _act_lower_and_upper_bound_desc(self): class VersionRange(_Comparable): - """Version range. - + """ A version range is a set of one or more contiguous ranges of versions. For example, "3.0 or greater, but less than 4" is a contiguous range that contains - versions such as "3.0", "3.1.0", "3.99" etc. Version ranges behave something - like sets - they can be intersected, added and subtracted, but can also be - inverted. You can test to see if a Version is contained within a VersionRange. + versions such as ``3.0``, ``3.1.0``, ``3.99`` etc. Version ranges behave something + like sets. They can be intersected, added and subtracted, but can also be + inverted. You can test to see if a :class:`Version` is contained within a :class:`VersionRange`. - A VersionRange "3" (for example) is the superset of any version "3[.X.X...]". - The version "3" itself is also within this range, and is smaller than "3.0" - - any version with common leading tokens, but with a larger token count, is + A VersionRange ``3`` (for example) is the superset of any version ``3[.X.X...]``. + The version ``3`` itself is also within this range, and is smaller than ``3.0``. + Any version with common leading tokens, but with a larger token count, is the larger version of the two. VersionRange objects have a flexible syntax that let you describe any @@ -821,47 +828,53 @@ class VersionRange(_Comparable): and lower bounds. This is best explained by example (those listed on the same line are equivalent): - "3": 'superset' syntax, contains "3", "3.0", "3.1.4" etc; - "2+", ">=2": inclusive lower bound syntax, contains "2", "2.1", "5.0.0" etc; - ">2": exclusive lower bound; - "<5": exclusive upper bound; - "<=5": inclusive upper bound; - "==2": a range that contains only the exact single version "2". + - ``3``: 'superset' syntax, contains ``3``, ``3.0``, ``3.1.4`` etc; + - ``2+``, ``>=2``: inclusive lower bound syntax, contains ``2``, ``2.1``, ``5.0.0`` etc; + - ``>2``: exclusive lower bound; + - ``<5``: exclusive upper bound; + - ``<=5``: inclusive upper bound; + - ``==2``: a range that contains only the exact single version ``2``. - "1+<5", ">=1<5": inclusive lower, exclusive upper. The most common form of - a 'bounded' version range (ie, one with a lower and upper bound); - ">1<5": exclusive lower, exclusive upper; - ">1<=5": exclusive lower, inclusive upper; - "1+<=5", "1..5": inclusive lower, inclusive upper; + .. - "<=4,>2", "<4,>2", "<4,>=2": Reverse pip syntax (note comma) + - ``1+<5``, ``>=1<5``: inclusive lower, exclusive upper. The most common form of + a 'bounded' version range (ie, one with a lower and upper bound); + + .. + + - ``>1<5``: exclusive lower, exclusive upper; + - ``>1<=5``: exclusive lower, inclusive upper; + - ``1+<=5``, ``1..5``: inclusive lower, inclusive upper; + + .. + + - ``<=4,>2``, ``<4,>2``, ``<4,>=2``: Reverse pip syntax (note comma) To help with readability, bounded ranges can also have their bounds separated - with a comma, eg ">=2,<=6". The comma is purely cosmetic and is dropped in + with a comma, eg ``>=2,<=6``. The comma is purely cosmetic and is dropped in the string representation. - To describe more than one contiguous range, seperate ranges with the or '|' - symbol. For example, the version range "4|6+" contains versions such as "4", - "4.0", "4.3.1", "6", "6.1", "10.0.0", but does not contain any version - "5[.X.X...X]". If you provide multiple ranges that overlap, they will be - automatically optimised - for example, the version range "3+<6|4+<8" - becomes "3+<8". + To describe more than one contiguous range, seperate ranges with the or ``|`` + symbol. For example, the version range ``4|6+`` contains versions such as ``4``, + ``4.0``, ``4.3.1``, ``6``, ``6.1``, ``10.0.0``, but does not contain any version + ``5[.X.X...X]``. If you provide multiple ranges that overlap, they will be + automatically optimised. For example, the version range ``3+<6|4+<8`` + becomes ``3+<8``. Note that the empty string version range represents the superset of all - possible versions - this is called the "any" range. The empty version can + possible versions. This is called the "any" range. The empty version can also be used as an upper or lower bound, leading to some odd but perfectly - valid version range syntax. For example, ">" is a valid range - read like - ">''", it means "any version greater than the empty version". + valid version range syntax. For example, ``>`` is a valid range - read like + ``>''``, it means ``any version greater than the empty version``. """ def __init__(self, range_str='', make_token=AlphanumericVersionToken, invalid_bound_error=True): - """Create a VersionRange object. - + """ Args: - range_str: Range string, such as "3", "3+<4.5", "2|6+". The range + range_str (str): Range string, such as "3", "3+<4.5", "2|6+". The range will be optimised, so the string representation of this instance may not match range_str. For example, "3+<6|4+<8" == "3+<8". - make_token: Version token class to use. + make_token (typing.Type[VersionToken]): Version token class to use. invalid_bound_error (bool): If True, raise an exception if an impossible range is given, such as '3+<2'. """ @@ -887,30 +900,46 @@ def __init__(self, range_str='', make_token=AlphanumericVersionToken, self.bounds.append(_Bound.any) def is_any(self): - """Returns True if this is the "any" range, ie the empty string range - that contains all versions.""" + """ + Returns: + bool: True if this is the "any" range, ie the empty string range + that contains all versions. + """ return (len(self.bounds) == 1) and (self.bounds[0] == _Bound.any) def lower_bounded(self): - """Returns True if the range has a lower bound (that is not the empty - version).""" + """ + Returns: + bool: True if the range has a lower bound (that is not the empty + version). + """ return self.bounds[0].lower_bounded() def upper_bounded(self): - """Returns True if the range has an upper bound.""" + """ + Returns: + bool: True if the range has an upper bound. + """ return self.bounds[-1].upper_bounded() def bounded(self): - """Returns True if the range has a lower and upper bound.""" + """ + Returns: + bool: True if the range has a lower and upper bound. + """ return (self.lower_bounded() and self.upper_bounded()) def issuperset(self, range): - """Returns True if the VersionRange is contained within this range. + """ + Returns: + bool: True if the VersionRange is contained within this range. """ return self._issuperset(self.bounds, range.bounds) def issubset(self, range): - """Returns True if we are contained within the version range. + """ + Returns: + bool: True if we are contained within the version range. """ return range.issuperset(self) @@ -920,10 +949,10 @@ def union(self, other): Calculates the union of this range with one or more other ranges. Args: - other: VersionRange object (or list of) to OR with. + other (VersionRange or list[VersionRange]): Version range object(s) to OR with. Returns: - New VersionRange object representing the union. + VersionRange: Range object representing the union. """ if not hasattr(other, "__iter__"): other = [other] @@ -942,10 +971,10 @@ def intersection(self, other): Calculates the intersection of this range with one or more other ranges. Args: - other: VersionRange object (or list of) to AND with. + other (VersionRange or list[VersionRange]): Version range object(s) to AND with. Returns: - New VersionRange object representing the intersection, or None if + typing.Optional[VersionRange]: New VersionRange object representing the intersection, or None if no ranges intersect. """ if not hasattr(other, "__iter__"): @@ -965,7 +994,7 @@ def inverse(self): """Calculate the inverse of the range. Returns: - New VersionRange object representing the inverse of this range, or + typing.Optional[VersionRange]: New VersionRange object representing the inverse of this range, or None if there is no inverse (ie, this range is the any range). """ if self.is_any(): @@ -980,10 +1009,10 @@ def intersects(self, other): """Determine if we intersect with another range. Args: - other: VersionRange object. + other (VersionRange): Version range object. Returns: - True if the ranges intersect, False otherwise. + bool: True if the ranges intersect, False otherwise. """ return self._intersects(self.bounds, other.bounds) @@ -991,8 +1020,8 @@ def split(self): """Split into separate contiguous ranges. Returns: - A list of VersionRange objects. For example, the range "3|5+" will - be split into ["3", "5+"]. + list[VersionRange]: A list of VersionRange objects. For example, the range ``3|5+`` will + be split into ``["3", "5+"]``. """ ranges = [] for bound in self.bounds: @@ -1007,11 +1036,12 @@ def as_span(cls, lower_version=None, upper_version=None, """Create a range from lower_version..upper_version. Args: - lower_version: Version object representing lower bound of the range. - upper_version: Version object representing upper bound of the range. - + lower_version (Version): Version object representing lower bound of the range. + upper_version (Version): Version object representing upper bound of the range. + lower_inclusive (bool): Include lower_version into the span. + upper_inclusive (bool): Include upper_inclusive into the span. Returns: - `VersionRange` object. + VersionRange: """ lower = (None if lower_version is None else _LowerBound(lower_version, lower_inclusive)) @@ -1028,14 +1058,14 @@ def from_version(cls, version, op=None): """Create a range from a version. Args: - version: Version object. This is used as the upper/lower bound of + version (Version): This is used as the upper/lower bound of the range. - op: Operation as a string. One of 'gt'/'>', 'gte'/'>=', lt'/'<', - 'lte'/'<=', 'eq'/'=='. If None, a bounded range will be created + op (typing.Optional[str]): Operation as a string. One of: gt, >, gte, >=, lt, <, + lte, <=, eq, ==. If None, a bounded range will be created that contains the version superset. Returns: - `VersionRange` object. + VersionRange: """ lower = None upper = None @@ -1067,13 +1097,13 @@ def from_versions(cls, versions): """Create a range from a list of versions. This method creates a range that contains only the given versions and - no other. Typically the range looks like (for eg) "==3|==4|==5.1". + no other. Typically the range looks like (for eg) ``==3|==4|==5.1``. Args: - versions: List of Version objects. + versions (list[Version]): List of Version objects. Returns: - `VersionRange` object. + VersionRange: """ range = cls(None) range.bounds = [] @@ -1087,6 +1117,9 @@ def from_versions(cls, versions): def to_versions(self): """Returns exact version ranges as Version objects, or None if there are no exact version ranges present. + + Returns: + typing.Optional[list[Version]]: """ versions = [] for bound in self.bounds: @@ -1097,7 +1130,11 @@ def to_versions(self): return versions or None def contains_version(self, version): - """Returns True if version is contained in this range.""" + """Returns True if version is contained in this range. + + Returns: + bool: + """ if len(self.bounds) < 5: # not worth overhead of binary search for bound in self.bounds: @@ -1121,20 +1158,20 @@ def iter_intersect_test(self, iterable, key=None, descending=False): Args: iterable: An ordered sequence of versioned objects. If the list is not sorted by version, behaviour is undefined. - key (callable): Function that returns a `Version` given an object - from `iterable`. If None, the identity function is used. - descending (bool): Set to True if `iterable` is in descending + key (callable): Function that returns a :class:`Version` given an object + from ``iterable``. If None, the identity function is used. + descending (bool): Set to True if ``iterable`` is in descending version order. Returns: - An iterator that returns (bool, object) tuples, where 'object' is - the original object in `iterable`, and the bool indicates whether + ~collections.abc.Iterator[tuple[bool, typing.Any]]: An iterator that returns (bool, object) tuples, where 'object' is + the original object in ``iterable``, and the bool indicates whether that version is contained in this range. """ return _ContainsVersionIterator(self, iterable, key, descending) def iter_intersecting(self, iterable, key=None, descending=False): - """Like `iter_intersect_test`, but returns intersections only. + """Like :meth:iter_intersect_test`, but returns intersections only. Returns: An iterator that returns items from `iterable` that intersect. @@ -1144,7 +1181,7 @@ def iter_intersecting(self, iterable, key=None, descending=False): ) def iter_non_intersecting(self, iterable, key=None, descending=False): - """Like `iter_intersect_test`, but returns non-intersections only. + """Like :meth:`iter_intersect_test`, but returns non-intersections only. Returns: An iterator that returns items from `iterable` that don't intersect. @@ -1157,8 +1194,8 @@ def span(self): """Return a contiguous range that is a superset of this range. Returns: - A VersionRange object representing the span of this range. For - example, the span of "2+<4|6+<8" would be "2+<8". + VersionRange: A range object representing the span of this range. For + example, the span of ``2+<4|6+<8`` would be ``2+<8``. """ other = VersionRange(None) bound = _Bound(self.bounds[0].lower, self.bounds[-1].upper) @@ -1172,7 +1209,7 @@ def visit_versions(self, func): This is for advanced usage only. - If `func` returns a `Version`, this call will change the versions in + If ``func`` returns a :class:`Version`, this call will change the versions in place. It is possible to change versions in a way that is nonsensical - for @@ -1180,10 +1217,13 @@ def visit_versions(self, func): Use at your own risk. Args: - func (callable): Takes a `Version` instance arg, and is applied to - every version in the range. If `func` returns a `Version`, it - will replace the existing version, updating this `VersionRange` - instance in place. + func (typing.Callable[[Version], typing.Optional[Version]]): Takes a + version, and is applied to every version in the range. + If ``func`` returns a :class:`Version`, it will replace the existing version, + updating this :class:`VersionRange` instance in place. + + Returns: + None: """ for bound in self.bounds: if bound.lower is not _LowerBound.min: From 7aa64b97c3ab2bcb3e0132590b9c3943c789cde9 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Morin Date: Sat, 28 Oct 2023 10:34:38 -0400 Subject: [PATCH 08/12] Re-add rez.vendor.version with redirects and a deprecation warning Signed-off-by: Jean-Christophe Morin --- src/rez/vendor/version/__init__.py | 11 +++++++++++ src/rez/vendor/version/requirement.py | 5 +++++ src/rez/vendor/version/util.py | 5 +++++ src/rez/vendor/version/version.py | 5 +++++ 4 files changed, 26 insertions(+) create mode 100644 src/rez/vendor/version/__init__.py create mode 100644 src/rez/vendor/version/requirement.py create mode 100644 src/rez/vendor/version/util.py create mode 100644 src/rez/vendor/version/version.py diff --git a/src/rez/vendor/version/__init__.py b/src/rez/vendor/version/__init__.py new file mode 100644 index 000000000..57d748640 --- /dev/null +++ b/src/rez/vendor/version/__init__.py @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright Contributors to the Rez Project + + +import warnings + +warnings.warn( + "module 'rez.vendor.version' is deprecated and will be removed in 3.0.0. Use 'rez.version' instead.", + DeprecationWarning, + stacklevel=2 +) diff --git a/src/rez/vendor/version/requirement.py b/src/rez/vendor/version/requirement.py new file mode 100644 index 000000000..04f53ae5f --- /dev/null +++ b/src/rez/vendor/version/requirement.py @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright Contributors to the Rez Project + + +from rez.version._requirement import * diff --git a/src/rez/vendor/version/util.py b/src/rez/vendor/version/util.py new file mode 100644 index 000000000..49dddd77c --- /dev/null +++ b/src/rez/vendor/version/util.py @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright Contributors to the Rez Project + + +from rez.version._util import * diff --git a/src/rez/vendor/version/version.py b/src/rez/vendor/version/version.py new file mode 100644 index 000000000..f3b7c54d7 --- /dev/null +++ b/src/rez/vendor/version/version.py @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright Contributors to the Rez Project + + +from rez.version._version import * From b33b96439fd11c0ec7ad8cbadc3dd39ac5613de8 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Morin Date: Sat, 28 Oct 2023 10:36:41 -0400 Subject: [PATCH 09/12] Fix lint warning Signed-off-by: Jean-Christophe Morin --- src/rez/version/_version.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/rez/version/_version.py b/src/rez/version/_version.py index 75d3b4397..bcacd7a34 100644 --- a/src/rez/version/_version.py +++ b/src/rez/version/_version.py @@ -1164,7 +1164,8 @@ def iter_intersect_test(self, iterable, key=None, descending=False): version order. Returns: - ~collections.abc.Iterator[tuple[bool, typing.Any]]: An iterator that returns (bool, object) tuples, where 'object' is + ~collections.abc.Iterator[tuple[bool, typing.Any]]: An iterator that returns (bool, object) tuples, + where 'object' is the original object in ``iterable``, and the bool indicates whether that version is contained in this range. """ From 6054d5c5215ab1fd7391729d28278e2c93a5aacc Mon Sep 17 00:00:00 2001 From: Jean-Christophe Morin Date: Sat, 28 Oct 2023 10:59:01 -0400 Subject: [PATCH 10/12] Improve docs Signed-off-by: Jean-Christophe Morin --- src/rez/version/__init__.py | 5 ++++- src/rez/version/_version.py | 5 ++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/rez/version/__init__.py b/src/rez/version/__init__.py index dafa532d8..af11036e9 100644 --- a/src/rez/version/__init__.py +++ b/src/rez/version/__init__.py @@ -3,7 +3,7 @@ """ -Implements a well defined versioning schema. +Implements everything needed to manipulate versions and requirements. There are three class types: :class:`VersionToken`, :class:`Version` and :class:`VersionRange`. A :class:`Version` is a set of zero or more :class:`VersionToken`\\s, separate by ``.``\\s or ``-``\\s (eg ``1.2-3``). @@ -19,6 +19,9 @@ The empty version ``''``, and empty version range ``''``, are also handled. The empty version is used to denote unversioned objects. The empty version range, also known as the 'any' range, is used to refer to any version of an object. + +Requirements and list of requirements are represented by :class:`Requirement` and +:class:`RequirementList` respectively. """ from rez.version._requirement import Requirement, RequirementList, VersionedObject diff --git a/src/rez/version/_version.py b/src/rez/version/_version.py index bcacd7a34..8658980a2 100644 --- a/src/rez/version/_version.py +++ b/src/rez/version/_version.py @@ -1158,15 +1158,14 @@ def iter_intersect_test(self, iterable, key=None, descending=False): Args: iterable: An ordered sequence of versioned objects. If the list is not sorted by version, behaviour is undefined. - key (callable): Function that returns a :class:`Version` given an object + key (typing.Callable[typing.Any]): Function that returns a :class:`Version` given an object from ``iterable``. If None, the identity function is used. descending (bool): Set to True if ``iterable`` is in descending version order. Returns: ~collections.abc.Iterator[tuple[bool, typing.Any]]: An iterator that returns (bool, object) tuples, - where 'object' is - the original object in ``iterable``, and the bool indicates whether + where 'object' is the original object in ``iterable``, and the bool indicates whether that version is contained in this range. """ return _ContainsVersionIterator(self, iterable, key, descending) From 0644e888f7ef31af6020f06e27b20e73fd89c325 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Morin Date: Sat, 18 Nov 2023 14:46:32 -0500 Subject: [PATCH 11/12] Remove most sphinx warnings added by this branch Signed-off-by: Jean-Christophe Morin --- docs/source/conf.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 4702e6547..ed9fad1cd 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -48,7 +48,9 @@ # TODO: Remove once we unvendor enum. ("py:class", "rez.solver._Common"), ("py:class", "_thread._local"), - ("py:class", "rez.utils.platform_._UnixPlatform") + ("py:class", "rez.utils.platform_._UnixPlatform"), + ("py:class", "rez.version._util._Common"), + ("py:class", "rez.version._version._Comparable"), ] nitpick_ignore_regex = [ From 5700f663d24ab4f5ffdcb12dfd05c96ab1ccbe72 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Morin Date: Thu, 23 Nov 2023 19:40:59 -0500 Subject: [PATCH 12/12] Use rez.deprecations Signed-off-by: Jean-Christophe Morin --- src/rez/vendor/version/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rez/vendor/version/__init__.py b/src/rez/vendor/version/__init__.py index 57d748640..ec87df48e 100644 --- a/src/rez/vendor/version/__init__.py +++ b/src/rez/vendor/version/__init__.py @@ -2,10 +2,10 @@ # Copyright Contributors to the Rez Project -import warnings +import rez.deprecations -warnings.warn( +rez.deprecations.warn( "module 'rez.vendor.version' is deprecated and will be removed in 3.0.0. Use 'rez.version' instead.", - DeprecationWarning, + rez.deprecations.RezDeprecationWarning, stacklevel=2 )