feat(spanner): drop Python 3.7-3.9 support and regenerate (#17169) · googleapis/google-cloud-python@2408166 · GitHub
Skip to content

Commit 2408166

Browse files
authored
feat(spanner): drop Python 3.7-3.9 support and regenerate (#17169)
Updates post processing to account for dropping support for Python 3.7, 3.8, 3.9 and the impacts that has on using 3.10 for lower bounds testing. ### Changes * updates the lower bound versions for several libraries to avoid conflicts and install issues in both `setup.py` and `constraints-3.10.txt` * updates post-processing scripts to ensure the above updates persist
1 parent 819ce1b commit 2408166

33 files changed

Lines changed: 392 additions & 237 deletions

File tree

.librarian/generator-input/client-post-processing/spanner-integration.yaml

Lines changed: 68 additions & 10 deletions

librarian.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1906,7 +1906,6 @@ libraries:
19061906
- docs/spanner_v1/table.rst
19071907
- docs/spanner_v1/transaction.rst
19081908
- tests/unit/gapic/conftest.py
1909-
skip_generate: true
19101909
python:
19111910
library_type: GAPIC_COMBO
19121911
opt_args_by_api:

packages/google-cloud-spanner/.devcontainer/devcontainer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"name": "Python 3",
55
"build": {
66
// Sets the run context to one level up instead of the .devcontainer folder.
7-
"args": { "VARIANT": "3.8" },
7+
"args": { "VARIANT": "3.10" },
88
// Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename.
99
"dockerfile": "Dockerfile"
1010
},

packages/google-cloud-spanner/.devcontainer/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# This file is autogenerated by pip-compile with Python 3.8
2+
# This file is autogenerated by pip-compile with Python 3.8 # version-scanner: ignore
33
# by the following command:
44
#
55
# pip-compile --generate-hashes requirements.in

packages/google-cloud-spanner/docs/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# -*- coding: utf-8 -*-
2-
# Copyright 2025 Google LLC
2+
# Copyright 2026 Google LLC
33
#
44
# Licensed under the Apache License, Version 2.0 (the "License");
55
# you may not use this file except in compliance with the License.
@@ -83,7 +83,7 @@
8383

8484
# General information about the project.
8585
project = "google-cloud-spanner"
86-
copyright = "2025, Google, LLC"
86+
copyright = "2026, Google, LLC"
8787
author = "Google APIs"
8888

8989
# The version info for the project you're documenting, acts as replacement for

packages/google-cloud-spanner/google/cloud/aio/_cross_sync/cross_sync.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ async def async_func(self, arg: int) -> int:
4242
import concurrent.futures
4343
import inspect
4444
import queue
45-
import sys
4645
import threading
4746
import time
4847
import typing
@@ -269,7 +268,7 @@ def create_task(
269268
sync_executor: ThreadPoolExecutor to use for sync operations. Ignored in async version
270269
"""
271270
task: CrossSync.Task[T] = asyncio.create_task(fn(*fn_args, **fn_kwargs))
272-
if task_name and sys.version_info >= (3, 8):
271+
if task_name:
273272
task.set_name(task_name)
274273
return task
275274

packages/google-cloud-spanner/google/cloud/spanner_admin_database_v1/__init__.py

Lines changed: 75 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# -*- coding: utf-8 -*-
2-
# Copyright 2025 Google LLC
2+
# Copyright 2026 Google LLC
33
#
44
# Licensed under the Apache License, Version 2.0 (the "License");
55
# you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
2121

2222
__version__ = package_version.__version__
2323

24+
from importlib import metadata
2425

2526
from .services.database_admin import DatabaseAdminAsyncClient, DatabaseAdminClient
2627
from .types.backup import (
@@ -99,18 +100,81 @@
99100
api_core.check_python_version("google.cloud.spanner_admin_database_v1") # type: ignore
100101
api_core.check_dependency_versions("google.cloud.spanner_admin_database_v1") # type: ignore
101102
else: # pragma: NO COVER
102-
import warnings
103+
# An older version of api_core is installed which does not define the
104+
# functions above. We do equivalent checks manually.
105+
try:
106+
import warnings
103107

104-
_py_version_str = sys.version.split()[0]
105-
# version-scanner: ignore-next-line
106-
if sys.version_info < (3, 10):
108+
_py_version_str = sys.version.split()[0]
109+
_package_label = "google.cloud.spanner_admin_database_v1"
110+
if sys.version_info < (3, 10):
111+
warnings.warn(
112+
"You are using a non-supported Python version "
113+
+ f"({_py_version_str}). Google will not post any further "
114+
+ f"updates to {_package_label} supporting this Python version. "
115+
+ "Please upgrade to the latest Python version, or at "
116+
+ f"least to Python 3.10, and then update {_package_label}.",
117+
FutureWarning,
118+
)
119+
120+
def parse_version_to_tuple(version_string: str):
121+
"""Safely converts a semantic version string to a comparable tuple of integers.
122+
Example: "4.25.8" -> (4, 25, 8)
123+
Ignores non-numeric parts and handles common version formats.
124+
Args:
125+
version_string: Version string in the format "x.y.z" or "x.y.z<suffix>"
126+
Returns:
127+
Tuple of integers for the parsed version string.
128+
"""
129+
parts = []
130+
for part in version_string.split("."):
131+
try:
132+
parts.append(int(part))
133+
except ValueError:
134+
# If it's a non-numeric part (e.g., '1.0.0b1' -> 'b1'), stop here.
135+
# This is a simplification compared to 'packaging.parse_version', but sufficient
136+
# for comparing strictly numeric semantic versions.
137+
break
138+
return tuple(parts)
139+
140+
def _get_version(dependency_name):
141+
try:
142+
version_string: str = metadata.version(dependency_name)
143+
parsed_version = parse_version_to_tuple(version_string)
144+
return (parsed_version, version_string)
145+
except Exception:
146+
# Catch exceptions from metadata.version() (e.g., PackageNotFoundError)
147+
# or errors during parse_version_to_tuple
148+
return (None, "--")
149+
150+
_dependency_package = "google.protobuf"
151+
_next_supported_version = "4.25.8"
152+
_next_supported_version_tuple = (4, 25, 8)
153+
_recommendation = " (we recommend 6.x)"
154+
(_version_used, _version_used_string) = _get_version(_dependency_package)
155+
if _version_used and _version_used < _next_supported_version_tuple:
156+
warnings.warn(
157+
f"Package {_package_label} depends on "
158+
+ f"{_dependency_package}, currently installed at version "
159+
+ f"{_version_used_string}. Future updates to "
160+
+ f"{_package_label} will require {_dependency_package} at "
161+
+ f"version {_next_supported_version} or higher{_recommendation}."
162+
+ " Please ensure "
163+
+ "that either (a) your Python environment doesn't pin the "
164+
+ f"version of {_dependency_package}, so that updates to "
165+
+ f"{_package_label} can require the higher version, or "
166+
+ "(b) you manually update your Python environment to use at "
167+
+ f"least version {_next_supported_version} of "
168+
+ f"{_dependency_package}.",
169+
FutureWarning,
170+
)
171+
except Exception:
107172
warnings.warn(
108-
"You are using a non-supported Python version "
109-
+ f"({_py_version_str}). Google will not post any further "
110-
+ "updates to google.cloud.spanner_admin_database_v1 supporting this Python version. "
111-
+ "Please upgrade to the latest Python version, or at "
112-
+ "least to Python 3.10, and then update google.cloud.spanner_admin_database_v1.",
113-
FutureWarning,
173+
"Could not determine the version of Python "
174+
+ "currently being used. To continue receiving "
175+
+ "updates for {_package_label}, ensure you are "
176+
+ "using a supported version of Python; see "
177+
+ "https://devguide.python.org/versions/"
114178
)
115179

116180
__all__ = (

packages/google-cloud-spanner/google/cloud/spanner_admin_database_v1/services/database_admin/async_client.py

Lines changed: 13 additions & 13 deletions

0 commit comments

Comments
 (0)