Skip to content

Commit

Permalink
[1.3.latest] Avoid packaging for semver (#10679) (#10685)
Browse files Browse the repository at this point in the history
* CT 2000 fix semver prerelease comparisons (#6838) (#6958)

* Modify semver.py to not use packaging.version.parse

* Changie

(cherry picked from commit d9424cc)



* Fix regression in semver comparison logic (#7040) (#7041)

(cherry picked from commit 915585c)



* Fix changed name of exception

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jeremy Cohen <jeremy@dbtlabs.com>
  • Loading branch information
3 people authored Sep 10, 2024
1 parent 35713d6 commit e0b9bee
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 11 deletions.
6 changes: 6 additions & 0 deletions .changes/unreleased/Fixes-20230201-154418.yaml
Original file line number Diff line number Diff line change
@@ -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"
6 changes: 6 additions & 0 deletions .changes/unreleased/Fixes-20230224-001338.yaml
Original file line number Diff line number Diff line change
@@ -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"
47 changes: 41 additions & 6 deletions core/dbt/semver.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
import re
from typing import List

from packaging import version as packaging_version

from dbt.exceptions import VersionsNotCompatibleException
import dbt.utils

Expand Down Expand Up @@ -66,6 +64,11 @@ class VersionSpecification(dbtClassMixin):
_VERSION_REGEX = re.compile(_VERSION_REGEX_PAT_STR, re.VERBOSE)


def _cmp(a, b):
"""Return negative if a<b, zero if a==b, positive if a>b."""
return (a > b) - (a < b)


@dataclass
class VersionSpecifier(VersionSpecification):
def to_version_string(self, skip_matcher=False):
Expand Down Expand Up @@ -145,10 +148,19 @@ def compare(self, other):
return 1
if b is None:
return -1
if packaging_version.parse(a) > packaging_version.parse(b):
return 1
elif packaging_version.parse(a) < packaging_version.parse(b):
return -1

# 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 int(a) < int(b):
return -1
# else is equal and will fall through

equal = ((self.matcher == Matchers.GREATER_THAN_OR_EQUAL and
other.matcher == Matchers.LESS_THAN_OR_EQUAL) or
Expand Down Expand Up @@ -205,6 +217,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:
Expand Down
2 changes: 1 addition & 1 deletion core/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
'mashumaro==2.9',
'minimal-snowplow-tracker==0.0.2',
'networkx>=2.3,<2.8.1',
'packaging>=20.9,<22.0',
'packaging>=20.9',
'sqlparse>=0.2.3,<0.5',
'dbt-extractor~=0.4.1',
'typing-extensions>=3.7.4,<3.11',
Expand Down
20 changes: 16 additions & 4 deletions test/unit/test_semver.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit e0b9bee

Please sign in to comment.