From 27406566ea222284ac9a88018e23d2a29d6d5cec Mon Sep 17 00:00:00 2001 From: Gerda Shank Date: Mon, 9 Sep 2024 17:12:35 -0400 Subject: [PATCH] [1.3.latest] Avoid packaging for semver (#10679) * CT 2000 fix semver prerelease comparisons (#6838) (#6958) * Modify semver.py to not use packaging.version.parse * Changie (cherry picked from commit d9424cc7100cb3fcf92155c7d4fb4f7e030f19fe) Co-authored-by: Gerda Shank * Fix regression in semver comparison logic (#7040) (#7041) (cherry picked from commit 915585c36e5798a8d81dbb74afde5a818b1c7803) Co-authored-by: Jeremy Cohen * Fix changed name of exception --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Jeremy Cohen --- .../unreleased/Fixes-20230201-154418.yaml | 6 +++ .../unreleased/Fixes-20230224-001338.yaml | 6 +++ core/dbt/semver.py | 47 +++++++++++++++---- core/setup.py | 2 +- test/unit/test_semver.py | 20 ++++++-- 5 files changed, 68 insertions(+), 13 deletions(-) create mode 100644 .changes/unreleased/Fixes-20230201-154418.yaml create mode 100644 .changes/unreleased/Fixes-20230224-001338.yaml diff --git a/.changes/unreleased/Fixes-20230201-154418.yaml b/.changes/unreleased/Fixes-20230201-154418.yaml new file mode 100644 index 00000000000..dc2099f94b1 --- /dev/null +++ b/.changes/unreleased/Fixes-20230201-154418.yaml @@ -0,0 +1,6 @@ +kind: Fixes +body: Remove pin on packaging and stop using it for prerelease comparisons +time: 2023-02-01T15:44:18.279158-05:00 +custom: + Author: gshank + Issue: "6834" diff --git a/.changes/unreleased/Fixes-20230224-001338.yaml b/.changes/unreleased/Fixes-20230224-001338.yaml new file mode 100644 index 00000000000..28f33bef515 --- /dev/null +++ b/.changes/unreleased/Fixes-20230224-001338.yaml @@ -0,0 +1,6 @@ +kind: Fixes +body: Fix semver comparison logic by ensuring numeric values +time: 2023-02-24T00:13:38.23242+01:00 +custom: + Author: jtcohen6 + Issue: "7039" diff --git a/core/dbt/semver.py b/core/dbt/semver.py index a98e18c3afe..63b474c5396 100644 --- a/core/dbt/semver.py +++ b/core/dbt/semver.py @@ -1,10 +1,7 @@ from dataclasses import dataclass import re -import warnings from typing import List -from packaging import version as packaging_version - from dbt.exceptions import VersionsNotCompatibleException import dbt.utils @@ -70,6 +67,11 @@ class VersionSpecification(dbtClassMixin): _VERSION_REGEX = re.compile(_VERSION_REGEX_PAT_STR, re.VERBOSE) +def _cmp(a, b): + """Return negative if ab.""" + return (a > b) - (a < b) + + @dataclass class VersionSpecifier(VersionSpecification): def to_version_string(self, skip_matcher=False): @@ -142,13 +144,19 @@ def compare(self, other): return 1 if b is None: return -1 - # This suppresses the LegacyVersion deprecation warning - with warnings.catch_warnings(): - warnings.simplefilter("ignore", category=DeprecationWarning) - if packaging_version.parse(a) > packaging_version.parse(b): + + # Check the prerelease component only + prcmp = self._nat_cmp(a, b) + if prcmp != 0: # either -1 or 1 + return prcmp + # else is equal and will fall through + + else: # major/minor/patch, should all be numbers + if int(a) > int(b): return 1 - elif packaging_version.parse(a) < packaging_version.parse(b): + elif int(a) < int(b): return -1 + # else is equal and will fall through equal = ( self.matcher == Matchers.GREATER_THAN_OR_EQUAL @@ -212,6 +220,29 @@ def is_upper_bound(self): def is_exact(self): return self.matcher == Matchers.EXACT + @classmethod + def _nat_cmp(cls, a, b): + def cmp_prerelease_tag(a, b): + if isinstance(a, int) and isinstance(b, int): + return _cmp(a, b) + elif isinstance(a, int): + return -1 + elif isinstance(b, int): + return 1 + else: + return _cmp(a, b) + + a, b = a or "", b or "" + a_parts, b_parts = a.split("."), b.split(".") + a_parts = [int(x) if re.match(r"^\d+$", x) else x for x in a_parts] + b_parts = [int(x) if re.match(r"^\d+$", x) else x for x in b_parts] + for sub_a, sub_b in zip(a_parts, b_parts): + cmp_result = cmp_prerelease_tag(sub_a, sub_b) + if cmp_result != 0: + return cmp_result + else: + return _cmp(len(a), len(b)) + @dataclass class VersionRange: diff --git a/core/setup.py b/core/setup.py index 728f4eb2e7c..2efc6b1ade5 100644 --- a/core/setup.py +++ b/core/setup.py @@ -62,7 +62,7 @@ "mashumaro==2.9", "minimal-snowplow-tracker==0.0.2", "networkx>=2.3,<2.8.4", - "packaging>=20.9,<22.0", + "packaging>20.9", "sqlparse>=0.2.3,<0.4.4", "dbt-extractor~=0.4.1", "typing-extensions>=3.7.4", diff --git a/test/unit/test_semver.py b/test/unit/test_semver.py index cb19e6fe1ff..601f285ca3a 100644 --- a/test/unit/test_semver.py +++ b/test/unit/test_semver.py @@ -173,13 +173,25 @@ def test__resolve_to_specific_version(self): ['1.0.0', '1.1.0a1', '1.1.0', '1.2.0a1', '1.2.0']), '1.1.0') + self.assertEqual( + resolve_to_specific_version( + # https://github.com/dbt-labs/dbt-core/issues/7039 + # 10 is greater than 9 + create_range('>0.9.0', '<0.10.0'), + ['0.9.0', '0.9.1', '0.10.0']), + '0.9.1') + def test__filter_installable(self): - assert filter_installable( + installable = filter_installable( ['1.1.0', '1.2.0a1', '1.0.0','2.1.0-alpha','2.2.0asdf','2.1.0','2.2.0','2.2.0-fishtown-beta','2.2.0-2'], install_prerelease=True - ) == ['1.0.0', '1.1.0', '1.2.0a1','2.1.0-alpha','2.1.0','2.2.0asdf','2.2.0-fishtown-beta','2.2.0-2','2.2.0'] + ) + expected = ['1.0.0', '1.1.0', '1.2.0a1','2.1.0-alpha','2.1.0','2.2.0-2','2.2.0asdf','2.2.0-fishtown-beta','2.2.0'] + assert installable == expected - assert filter_installable( + installable = filter_installable( ['1.1.0', '1.2.0a1', '1.0.0','2.1.0-alpha','2.2.0asdf','2.1.0','2.2.0','2.2.0-fishtown-beta'], install_prerelease=False - ) == ['1.0.0', '1.1.0','2.1.0','2.2.0'] + ) + expected = ['1.0.0', '1.1.0','2.1.0','2.2.0'] + assert installable == expected