From b1e0190ef7c2ffd9bd83d3b249776290f9a2c7d5 Mon Sep 17 00:00:00 2001 From: ohmayr Date: Tue, 4 Aug 2026 17:24:37 +0000 Subject: [PATCH 1/7] feat: add _parse_version_to_tuple helper and improve pre-release version parsing --- .../%name_%version/%sub/__init__.py.j2 | 18 ++++++++----- .../asset/google/cloud/asset_v1/__init__.py | 16 +++++++----- .../google/iam/credentials_v1/__init__.py | 16 +++++++----- .../google/cloud/logging_v2/__init__.py | 16 +++++++----- .../google/cloud/logging_v2/__init__.py | 16 +++++++----- .../redis/google/cloud/redis_v1/__init__.py | 16 +++++++----- .../google/cloud/redis_v1/__init__.py | 16 +++++++----- .../storagebatchoperations_v1/__init__.py | 16 +++++++----- .../api_core/_python_package_support.py | 19 ++++++++------ .../tests/unit/test_python_package_support.py | 8 ++++++ packages/google-auth/google/auth/_helpers.py | 26 +++++++++++++++++++ packages/google-auth/tests/test__helpers.py | 8 ++++++ .../google/cloud/bigquery/_helpers.py | 26 +++++++++++++++++++ .../tests/unit/test__helpers.py | 10 +++++++ .../google/cloud/ndb/utils.py | 26 +++++++++++++++++++ .../google-cloud-ndb/tests/unit/test_utils.py | 8 ++++++ 16 files changed, 197 insertions(+), 64 deletions(-) diff --git a/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/__init__.py.j2 b/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/__init__.py.j2 index 21aa85db5b11..018a1a63a8d7 100644 --- a/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/__init__.py.j2 +++ b/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/__init__.py.j2 @@ -91,7 +91,7 @@ else: # pragma: NO COVER def parse_version_to_tuple(version_string: str): """Safely converts a semantic version string to a comparable tuple of integers. - Example: "6.33.5" -> (6, 33, 5) + Example: "6.33.5" -> (6, 33, 5), "1.83.1rc1" -> (1, 83, 1) Ignores non-numeric parts and handles common version formats. Args: version_string: Version string in the format "x.y.z" or "x.y.z" @@ -100,15 +100,19 @@ else: # pragma: NO COVER """ parts = [] for part in version_string.split("."): - try: - parts.append(int(part)) - except ValueError: - # If it's a non-numeric part (e.g., '1.0.0b1' -> 'b1'), stop here. - # This is a simplification compared to 'packaging.parse_version', but sufficient - # for comparing strictly numeric semantic versions. + digits = "" + for c in part: + if not c.isdigit(): + break + digits += c + if digits: + parts.append(int(digits)) + else: break return tuple(parts) + + def _get_version(dependency_name): try: version_string: str = metadata.version(dependency_name) diff --git a/packages/gapic-generator/tests/integration/goldens/asset/google/cloud/asset_v1/__init__.py b/packages/gapic-generator/tests/integration/goldens/asset/google/cloud/asset_v1/__init__.py index 299a062f0a1e..ed0af167e83e 100755 --- a/packages/gapic-generator/tests/integration/goldens/asset/google/cloud/asset_v1/__init__.py +++ b/packages/gapic-generator/tests/integration/goldens/asset/google/cloud/asset_v1/__init__.py @@ -142,7 +142,7 @@ def parse_version_to_tuple(version_string: str): """Safely converts a semantic version string to a comparable tuple of integers. - Example: "6.33.5" -> (6, 33, 5) + Example: "6.33.5" -> (6, 33, 5), "1.83.1rc1" -> (1, 83, 1) Ignores non-numeric parts and handles common version formats. Args: version_string: Version string in the format "x.y.z" or "x.y.z" @@ -151,12 +151,14 @@ def parse_version_to_tuple(version_string: str): """ parts = [] for part in version_string.split("."): - try: - parts.append(int(part)) - except ValueError: - # If it's a non-numeric part (e.g., '1.0.0b1' -> 'b1'), stop here. - # This is a simplification compared to 'packaging.parse_version', but sufficient - # for comparing strictly numeric semantic versions. + digits = "" + for c in part: + if not c.isdigit(): + break + digits += c + if digits: + parts.append(int(digits)) + else: break return tuple(parts) diff --git a/packages/gapic-generator/tests/integration/goldens/credentials/google/iam/credentials_v1/__init__.py b/packages/gapic-generator/tests/integration/goldens/credentials/google/iam/credentials_v1/__init__.py index a29db9042c73..7902209b9b28 100755 --- a/packages/gapic-generator/tests/integration/goldens/credentials/google/iam/credentials_v1/__init__.py +++ b/packages/gapic-generator/tests/integration/goldens/credentials/google/iam/credentials_v1/__init__.py @@ -68,7 +68,7 @@ def parse_version_to_tuple(version_string: str): """Safely converts a semantic version string to a comparable tuple of integers. - Example: "6.33.5" -> (6, 33, 5) + Example: "6.33.5" -> (6, 33, 5), "1.83.1rc1" -> (1, 83, 1) Ignores non-numeric parts and handles common version formats. Args: version_string: Version string in the format "x.y.z" or "x.y.z" @@ -77,12 +77,14 @@ def parse_version_to_tuple(version_string: str): """ parts = [] for part in version_string.split("."): - try: - parts.append(int(part)) - except ValueError: - # If it's a non-numeric part (e.g., '1.0.0b1' -> 'b1'), stop here. - # This is a simplification compared to 'packaging.parse_version', but sufficient - # for comparing strictly numeric semantic versions. + digits = "" + for c in part: + if not c.isdigit(): + break + digits += c + if digits: + parts.append(int(digits)) + else: break return tuple(parts) diff --git a/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/__init__.py b/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/__init__.py index 5753d5e9e9f5..8cfa8a7d6829 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/__init__.py +++ b/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/__init__.py @@ -144,7 +144,7 @@ def parse_version_to_tuple(version_string: str): """Safely converts a semantic version string to a comparable tuple of integers. - Example: "6.33.5" -> (6, 33, 5) + Example: "6.33.5" -> (6, 33, 5), "1.83.1rc1" -> (1, 83, 1) Ignores non-numeric parts and handles common version formats. Args: version_string: Version string in the format "x.y.z" or "x.y.z" @@ -153,12 +153,14 @@ def parse_version_to_tuple(version_string: str): """ parts = [] for part in version_string.split("."): - try: - parts.append(int(part)) - except ValueError: - # If it's a non-numeric part (e.g., '1.0.0b1' -> 'b1'), stop here. - # This is a simplification compared to 'packaging.parse_version', but sufficient - # for comparing strictly numeric semantic versions. + digits = "" + for c in part: + if not c.isdigit(): + break + digits += c + if digits: + parts.append(int(digits)) + else: break return tuple(parts) diff --git a/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/__init__.py b/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/__init__.py index a556a1fd0bcb..88262614d2e1 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/__init__.py +++ b/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/__init__.py @@ -144,7 +144,7 @@ def parse_version_to_tuple(version_string: str): """Safely converts a semantic version string to a comparable tuple of integers. - Example: "6.33.5" -> (6, 33, 5) + Example: "6.33.5" -> (6, 33, 5), "1.83.1rc1" -> (1, 83, 1) Ignores non-numeric parts and handles common version formats. Args: version_string: Version string in the format "x.y.z" or "x.y.z" @@ -153,12 +153,14 @@ def parse_version_to_tuple(version_string: str): """ parts = [] for part in version_string.split("."): - try: - parts.append(int(part)) - except ValueError: - # If it's a non-numeric part (e.g., '1.0.0b1' -> 'b1'), stop here. - # This is a simplification compared to 'packaging.parse_version', but sufficient - # for comparing strictly numeric semantic versions. + digits = "" + for c in part: + if not c.isdigit(): + break + digits += c + if digits: + parts.append(int(digits)) + else: break return tuple(parts) diff --git a/packages/gapic-generator/tests/integration/goldens/redis/google/cloud/redis_v1/__init__.py b/packages/gapic-generator/tests/integration/goldens/redis/google/cloud/redis_v1/__init__.py index c123b1faff66..d9af215fdb93 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis/google/cloud/redis_v1/__init__.py +++ b/packages/gapic-generator/tests/integration/goldens/redis/google/cloud/redis_v1/__init__.py @@ -86,7 +86,7 @@ def parse_version_to_tuple(version_string: str): """Safely converts a semantic version string to a comparable tuple of integers. - Example: "6.33.5" -> (6, 33, 5) + Example: "6.33.5" -> (6, 33, 5), "1.83.1rc1" -> (1, 83, 1) Ignores non-numeric parts and handles common version formats. Args: version_string: Version string in the format "x.y.z" or "x.y.z" @@ -95,12 +95,14 @@ def parse_version_to_tuple(version_string: str): """ parts = [] for part in version_string.split("."): - try: - parts.append(int(part)) - except ValueError: - # If it's a non-numeric part (e.g., '1.0.0b1' -> 'b1'), stop here. - # This is a simplification compared to 'packaging.parse_version', but sufficient - # for comparing strictly numeric semantic versions. + digits = "" + for c in part: + if not c.isdigit(): + break + digits += c + if digits: + parts.append(int(digits)) + else: break return tuple(parts) diff --git a/packages/gapic-generator/tests/integration/goldens/redis_selective/google/cloud/redis_v1/__init__.py b/packages/gapic-generator/tests/integration/goldens/redis_selective/google/cloud/redis_v1/__init__.py index c95170f12e4c..5f817a3bd0af 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis_selective/google/cloud/redis_v1/__init__.py +++ b/packages/gapic-generator/tests/integration/goldens/redis_selective/google/cloud/redis_v1/__init__.py @@ -79,7 +79,7 @@ def parse_version_to_tuple(version_string: str): """Safely converts a semantic version string to a comparable tuple of integers. - Example: "6.33.5" -> (6, 33, 5) + Example: "6.33.5" -> (6, 33, 5), "1.83.1rc1" -> (1, 83, 1) Ignores non-numeric parts and handles common version formats. Args: version_string: Version string in the format "x.y.z" or "x.y.z" @@ -88,12 +88,14 @@ def parse_version_to_tuple(version_string: str): """ parts = [] for part in version_string.split("."): - try: - parts.append(int(part)) - except ValueError: - # If it's a non-numeric part (e.g., '1.0.0b1' -> 'b1'), stop here. - # This is a simplification compared to 'packaging.parse_version', but sufficient - # for comparing strictly numeric semantic versions. + digits = "" + for c in part: + if not c.isdigit(): + break + digits += c + if digits: + parts.append(int(digits)) + else: break return tuple(parts) diff --git a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/google/cloud/storagebatchoperations_v1/__init__.py b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/google/cloud/storagebatchoperations_v1/__init__.py index 34e11b3de6b6..7a9a4c64a38b 100755 --- a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/google/cloud/storagebatchoperations_v1/__init__.py +++ b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/google/cloud/storagebatchoperations_v1/__init__.py @@ -88,7 +88,7 @@ def parse_version_to_tuple(version_string: str): """Safely converts a semantic version string to a comparable tuple of integers. - Example: "6.33.5" -> (6, 33, 5) + Example: "6.33.5" -> (6, 33, 5), "1.83.1rc1" -> (1, 83, 1) Ignores non-numeric parts and handles common version formats. Args: version_string: Version string in the format "x.y.z" or "x.y.z" @@ -97,12 +97,14 @@ def parse_version_to_tuple(version_string: str): """ parts = [] for part in version_string.split("."): - try: - parts.append(int(part)) - except ValueError: - # If it's a non-numeric part (e.g., '1.0.0b1' -> 'b1'), stop here. - # This is a simplification compared to 'packaging.parse_version', but sufficient - # for comparing strictly numeric semantic versions. + digits = "" + for c in part: + if not c.isdigit(): + break + digits += c + if digits: + parts.append(int(digits)) + else: break return tuple(parts) diff --git a/packages/google-api-core/google/api_core/_python_package_support.py b/packages/google-api-core/google/api_core/_python_package_support.py index a6c35d8c1804..09b9dc68b6b1 100644 --- a/packages/google-api-core/google/api_core/_python_package_support.py +++ b/packages/google-api-core/google/api_core/_python_package_support.py @@ -50,8 +50,8 @@ def parse_version_to_tuple(version_string: str) -> ParsedVersion: """Safely converts a semantic version string to a comparable tuple of integers. - Example: "6.33.5" -> (6, 33, 5) - Ignores non-numeric parts and handles common version formats. + Example: "6.33.5" -> (6, 33, 5), "1.83.1rc1" -> (1, 83, 1) + Parses leading digits of each component to correctly handle pre-releases. Args: version_string: Version string in the format "x.y.z" or "x.y.z" @@ -61,16 +61,19 @@ def parse_version_to_tuple(version_string: str) -> ParsedVersion: """ parts = [] for part in version_string.split("."): - try: - parts.append(int(part)) - except ValueError: - # If it's a non-numeric part (e.g., '1.0.0b1' -> 'b1'), stop here. - # This is a simplification compared to 'packaging.parse_version', but sufficient - # for comparing strictly numeric semantic versions. + digits = "" + for c in part: + if not c.isdigit(): + break + digits += c + if digits: + parts.append(int(digits)) + else: break return tuple(parts) + def get_dependency_version( dependency_name: str, ) -> DependencyVersion: diff --git a/packages/google-api-core/tests/unit/test_python_package_support.py b/packages/google-api-core/tests/unit/test_python_package_support.py index 42e8de673dea..84ddc91c0f51 100644 --- a/packages/google-api-core/tests/unit/test_python_package_support.py +++ b/packages/google-api-core/tests/unit/test_python_package_support.py @@ -45,6 +45,14 @@ def test_get_dependency_version(mocker, version_string_to_test): assert get_dependency_version("not-a-package") == DependencyVersion(None, "--") +def test_parse_version_to_tuple_prerelease(): + """Test parse_version_to_tuple with pre-release versions.""" + assert parse_version_to_tuple("1.83.1rc1") == (1, 83, 1) + assert parse_version_to_tuple("1.83.0dev0") == (1, 83, 0) + assert parse_version_to_tuple("6.33.5b2") == (6, 33, 5) + + + @patch("google.api_core._python_package_support._get_distribution_and_import_packages") @patch("google.api_core._python_package_support.get_dependency_version") def test_warn_deprecation_for_versions_less_than(mock_get_version, mock_get_packages): diff --git a/packages/google-auth/google/auth/_helpers.py b/packages/google-auth/google/auth/_helpers.py index 86c48c1e525c..d77b3bfe8993 100644 --- a/packages/google-auth/google/auth/_helpers.py +++ b/packages/google-auth/google/auth/_helpers.py @@ -534,3 +534,29 @@ def response_log(logger: logging.Logger, response: Any) -> None: if is_logging_enabled(logger): json_response = _parse_response(response) _response_log_base(logger, json_response) + + +def _parse_version_to_tuple(version_string): + """Safely converts a semantic version string to a comparable tuple of integers. + + Example: "6.33.5" -> (6, 33, 5), "1.83.1rc1" -> (1, 83, 1) + Parses leading digits of each component to correctly handle pre-releases. + + Args: + version_string: Version string in the format "x.y.z" or "x.y.z" + + Returns: + Tuple of integers for the parsed version string. + """ + parts = [] + for part in version_string.split("."): + digits = "" + for c in part: + if not c.isdigit(): + break + digits += c + if digits: + parts.append(int(digits)) + else: + break + return tuple(parts) diff --git a/packages/google-auth/tests/test__helpers.py b/packages/google-auth/tests/test__helpers.py index e2d8e7b20c03..092d6b4a8acc 100644 --- a/packages/google-auth/tests/test__helpers.py +++ b/packages/google-auth/tests/test__helpers.py @@ -697,3 +697,11 @@ def test_out_of_range(self): with pytest.raises((OverflowError, OSError, ValueError)): # Large enough to fail on most systems (Year 300,000+) _helpers.utcfromtimestamp(9999999999999) + + +def test_parse_version_to_tuple(): + assert _helpers._parse_version_to_tuple("1.83.0") == (1, 83, 0) + assert _helpers._parse_version_to_tuple("1.83.1rc1") == (1, 83, 1) + assert _helpers._parse_version_to_tuple("1.83.0dev0") == (1, 83, 0) + assert _helpers._parse_version_to_tuple("2.0") == (2, 0) + diff --git a/packages/google-cloud-bigquery/google/cloud/bigquery/_helpers.py b/packages/google-cloud-bigquery/google/cloud/bigquery/_helpers.py index a35fe1677a8f..db0d88a6006a 100644 --- a/packages/google-cloud-bigquery/google/cloud/bigquery/_helpers.py +++ b/packages/google-cloud-bigquery/google/cloud/bigquery/_helpers.py @@ -1106,3 +1106,29 @@ def _isinstance_or_raise( msg = f"Pass {value} as a '{dtype}'{or_none}. Got {type(value)}." raise TypeError(msg) + + +def _parse_version_to_tuple(version_string: str) -> Tuple[int, ...]: + """Safely converts a semantic version string to a comparable tuple of integers. + + Example: "6.33.5" -> (6, 33, 5), "1.83.1rc1" -> (1, 83, 1) + Parses leading digits of each component to correctly handle pre-releases. + + Args: + version_string: Version string in the format "x.y.z" or "x.y.z" + + Returns: + Tuple of integers for the parsed version string. + """ + parts = [] + for part in version_string.split("."): + digits = "" + for c in part: + if not c.isdigit(): + break + digits += c + if digits: + parts.append(int(digits)) + else: + break + return tuple(parts) diff --git a/packages/google-cloud-bigquery/tests/unit/test__helpers.py b/packages/google-cloud-bigquery/tests/unit/test__helpers.py index 4e53236e39e7..4fd4f28cede4 100644 --- a/packages/google-cloud-bigquery/tests/unit/test__helpers.py +++ b/packages/google-cloud-bigquery/tests/unit/test__helpers.py @@ -1214,3 +1214,13 @@ def test__valid_isinstance_or_raise(self, value, dtype, none_allowed, expected): def test__invalid_isinstance_or_raise(self, value, dtype, none_allowed, expected): with expected: _isinstance_or_raise(value, dtype, none_allowed=none_allowed) + + +def test__parse_version_to_tuple(): + from google.cloud.bigquery._helpers import _parse_version_to_tuple + + assert _parse_version_to_tuple("1.83.0") == (1, 83, 0) + assert _parse_version_to_tuple("1.83.1rc1") == (1, 83, 1) + assert _parse_version_to_tuple("1.83.0dev0") == (1, 83, 0) + assert _parse_version_to_tuple("2.0") == (2, 0) + diff --git a/packages/google-cloud-ndb/google/cloud/ndb/utils.py b/packages/google-cloud-ndb/google/cloud/ndb/utils.py index aecf861cd52c..b743a9333118 100644 --- a/packages/google-cloud-ndb/google/cloud/ndb/utils.py +++ b/packages/google-cloud-ndb/google/cloud/ndb/utils.py @@ -163,3 +163,29 @@ def tweak_logging(*args, **kwargs): def wrapping(*args, **kwargs): """Use functools.wraps instead""" raise NotImplementedError + + +def _parse_version_to_tuple(version_string): + """Safely converts a semantic version string to a comparable tuple of integers. + + Example: "6.33.5" -> (6, 33, 5), "1.83.1rc1" -> (1, 83, 1) + Parses leading digits of each component to correctly handle pre-releases. + + Args: + version_string: Version string in the format "x.y.z" or "x.y.z" + + Returns: + Tuple of integers for the parsed version string. + """ + parts = [] + for part in version_string.split("."): + digits = "" + for c in part: + if not c.isdigit(): + break + digits += c + if digits: + parts.append(int(digits)) + else: + break + return tuple(parts) diff --git a/packages/google-cloud-ndb/tests/unit/test_utils.py b/packages/google-cloud-ndb/tests/unit/test_utils.py index 571aa5ada0ed..43bfaf1698f3 100644 --- a/packages/google-cloud-ndb/tests/unit/test_utils.py +++ b/packages/google-cloud-ndb/tests/unit/test_utils.py @@ -133,3 +133,11 @@ def test_tweak_logging(): def test_wrapping(): with pytest.raises(NotImplementedError): utils.wrapping() + + +def test__parse_version_to_tuple(): + assert utils._parse_version_to_tuple("1.83.0") == (1, 83, 0) + assert utils._parse_version_to_tuple("1.83.1rc1") == (1, 83, 1) + assert utils._parse_version_to_tuple("1.83.0dev0") == (1, 83, 0) + assert utils._parse_version_to_tuple("2.0") == (2, 0) + From 0eba651dae6d41abc6b98794569e77a0d97f0cbc Mon Sep 17 00:00:00 2001 From: ohmayr Date: Tue, 4 Aug 2026 17:28:26 +0000 Subject: [PATCH 2/7] fix lint --- packages/google-auth/tests/test__helpers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/google-auth/tests/test__helpers.py b/packages/google-auth/tests/test__helpers.py index 092d6b4a8acc..ad2de3eeca6e 100644 --- a/packages/google-auth/tests/test__helpers.py +++ b/packages/google-auth/tests/test__helpers.py @@ -704,4 +704,3 @@ def test_parse_version_to_tuple(): assert _helpers._parse_version_to_tuple("1.83.1rc1") == (1, 83, 1) assert _helpers._parse_version_to_tuple("1.83.0dev0") == (1, 83, 0) assert _helpers._parse_version_to_tuple("2.0") == (2, 0) - From 03b3cc9cec1d9abc27afa2cff9dd9b12fe962c6a Mon Sep 17 00:00:00 2001 From: ohmayr Date: Tue, 4 Aug 2026 17:32:30 +0000 Subject: [PATCH 3/7] fix lint --- packages/google-cloud-bigquery/tests/unit/test__helpers.py | 1 - packages/google-cloud-ndb/tests/unit/test_utils.py | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/google-cloud-bigquery/tests/unit/test__helpers.py b/packages/google-cloud-bigquery/tests/unit/test__helpers.py index 4fd4f28cede4..848afe1fafe8 100644 --- a/packages/google-cloud-bigquery/tests/unit/test__helpers.py +++ b/packages/google-cloud-bigquery/tests/unit/test__helpers.py @@ -1223,4 +1223,3 @@ def test__parse_version_to_tuple(): assert _parse_version_to_tuple("1.83.1rc1") == (1, 83, 1) assert _parse_version_to_tuple("1.83.0dev0") == (1, 83, 0) assert _parse_version_to_tuple("2.0") == (2, 0) - diff --git a/packages/google-cloud-ndb/tests/unit/test_utils.py b/packages/google-cloud-ndb/tests/unit/test_utils.py index 43bfaf1698f3..16ebe6ec7454 100644 --- a/packages/google-cloud-ndb/tests/unit/test_utils.py +++ b/packages/google-cloud-ndb/tests/unit/test_utils.py @@ -140,4 +140,3 @@ def test__parse_version_to_tuple(): assert utils._parse_version_to_tuple("1.83.1rc1") == (1, 83, 1) assert utils._parse_version_to_tuple("1.83.0dev0") == (1, 83, 0) assert utils._parse_version_to_tuple("2.0") == (2, 0) - From c01e4b3d2e5c5521b6c7d19dfad7149aedeed09f Mon Sep 17 00:00:00 2001 From: ohmayr Date: Tue, 4 Aug 2026 17:40:35 +0000 Subject: [PATCH 4/7] format --- .../google-api-core/google/api_core/_python_package_support.py | 1 - .../google-api-core/tests/unit/test_python_package_support.py | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/google-api-core/google/api_core/_python_package_support.py b/packages/google-api-core/google/api_core/_python_package_support.py index 09b9dc68b6b1..c574b1e392e3 100644 --- a/packages/google-api-core/google/api_core/_python_package_support.py +++ b/packages/google-api-core/google/api_core/_python_package_support.py @@ -73,7 +73,6 @@ def parse_version_to_tuple(version_string: str) -> ParsedVersion: return tuple(parts) - def get_dependency_version( dependency_name: str, ) -> DependencyVersion: diff --git a/packages/google-api-core/tests/unit/test_python_package_support.py b/packages/google-api-core/tests/unit/test_python_package_support.py index 84ddc91c0f51..b275ad8867ec 100644 --- a/packages/google-api-core/tests/unit/test_python_package_support.py +++ b/packages/google-api-core/tests/unit/test_python_package_support.py @@ -52,7 +52,6 @@ def test_parse_version_to_tuple_prerelease(): assert parse_version_to_tuple("6.33.5b2") == (6, 33, 5) - @patch("google.api_core._python_package_support._get_distribution_and_import_packages") @patch("google.api_core._python_package_support.get_dependency_version") def test_warn_deprecation_for_versions_less_than(mock_get_version, mock_get_packages): From cc9e229f775ea42dd5052fcb8d36a14631a92068 Mon Sep 17 00:00:00 2001 From: ohmayr Date: Tue, 4 Aug 2026 18:06:12 +0000 Subject: [PATCH 5/7] add coverage --- .../google-api-core/tests/unit/test_python_package_support.py | 3 +++ packages/google-auth/tests/test__helpers.py | 3 +++ packages/google-cloud-bigquery/tests/unit/test__helpers.py | 3 +++ packages/google-cloud-ndb/tests/unit/test_utils.py | 3 +++ 4 files changed, 12 insertions(+) diff --git a/packages/google-api-core/tests/unit/test_python_package_support.py b/packages/google-api-core/tests/unit/test_python_package_support.py index b275ad8867ec..a1bbf0f51f0a 100644 --- a/packages/google-api-core/tests/unit/test_python_package_support.py +++ b/packages/google-api-core/tests/unit/test_python_package_support.py @@ -50,6 +50,9 @@ def test_parse_version_to_tuple_prerelease(): assert parse_version_to_tuple("1.83.1rc1") == (1, 83, 1) assert parse_version_to_tuple("1.83.0dev0") == (1, 83, 0) assert parse_version_to_tuple("6.33.5b2") == (6, 33, 5) + assert parse_version_to_tuple("1.83.0.dev0") == (1, 83, 0) + assert parse_version_to_tuple("1.83.dev0") == (1, 83) + assert parse_version_to_tuple("dev0") == () @patch("google.api_core._python_package_support._get_distribution_and_import_packages") diff --git a/packages/google-auth/tests/test__helpers.py b/packages/google-auth/tests/test__helpers.py index ad2de3eeca6e..34b8e72ac91b 100644 --- a/packages/google-auth/tests/test__helpers.py +++ b/packages/google-auth/tests/test__helpers.py @@ -704,3 +704,6 @@ def test_parse_version_to_tuple(): assert _helpers._parse_version_to_tuple("1.83.1rc1") == (1, 83, 1) assert _helpers._parse_version_to_tuple("1.83.0dev0") == (1, 83, 0) assert _helpers._parse_version_to_tuple("2.0") == (2, 0) + assert _helpers._parse_version_to_tuple("1.83.0.dev0") == (1, 83, 0) + assert _helpers._parse_version_to_tuple("1.83.dev0") == (1, 83) + assert _helpers._parse_version_to_tuple("dev0") == () diff --git a/packages/google-cloud-bigquery/tests/unit/test__helpers.py b/packages/google-cloud-bigquery/tests/unit/test__helpers.py index 848afe1fafe8..106d1bacdf2e 100644 --- a/packages/google-cloud-bigquery/tests/unit/test__helpers.py +++ b/packages/google-cloud-bigquery/tests/unit/test__helpers.py @@ -1223,3 +1223,6 @@ def test__parse_version_to_tuple(): assert _parse_version_to_tuple("1.83.1rc1") == (1, 83, 1) assert _parse_version_to_tuple("1.83.0dev0") == (1, 83, 0) assert _parse_version_to_tuple("2.0") == (2, 0) + assert _parse_version_to_tuple("1.83.0.dev0") == (1, 83, 0) + assert _parse_version_to_tuple("1.83.dev0") == (1, 83) + assert _parse_version_to_tuple("dev0") == () diff --git a/packages/google-cloud-ndb/tests/unit/test_utils.py b/packages/google-cloud-ndb/tests/unit/test_utils.py index 16ebe6ec7454..737f886ab996 100644 --- a/packages/google-cloud-ndb/tests/unit/test_utils.py +++ b/packages/google-cloud-ndb/tests/unit/test_utils.py @@ -140,3 +140,6 @@ def test__parse_version_to_tuple(): assert utils._parse_version_to_tuple("1.83.1rc1") == (1, 83, 1) assert utils._parse_version_to_tuple("1.83.0dev0") == (1, 83, 0) assert utils._parse_version_to_tuple("2.0") == (2, 0) + assert utils._parse_version_to_tuple("1.83.0.dev0") == (1, 83, 0) + assert utils._parse_version_to_tuple("1.83.dev0") == (1, 83) + assert utils._parse_version_to_tuple("dev0") == () From bd6b3dd6619f934f10e549fb1a9c2f71b401b417 Mon Sep 17 00:00:00 2001 From: ohmayr Date: Tue, 4 Aug 2026 18:38:13 +0000 Subject: [PATCH 6/7] update eventarc --- .../google/cloud/eventarc_v1/__init__.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/gapic-generator/tests/integration/goldens/eventarc/google/cloud/eventarc_v1/__init__.py b/packages/gapic-generator/tests/integration/goldens/eventarc/google/cloud/eventarc_v1/__init__.py index daf40c704795..33065d875922 100755 --- a/packages/gapic-generator/tests/integration/goldens/eventarc/google/cloud/eventarc_v1/__init__.py +++ b/packages/gapic-generator/tests/integration/goldens/eventarc/google/cloud/eventarc_v1/__init__.py @@ -140,7 +140,7 @@ def parse_version_to_tuple(version_string: str): """Safely converts a semantic version string to a comparable tuple of integers. - Example: "6.33.5" -> (6, 33, 5) + Example: "6.33.5" -> (6, 33, 5), "1.83.1rc1" -> (1, 83, 1) Ignores non-numeric parts and handles common version formats. Args: version_string: Version string in the format "x.y.z" or "x.y.z" @@ -149,12 +149,14 @@ def parse_version_to_tuple(version_string: str): """ parts = [] for part in version_string.split("."): - try: - parts.append(int(part)) - except ValueError: - # If it's a non-numeric part (e.g., '1.0.0b1' -> 'b1'), stop here. - # This is a simplification compared to 'packaging.parse_version', but sufficient - # for comparing strictly numeric semantic versions. + digits = "" + for c in part: + if not c.isdigit(): + break + digits += c + if digits: + parts.append(int(digits)) + else: break return tuple(parts) From 103597c581831b09815174fb934d5895ec7cebd6 Mon Sep 17 00:00:00 2001 From: ohmayr Date: Tue, 4 Aug 2026 20:08:33 +0000 Subject: [PATCH 7/7] address feedback --- .../google/cloud/bigquery/_helpers.py | 26 ----------------- .../cloud/bigquery/_versions_helpers.py | 28 ++++++++++++++++++- .../tests/unit/test__helpers.py | 12 -------- .../tests/unit/test__versions_helpers.py | 13 +++++++++ 4 files changed, 40 insertions(+), 39 deletions(-) diff --git a/packages/google-cloud-bigquery/google/cloud/bigquery/_helpers.py b/packages/google-cloud-bigquery/google/cloud/bigquery/_helpers.py index db0d88a6006a..a35fe1677a8f 100644 --- a/packages/google-cloud-bigquery/google/cloud/bigquery/_helpers.py +++ b/packages/google-cloud-bigquery/google/cloud/bigquery/_helpers.py @@ -1106,29 +1106,3 @@ def _isinstance_or_raise( msg = f"Pass {value} as a '{dtype}'{or_none}. Got {type(value)}." raise TypeError(msg) - - -def _parse_version_to_tuple(version_string: str) -> Tuple[int, ...]: - """Safely converts a semantic version string to a comparable tuple of integers. - - Example: "6.33.5" -> (6, 33, 5), "1.83.1rc1" -> (1, 83, 1) - Parses leading digits of each component to correctly handle pre-releases. - - Args: - version_string: Version string in the format "x.y.z" or "x.y.z" - - Returns: - Tuple of integers for the parsed version string. - """ - parts = [] - for part in version_string.split("."): - digits = "" - for c in part: - if not c.isdigit(): - break - digits += c - if digits: - parts.append(int(digits)) - else: - break - return tuple(parts) diff --git a/packages/google-cloud-bigquery/google/cloud/bigquery/_versions_helpers.py b/packages/google-cloud-bigquery/google/cloud/bigquery/_versions_helpers.py index d856c19852e7..80ce8bce7572 100644 --- a/packages/google-cloud-bigquery/google/cloud/bigquery/_versions_helpers.py +++ b/packages/google-cloud-bigquery/google/cloud/bigquery/_versions_helpers.py @@ -13,7 +13,7 @@ # limitations under the License. """Shared helper functions for verifying versions of installed modules.""" -from typing import Any +from typing import Any, Tuple import packaging.version @@ -247,3 +247,29 @@ def try_import(self, raise_if_error: bool = False) -> Any: and PYARROW_VERSIONS.try_import() is not None and PYARROW_VERSIONS.installed_version >= _MIN_PYARROW_VERSION_RANGE ) + + +def _parse_version_to_tuple(version_string: str) -> Tuple[int, ...]: + """Safely converts a semantic version string to a comparable tuple of integers. + + Example: "6.33.5" -> (6, 33, 5), "1.83.1rc1" -> (1, 83, 1) + Parses leading digits of each component to correctly handle pre-releases. + + Args: + version_string: Version string in the format "x.y.z" or "x.y.z" + + Returns: + Tuple of integers for the parsed version string. + """ + parts = [] + for part in version_string.split("."): + digits = "" + for c in part: + if not c.isdigit(): + break + digits += c + if digits: + parts.append(int(digits)) + if not digits or digits != part: + break + return tuple(parts) diff --git a/packages/google-cloud-bigquery/tests/unit/test__helpers.py b/packages/google-cloud-bigquery/tests/unit/test__helpers.py index 106d1bacdf2e..4e53236e39e7 100644 --- a/packages/google-cloud-bigquery/tests/unit/test__helpers.py +++ b/packages/google-cloud-bigquery/tests/unit/test__helpers.py @@ -1214,15 +1214,3 @@ def test__valid_isinstance_or_raise(self, value, dtype, none_allowed, expected): def test__invalid_isinstance_or_raise(self, value, dtype, none_allowed, expected): with expected: _isinstance_or_raise(value, dtype, none_allowed=none_allowed) - - -def test__parse_version_to_tuple(): - from google.cloud.bigquery._helpers import _parse_version_to_tuple - - assert _parse_version_to_tuple("1.83.0") == (1, 83, 0) - assert _parse_version_to_tuple("1.83.1rc1") == (1, 83, 1) - assert _parse_version_to_tuple("1.83.0dev0") == (1, 83, 0) - assert _parse_version_to_tuple("2.0") == (2, 0) - assert _parse_version_to_tuple("1.83.0.dev0") == (1, 83, 0) - assert _parse_version_to_tuple("1.83.dev0") == (1, 83) - assert _parse_version_to_tuple("dev0") == () diff --git a/packages/google-cloud-bigquery/tests/unit/test__versions_helpers.py b/packages/google-cloud-bigquery/tests/unit/test__versions_helpers.py index 8379c87c18e0..3be503d20b0e 100644 --- a/packages/google-cloud-bigquery/tests/unit/test__versions_helpers.py +++ b/packages/google-cloud-bigquery/tests/unit/test__versions_helpers.py @@ -246,3 +246,16 @@ def test_installed_pandas_version_returns_parsed_version(): assert version.major == 1 assert version.minor == 1 assert version.micro == 0 + + +def test__parse_version_to_tuple(): + from google.cloud.bigquery._versions_helpers import _parse_version_to_tuple + + assert _parse_version_to_tuple("1.83.0") == (1, 83, 0) + assert _parse_version_to_tuple("1.83.1rc1") == (1, 83, 1) + assert _parse_version_to_tuple("1.83.0dev0") == (1, 83, 0) + assert _parse_version_to_tuple("2.0") == (2, 0) + assert _parse_version_to_tuple("1.83.0.dev0") == (1, 83, 0) + assert _parse_version_to_tuple("1.83.dev0") == (1, 83) + assert _parse_version_to_tuple("dev0") == () + assert _parse_version_to_tuple("1.83.1rc1.post2") == (1, 83, 1)