From 680a37105d4dd3c5ac138eb558869d92be2b9114 Mon Sep 17 00:00:00 2001 From: couzhei Date: Wed, 14 Aug 2024 15:35:02 +0330 Subject: [PATCH 1/7] - This will make sure that the version unpacking doesn't stop connection to some versions of message brokers. --- kombu/utils/text.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kombu/utils/text.py b/kombu/utils/text.py index a6558cfc7..bed715d42 100644 --- a/kombu/utils/text.py +++ b/kombu/utils/text.py @@ -6,7 +6,7 @@ from difflib import SequenceMatcher from typing import Iterable, Iterator - +from typing import Tuple from kombu import version_info_t @@ -59,7 +59,8 @@ def _unpack_version( minor: str | int = 0, micro: str | int = 0, releaselevel: str = '', - serial: str = '' + serial: str = '', + *args: Tuple[str] ) -> version_info_t: return version_info_t(int(major), int(minor), micro, releaselevel, serial) From b8cf3ab6c566bc61da06943a5e2c0d56b51cdaa1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 14 Aug 2024 12:15:48 +0000 Subject: [PATCH 2/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- kombu/utils/text.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kombu/utils/text.py b/kombu/utils/text.py index bed715d42..551b82d3f 100644 --- a/kombu/utils/text.py +++ b/kombu/utils/text.py @@ -5,8 +5,8 @@ from __future__ import annotations from difflib import SequenceMatcher -from typing import Iterable, Iterator -from typing import Tuple +from typing import Iterable, Iterator, Tuple + from kombu import version_info_t From 62355ce094d516bc605e896922ab52e2e992688c Mon Sep 17 00:00:00 2001 From: couzhei Date: Mon, 19 Aug 2024 12:16:12 +0330 Subject: [PATCH 3/7] - I updated the test in this version - Improved my code --- kombu/utils/text.py | 41 +++++++++++++++++++++++++++----------- t/unit/utils/test_utils.py | 22 +++++++++++++------- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/kombu/utils/text.py b/kombu/utils/text.py index bed715d42..7e45df75c 100644 --- a/kombu/utils/text.py +++ b/kombu/utils/text.py @@ -4,9 +4,10 @@ from __future__ import annotations +import re from difflib import SequenceMatcher from typing import Iterable, Iterator -from typing import Tuple + from kombu import version_info_t @@ -42,16 +43,33 @@ def fmatch_best(needle: str, haystack: Iterable[str], min_ratio: float = 0.6) -> return None -def version_string_as_tuple(s: str) -> version_info_t: - """Convert version string to version info tuple.""" - v = _unpack_version(*s.split('.')) - # X.Y.3a1 -> (X, Y, 3, 'a1') - if isinstance(v.micro, str): - v = version_info_t(v.major, v.minor, *_splitmicro(*v[2:])) - # X.Y.3a1-40 -> (X, Y, 3, 'a1', '40') - if not v.serial and v.releaselevel and '-' in v.releaselevel: - v = version_info_t(*list(v[0:3]) + v.releaselevel.split('-')) - return v +def version_string_as_tuple(version: str) -> version_info_t: + """ + This is a function for parsing the version into + meaningful comment. + """ + + # regex pattern to match the different parts of the version string + pattern = r"^(\d+)" # catching the major version (mandatory) + pattern += r"(?:\.(\d+))?" # optionally catching the minor version + pattern += r"(?:\.(\d+))?" # optionally catching the micro version + pattern += r"(?:\.*([a-zA-Z+-][\da-zA-Z+-]*))?" # optionally catching the release level (starting with a letter, + or -) after a dot + pattern += r"(?:\.(.*))?" # optionally catching the serial number after a dot + + # applying the regex pattern to the input version string + match = re.match(pattern, version) + + if not match: + raise ValueError(f"Invalid version string: {version}") + + # extracting the matched groups + major = int(match.group(1)) + minor = int(match.group(2)) if match.group(2) else 0 + micro = int(match.group(3)) if match.group(3) else 0 + releaselevel = match.group(4) if match.group(4) else "" + serial = match.group(5) if match.group(5) else "" + + return _unpack_version(major, minor, micro, releaselevel, serial) def _unpack_version( @@ -60,7 +78,6 @@ def _unpack_version( micro: str | int = 0, releaselevel: str = '', serial: str = '', - *args: Tuple[str] ) -> version_info_t: return version_info_t(int(major), int(minor), micro, releaselevel, serial) diff --git a/t/unit/utils/test_utils.py b/t/unit/utils/test_utils.py index 08f950836..0e212029c 100644 --- a/t/unit/utils/test_utils.py +++ b/t/unit/utils/test_utils.py @@ -8,15 +8,23 @@ def test_dir(): import kombu + assert dir(kombu) -@pytest.mark.parametrize('version,expected', [ - ('3', version_info_t(3, 0, 0, '', '')), - ('3.3', version_info_t(3, 3, 0, '', '')), - ('3.3.1', version_info_t(3, 3, 1, '', '')), - ('3.3.1a3', version_info_t(3, 3, 1, 'a3', '')), - ('3.3.1.a3.40c32', version_info_t(3, 3, 1, 'a3', '40c32')), -]) +@pytest.mark.parametrize( + "version,expected", + [ + ("3", version_info_t(3, 0, 0, "", "")), + ("3.3", version_info_t(3, 3, 0, "", "")), + ("3.3.1", version_info_t(3, 3, 1, "", "")), + ("3.3.1a3", version_info_t(3, 3, 1, "a3", "")), + ("3.3.1.a3.40c32", version_info_t(3, 3, 1, "a3", "40c32")), + ("4.0.0+beta.3.47.g4f1a05b", version_info_t(4, 0, 0, "+beta", "3.47.g4f1a05b")), + ("4.0.0-beta3.47.g4f1a05b", version_info_t(4, 0, 0, "-beta3", "47.g4f1a05b")), + ("4.0.1-alpha.3+40c32", version_info_t(4, 0, 1, "-alpha", "3+40c32")), + ("0+beta3.14159265", version_info_t(0, 0, 0, "+beta3", "14159265")), + ], +) def test_version_string_as_tuple(version, expected): assert version_string_as_tuple(version) == expected From 8e9d62746da10d4d7478a14ccfdbf6e590e15aad Mon Sep 17 00:00:00 2001 From: couzhei Date: Mon, 19 Aug 2024 12:24:35 +0330 Subject: [PATCH 4/7] - Removed `merge-conflict` comments in the code! --- kombu/utils/text.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/kombu/utils/text.py b/kombu/utils/text.py index 86abd353d..7e45df75c 100644 --- a/kombu/utils/text.py +++ b/kombu/utils/text.py @@ -6,11 +6,7 @@ import re from difflib import SequenceMatcher -<<<<<<< HEAD from typing import Iterable, Iterator -======= -from typing import Iterable, Iterator, Tuple ->>>>>>> b8cf3ab6c566bc61da06943a5e2c0d56b51cdaa1 from kombu import version_info_t From 26cac4a0c5c57be90bc9f1b0ffd68559e125dabb Mon Sep 17 00:00:00 2001 From: couzhei Date: Mon, 19 Aug 2024 12:30:46 +0330 Subject: [PATCH 5/7] - linting problem resolved. --- t/unit/utils/test_utils.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/t/unit/utils/test_utils.py b/t/unit/utils/test_utils.py index 0e212029c..aa1b9085c 100644 --- a/t/unit/utils/test_utils.py +++ b/t/unit/utils/test_utils.py @@ -20,8 +20,10 @@ def test_dir(): ("3.3.1", version_info_t(3, 3, 1, "", "")), ("3.3.1a3", version_info_t(3, 3, 1, "a3", "")), ("3.3.1.a3.40c32", version_info_t(3, 3, 1, "a3", "40c32")), - ("4.0.0+beta.3.47.g4f1a05b", version_info_t(4, 0, 0, "+beta", "3.47.g4f1a05b")), - ("4.0.0-beta3.47.g4f1a05b", version_info_t(4, 0, 0, "-beta3", "47.g4f1a05b")), + ("4.0.0+beta.3.47.g4f1a05b", version_info_t( + 4, 0, 0, "+beta", "3.47.g4f1a05b")), + ("4.0.0-beta3.47.g4f1a05b", version_info_t( + 4, 0, 0, "-beta3", "47.g4f1a05b")), ("4.0.1-alpha.3+40c32", version_info_t(4, 0, 1, "-alpha", "3+40c32")), ("0+beta3.14159265", version_info_t(0, 0, 0, "+beta3", "14159265")), ], From bf354000985ed6b209015b2afa92b777ca97155d Mon Sep 17 00:00:00 2001 From: couzhei Date: Wed, 21 Aug 2024 09:55:47 +0330 Subject: [PATCH 6/7] - Docstrings are now in accordance with `pydocstyle`. --- kombu/utils/text.py | 56 ++++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/kombu/utils/text.py b/kombu/utils/text.py index 7e45df75c..d86fc4cb6 100644 --- a/kombu/utils/text.py +++ b/kombu/utils/text.py @@ -1,4 +1,5 @@ """Text Utilities.""" + # flake8: noqa @@ -11,16 +12,19 @@ from kombu import version_info_t -def escape_regex(p, white=''): +def escape_regex(p, white=""): # type: (str, str) -> str """Escape string for use within a regular expression.""" # what's up with re.escape? that code must be neglected or something - return ''.join(c if c.isalnum() or c in white - else ('\\000' if c == '\000' else '\\' + c) - for c in p) + return "".join( + c if c.isalnum() or c in white else ("\\000" if c == "\000" else "\\" + c) + for c in p + ) -def fmatch_iter(needle: str, haystack: Iterable[str], min_ratio: float = 0.6) -> Iterator[tuple[float, str]]: +def fmatch_iter( + needle: str, haystack: Iterable[str], min_ratio: float = 0.6 +) -> Iterator[tuple[float, str]]: """Fuzzy match: iteratively. Yields @@ -33,23 +37,41 @@ def fmatch_iter(needle: str, haystack: Iterable[str], min_ratio: float = 0.6) -> yield ratio, key -def fmatch_best(needle: str, haystack: Iterable[str], min_ratio: float = 0.6) -> str | None: +def fmatch_best( + needle: str, haystack: Iterable[str], min_ratio: float = 0.6 +) -> str | None: """Fuzzy match - Find best match (scalar).""" try: return sorted( - fmatch_iter(needle, haystack, min_ratio), reverse=True, - )[0][1] + fmatch_iter(needle, haystack, min_ratio), + reverse=True, + )[ + 0 + ][1] except IndexError: return None def version_string_as_tuple(version: str) -> version_info_t: - """ - This is a function for parsing the version into - meaningful comment. - """ + """Parse a version string into its components and return a version_info_t tuple. + + The version string is expected to follow the pattern: + 'major.minor.micro[releaselevel][serial]'. Each component of the version + is extracted and returned as a tuple in the format (major, minor, micro, + releaselevel, serial). - # regex pattern to match the different parts of the version string + Args + ---- + version (str): The version string to parse. + + Returns + ------- + version_info_t: A tuple containing the parsed version components. + + Raises + ------ + ValueError: If the version string is invalid and does not match the expected pattern. + """ pattern = r"^(\d+)" # catching the major version (mandatory) pattern += r"(?:\.(\d+))?" # optionally catching the minor version pattern += r"(?:\.(\d+))?" # optionally catching the micro version @@ -76,13 +98,15 @@ def _unpack_version( major: str, minor: str | int = 0, micro: str | int = 0, - releaselevel: str = '', - serial: str = '', + releaselevel: str = "", + serial: str = "", ) -> version_info_t: return version_info_t(int(major), int(minor), micro, releaselevel, serial) -def _splitmicro(micro: str, releaselevel: str = '', serial: str = '') -> tuple[int, str, str]: +def _splitmicro( + micro: str, releaselevel: str = "", serial: str = "" +) -> tuple[int, str, str]: for index, char in enumerate(micro): if not char.isdigit(): break From c044dbe37e224aa72bd486b50c61ffb66b0ea446 Mon Sep 17 00:00:00 2001 From: couzhei Date: Wed, 21 Aug 2024 10:31:13 +0330 Subject: [PATCH 7/7] - resolving `"_unpack_version" has incompatible type "int"` problem in `_unpack_version` method - `"` are sent back to `'` (apparently my company's formatter `black` is not compatible with `pydocstyle`, and mine integration with VSCode has messed with kombu's repository) --- kombu/utils/text.py | 30 +++++++++++++++--------------- t/unit/utils/test_utils.py | 24 ++++++++++++------------ 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/kombu/utils/text.py b/kombu/utils/text.py index d86fc4cb6..fd359f8bd 100644 --- a/kombu/utils/text.py +++ b/kombu/utils/text.py @@ -12,12 +12,12 @@ from kombu import version_info_t -def escape_regex(p, white=""): +def escape_regex(p, white=''): # type: (str, str) -> str """Escape string for use within a regular expression.""" # what's up with re.escape? that code must be neglected or something - return "".join( - c if c.isalnum() or c in white else ("\\000" if c == "\000" else "\\" + c) + return ''.join( + c if c.isalnum() or c in white else ('\\000' if c == '\000' else '\\' + c) for c in p ) @@ -72,11 +72,11 @@ def version_string_as_tuple(version: str) -> version_info_t: ------ ValueError: If the version string is invalid and does not match the expected pattern. """ - pattern = r"^(\d+)" # catching the major version (mandatory) - pattern += r"(?:\.(\d+))?" # optionally catching the minor version - pattern += r"(?:\.(\d+))?" # optionally catching the micro version - pattern += r"(?:\.*([a-zA-Z+-][\da-zA-Z+-]*))?" # optionally catching the release level (starting with a letter, + or -) after a dot - pattern += r"(?:\.(.*))?" # optionally catching the serial number after a dot + pattern = r'^(\d+)' # catching the major version (mandatory) + pattern += r'(?:\.(\d+))?' # optionally catching the minor version + pattern += r'(?:\.(\d+))?' # optionally catching the micro version + pattern += r'(?:\.*([a-zA-Z+-][\da-zA-Z+-]*))?' # optionally catching the release level (starting with a letter, + or -) after a dot + pattern += r'(?:\.(.*))?' # optionally catching the serial number after a dot # applying the regex pattern to the input version string match = re.match(pattern, version) @@ -88,24 +88,24 @@ def version_string_as_tuple(version: str) -> version_info_t: major = int(match.group(1)) minor = int(match.group(2)) if match.group(2) else 0 micro = int(match.group(3)) if match.group(3) else 0 - releaselevel = match.group(4) if match.group(4) else "" - serial = match.group(5) if match.group(5) else "" + releaselevel = match.group(4) if match.group(4) else '' + serial = match.group(5) if match.group(5) else '' return _unpack_version(major, minor, micro, releaselevel, serial) def _unpack_version( - major: str, + major: str | int = 0, minor: str | int = 0, micro: str | int = 0, - releaselevel: str = "", - serial: str = "", + releaselevel: str = '', + serial: str = '', ) -> version_info_t: - return version_info_t(int(major), int(minor), micro, releaselevel, serial) + return version_info_t(int(major), int(minor), int(micro), releaselevel, serial) def _splitmicro( - micro: str, releaselevel: str = "", serial: str = "" + micro: str, releaselevel: str = '', serial: str = '' ) -> tuple[int, str, str]: for index, char in enumerate(micro): if not char.isdigit(): diff --git a/t/unit/utils/test_utils.py b/t/unit/utils/test_utils.py index aa1b9085c..051928768 100644 --- a/t/unit/utils/test_utils.py +++ b/t/unit/utils/test_utils.py @@ -13,19 +13,19 @@ def test_dir(): @pytest.mark.parametrize( - "version,expected", + 'version,expected', [ - ("3", version_info_t(3, 0, 0, "", "")), - ("3.3", version_info_t(3, 3, 0, "", "")), - ("3.3.1", version_info_t(3, 3, 1, "", "")), - ("3.3.1a3", version_info_t(3, 3, 1, "a3", "")), - ("3.3.1.a3.40c32", version_info_t(3, 3, 1, "a3", "40c32")), - ("4.0.0+beta.3.47.g4f1a05b", version_info_t( - 4, 0, 0, "+beta", "3.47.g4f1a05b")), - ("4.0.0-beta3.47.g4f1a05b", version_info_t( - 4, 0, 0, "-beta3", "47.g4f1a05b")), - ("4.0.1-alpha.3+40c32", version_info_t(4, 0, 1, "-alpha", "3+40c32")), - ("0+beta3.14159265", version_info_t(0, 0, 0, "+beta3", "14159265")), + ('3', version_info_t(3, 0, 0, '', '')), + ('3.3', version_info_t(3, 3, 0, '', '')), + ('3.3.1', version_info_t(3, 3, 1, '', '')), + ('3.3.1a3', version_info_t(3, 3, 1, 'a3', '')), + ('3.3.1.a3.40c32', version_info_t(3, 3, 1, 'a3', '40c32')), + ('4.0.0+beta.3.47.g4f1a05b', version_info_t( + 4, 0, 0, '+beta', '3.47.g4f1a05b')), + ('4.0.0-beta3.47.g4f1a05b', version_info_t( + 4, 0, 0, '-beta3', '47.g4f1a05b')), + ('4.0.1-alpha.3+40c32', version_info_t(4, 0, 1, '-alpha', '3+40c32')), + ('0+beta3.14159265', version_info_t(0, 0, 0, '+beta3', '14159265')), ], ) def test_version_string_as_tuple(version, expected):