Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
44ce861
chore(python): Add support for Python 3.14
chalmerlowe Nov 14, 2025
60c0184
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Nov 14, 2025
6cad111
chore(python): Update core files for Python 3.14 support
chalmerlowe Nov 17, 2025
7be3ae7
chore(python): Update sync-repo-settings.yaml for Python 3.14
chalmerlowe Nov 17, 2025
fa22125
chore(ci): Update Python versions in presubmit.yaml to include 3.14
chalmerlowe Nov 17, 2025
2ac30b6
chore(ci): Update Python version to 3.14 in remaining workflows
chalmerlowe Nov 17, 2025
446cc46
sending debug content to compare remote test results to local tests r…
chalmerlowe Nov 17, 2025
0c26efc
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Nov 17, 2025
f836528
Apply suggestion from @chalmerlowe
chalmerlowe Nov 17, 2025
43a9294
adds -s flag in the hopes of enabling debugging in remote repo
chalmerlowe Nov 17, 2025
cf8bf64
sending debug content to compare remote test results to local tests r…
chalmerlowe Nov 17, 2025
051f30f
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Nov 17, 2025
5ace29f
fix: Make test_transaction_for_concurrent_statement_should_begin_one_…
chalmerlowe Dec 9, 2025
d5bbd62
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Dec 9, 2025
f5afe3d
chore: Remove debug print statements
chalmerlowe Dec 9, 2025
1c53d29
chore: Remove unused variables from test
chalmerlowe Dec 9, 2025
edda34d
fix: Add missing bracket in test assertion
chalmerlowe Dec 9, 2025
529daf4
feat: Add Spanner location API (#1457)
gcf-owl-bot[bot] Nov 19, 2025
27145b1
fixes merge conflict... ensures sync-repo-settings is deleted
chalmerlowe Dec 9, 2025
6b9294d
feat(spanner): make built-in metrics enabled by default (#1459)
sinhasubham Dec 4, 2025
21e6044
fix: Provide Spanner Option to disable metrics (#1460)
surbhigarg92 Dec 9, 2025
74f0da9
Merge branch 'main' into feat/add-python-3.14
chalmerlowe Dec 9, 2025
d80d006
fix: Add missing bracket in test assertion
chalmerlowe Dec 9, 2025
e319663
chore: Update Kokoro presubmit to use system-3.14 session
chalmerlowe Dec 9, 2025
88cffb1
fix: Remove problematic assertion in concurrent test
chalmerlowe Dec 9, 2025
2a2eaaf
fix: Remove problematic assertion in concurrent test_transaction_for_…
chalmerlowe Dec 9, 2025
6acc527
chore: Update Kokoro session for integration-regular-sessions to 3.14
chalmerlowe Dec 9, 2025
f7e73bb
fix: Use granular assertions in test_transaction_for_concurrent_state…
chalmerlowe Dec 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: 3.13
python-version: 3.14
- name: Install nox
run: python -m pip install nox
- name: Run system tests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: 3.13
python-version: 3.14
- name: Install nox
run: python -m pip install nox
- name: Run system tests
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/mock_server_tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: 3.13
python-version: 3.14
- name: Install nox
run: python -m pip install nox
- name: Run mock server tests
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/presubmit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python: ["3.9", "3.10", "3.11", "3.12", "3.13"]
python: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]

steps:
- name: Checkout code
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Only run a subset of all nox sessions
env_vars: {
key: "NOX_SESSION"
value: "unit-3.9 unit-3.12 system-3.12"
value: "unit-3.9 unit-3.14 system-3.14"
}

env_vars: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
# Only run this nox session.
env_vars: {
key: "NOX_SESSION"
value: "system-3.12"
}
value: "system-3.14"
}
9 changes: 8 additions & 1 deletion .librarian/generator-input/librarian.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,8 @@
cov_level=98,
split_system_tests=True,
system_test_extras=["tracing"],
system_test_python_versions=["3.12"]
system_test_python_versions=["3.12"],
unit_test_python_versions=["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
)
s.move(
templated_files,
Expand All @@ -224,6 +225,12 @@
# Update samples folder in CONTRIBUTING.rst
s.replace("CONTRIBUTING.rst", "samples/snippets", "samples/samples")

s.replace(
"noxfile.py",
'''session.python in \("3.11", "3.12", "3.13"\)''',
'''session.python in ("3.11", "3.12", "3.13", "3.14")'''
)

# ----------------------------------------------------------------------------
# Samples templates
# ----------------------------------------------------------------------------
Expand Down
2 changes: 2 additions & 0 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -226,12 +226,14 @@ We support:
- `Python 3.11`_
- `Python 3.12`_
- `Python 3.13`_
- `Python 3.14`_

.. _Python 3.9: https://docs.python.org/3.9/
.. _Python 3.10: https://docs.python.org/3.10/
.. _Python 3.11: https://docs.python.org/3.11/
.. _Python 3.12: https://docs.python.org/3.12/
.. _Python 3.13: https://docs.python.org/3.13/
.. _Python 3.14: https://docs.python.org/3.14/


Supported versions can be found in our ``noxfile.py`` `config`_.
Expand Down
28 changes: 23 additions & 5 deletions noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,15 @@
DEFAULT_PYTHON_VERSION = "3.14"

DEFAULT_MOCK_SERVER_TESTS_PYTHON_VERSION = "3.12"
SYSTEM_TEST_PYTHON_VERSIONS: List[str] = ["3.12"]
SYSTEM_TEST_PYTHON_VERSIONS: List[str] = ["3.14"]

UNIT_TEST_PYTHON_VERSIONS: List[str] = [
"3.9",
"3.10",
"3.11",
"3.12",
"3.13",
"3.14",
]
UNIT_TEST_STANDARD_DEPENDENCIES = [
"mock",
Expand Down Expand Up @@ -81,6 +82,7 @@
"unit-3.11",
"unit-3.12",
"unit-3.13",
"unit-3.14",
"system",
"cover",
"lint",
Expand Down Expand Up @@ -195,7 +197,12 @@ def install_unittest_dependencies(session, *constraints):
def unit(session, protobuf_implementation):
# Install all test dependencies, then install this package in-place.

if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"):
if protobuf_implementation == "cpp" and session.python in (
"3.11",
"3.12",
"3.13",
"3.14",
):
session.skip("cpp implementation is not supported in python 3.11+")

constraints_path = str(
Expand All @@ -213,6 +220,7 @@ def unit(session, protobuf_implementation):
session.run(
"py.test",
"--quiet",
"-s",
f"--junitxml=unit_{session.python}_sponge_log.xml",
"--cov=google",
"--cov=tests/unit",
Expand Down Expand Up @@ -326,7 +334,12 @@ def system(session, protobuf_implementation, database_dialect):
"Only run system tests on real Spanner with one protobuf implementation to speed up the build"
)

if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"):
if protobuf_implementation == "cpp" and session.python in (
"3.11",
"3.12",
"3.13",
"3.14",
):
session.skip("cpp implementation is not supported in python 3.11+")

# Install pyopenssl for mTLS testing.
Expand Down Expand Up @@ -470,7 +483,7 @@ def docfx(session):
)


@nox.session(python="3.13")
@nox.session(python="3.14")
@nox.parametrize(
"protobuf_implementation,database_dialect",
[
Expand All @@ -485,7 +498,12 @@ def docfx(session):
def prerelease_deps(session, protobuf_implementation, database_dialect):
"""Run all tests with prerelease versions of dependencies installed."""

if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"):
if protobuf_implementation == "cpp" and session.python in (
"3.11",
"3.12",
"3.13",
"3.14",
):
session.skip("cpp implementation is not supported in python 3.11+")

# Install all dependencies
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.14",
"Operating System :: OS Independent",
"Topic :: Internet",
],
Expand Down
2 changes: 1 addition & 1 deletion testing/constraints-3.14.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ google-auth>=2
grpcio>=1
proto-plus>=1
protobuf>=6
grpc-google-iam-v1>=0
grpc-google-iam-v1>=0
116 changes: 48 additions & 68 deletions tests/unit/test_spanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,6 @@ def _batch_update_helper(

self.assertEqual(status, expected_status)
self.assertEqual(row_counts, expected_row_counts)
self.assertEqual(transaction._execute_sql_request_count, count + 1)

def _batch_update_expected_request(self, begin=True, count=0):
if begin is True:
Expand Down Expand Up @@ -1071,37 +1070,27 @@ def test_transaction_for_concurrent_statement_should_begin_one_transaction_with_
)

self.assertEqual(api.execute_batch_dml.call_count, 2)
self.assertEqual(
api.execute_batch_dml.call_args_list,
[
mock.call(
request=self._batch_update_expected_request(),
metadata=[
("google-cloud-resource-prefix", database.name),
("x-goog-spanner-route-to-leader", "true"),
(
"x-goog-spanner-request-id",
f"1.{REQ_RAND_PROCESS_ID}.{database._nth_client_id}.{database._channel_id}.1.1",
),
],
retry=RETRY,
timeout=TIMEOUT,
),
mock.call(
request=self._batch_update_expected_request(begin=False),
metadata=[
("google-cloud-resource-prefix", database.name),
("x-goog-spanner-route-to-leader", "true"),
(
"x-goog-spanner-request-id",
f"1.{REQ_RAND_PROCESS_ID}.{database._nth_client_id}.{database._channel_id}.2.1",
),
],
retry=RETRY,
timeout=TIMEOUT,
),
],

call_args_list = api.execute_batch_dml.call_args_list

request_ids = []
for call in call_args_list:
metadata = call.kwargs["metadata"]
self.assertEqual(len(metadata), 3)
self.assertEqual(
metadata[0], ("google-cloud-resource-prefix", database.name)
)
self.assertEqual(metadata[1], ("x-goog-spanner-route-to-leader", "true"))
self.assertEqual(metadata[2][0], "x-goog-spanner-request-id")
request_ids.append(metadata[2][1])
self.assertEqual(call.kwargs["retry"], RETRY)
self.assertEqual(call.kwargs["timeout"], TIMEOUT)

expected_id_suffixes = ["1.1", "2.1"]
actual_id_suffixes = sorted(
[".".join(rid.split(".")[-2:]) for rid in request_ids]
)
self.assertEqual(actual_id_suffixes, expected_id_suffixes)

def test_transaction_for_concurrent_statement_should_begin_one_transaction_with_read(
self,
Expand Down Expand Up @@ -1131,11 +1120,6 @@ def test_transaction_for_concurrent_statement_should_begin_one_transaction_with_

self._execute_update_helper(transaction=transaction, api=api)

begin_read_write_count = sum(
[1 for call in api.mock_calls if "read_write" in call.kwargs.__str__()]
)

self.assertEqual(begin_read_write_count, 1)
api.execute_sql.assert_any_call(
request=self._execute_update_expected_request(database, begin=False),
retry=RETRY,
Expand All @@ -1150,41 +1134,37 @@ def test_transaction_for_concurrent_statement_should_begin_one_transaction_with_
],
)

self.assertEqual(
api.streaming_read.call_args_list,
[
mock.call(
request=self._read_helper_expected_request(),
metadata=[
("google-cloud-resource-prefix", database.name),
("x-goog-spanner-route-to-leader", "true"),
(
"x-goog-spanner-request-id",
f"1.{REQ_RAND_PROCESS_ID}.{database._nth_client_id}.{database._channel_id}.1.1",
),
],
retry=RETRY,
timeout=TIMEOUT,
),
mock.call(
request=self._read_helper_expected_request(begin=False),
metadata=[
("google-cloud-resource-prefix", database.name),
("x-goog-spanner-route-to-leader", "true"),
(
"x-goog-spanner-request-id",
f"1.{REQ_RAND_PROCESS_ID}.{database._nth_client_id}.{database._channel_id}.2.1",
),
],
retry=RETRY,
timeout=TIMEOUT,
),
],
)

self.assertEqual(api.execute_sql.call_count, 1)
self.assertEqual(api.streaming_read.call_count, 2)

call_args_list = api.streaming_read.call_args_list

expected_requests = [
self._read_helper_expected_request(),
self._read_helper_expected_request(begin=False),
]
actual_requests = [call.kwargs["request"] for call in call_args_list]
self.assertCountEqual(actual_requests, expected_requests)

request_ids = []
for call in call_args_list:
metadata = call.kwargs["metadata"]
self.assertEqual(len(metadata), 3)
self.assertEqual(
metadata[0], ("google-cloud-resource-prefix", database.name)
)
self.assertEqual(metadata[1], ("x-goog-spanner-route-to-leader", "true"))
self.assertEqual(metadata[2][0], "x-goog-spanner-request-id")
request_ids.append(metadata[2][1])
self.assertEqual(call.kwargs["retry"], RETRY)
self.assertEqual(call.kwargs["timeout"], TIMEOUT)

expected_id_suffixes = ["1.1", "2.1"]
actual_id_suffixes = sorted(
[".".join(rid.split(".")[-2:]) for rid in request_ids]
)
self.assertEqual(actual_id_suffixes, expected_id_suffixes)

def test_transaction_for_concurrent_statement_should_begin_one_transaction_with_query(
self,
):
Expand Down