From bb7ba0eafdcb7012dda43bf75992f8e112b0b59d Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Tue, 7 Jul 2026 04:48:28 -0400 Subject: [PATCH 1/6] feat: centralize mypy config for spanner --- mypy.ini | 50 ++++++++++++++++++------ packages/google-cloud-spanner/mypy.ini | 15 ------- packages/google-cloud-spanner/noxfile.py | 14 +++++++ 3 files changed, 53 insertions(+), 26 deletions(-) delete mode 100644 packages/google-cloud-spanner/mypy.ini diff --git a/mypy.ini b/mypy.ini index e36c23ebbc8a..a6f8d17f0ab3 100644 --- a/mypy.ini +++ b/mypy.ini @@ -14,7 +14,6 @@ exclude = (?x)( | (^|/)tests/unit/gapic/ ) - # ============================================================================== # GLOBAL THIRD-PARTY & SHARED LIBRARY IGNORES # ============================================================================== @@ -28,13 +27,7 @@ ignore_missing_imports = True [mypy-flask] ignore_missing_imports = True -[mypy-google.auth.*] -ignore_missing_imports = True - -[mypy-google.cloud.bigtable] -ignore_missing_imports = True - -[mypy-google.cloud.pubsub] +[mypy-google.api.*] ignore_missing_imports = True [mypy-google.colab] @@ -61,6 +54,9 @@ ignore_missing_imports = True [mypy-grpc.*] ignore_missing_imports = True +[mypy-grpc_status] +ignore_missing_imports = True + [mypy-ibis.*] ignore_missing_imports = True @@ -86,15 +82,47 @@ ignore_missing_imports = True # ============================================================================== # PACKAGE-SPECIFIC OVERRIDES & EXCEPTIONS # ============================================================================== +# --- bigframes --- +[mypy-bigframes_vendored.*] +ignore_errors = True + +# --- google-auth --- +[mypy-google.auth.*] +ignore_missing_imports = True # --- google-cloud-bigtable --- -[mypy-google.cloud.bigtable.*] -ignore_errors = True +[mypy-google.cloud.bigtable] +ignore_missing_imports = True -[mypy-google.cloud.bigtable.data.*] +[mypy-google.cloud.bigtable.*] check_untyped_defs = True warn_unreachable = True disallow_any_generics = True +ignore_errors = True + +[mypy-google.cloud.bigtable.data.*] ignore_errors = False +[mypy-google.cloud.bigtable_admin.*] +ignore_errors = True + +[mypy-google.cloud.bigtable_admin_v2.*] +ignore_errors = True + +[mypy-google.cloud.bigtable_v2.*] +ignore_errors = True + +# --- google-cloud-datastore --- +[mypy-google.cloud.datastore.*] +ignore_missing_imports = True + +[mypy-google.cloud.datastore._app_engine_key_pb2] +ignore_errors = True +# --- google-cloud-firestore --- +[mypy-google.cloud.firestore.*] +check_untyped_defs = True + +# --- google-cloud-pubsub --- +[mypy-google.cloud.pubsub] +ignore_missing_imports = True diff --git a/packages/google-cloud-spanner/mypy.ini b/packages/google-cloud-spanner/mypy.ini deleted file mode 100644 index e0e0da2e9e40..000000000000 --- a/packages/google-cloud-spanner/mypy.ini +++ /dev/null @@ -1,15 +0,0 @@ -[mypy] -python_version = 3.14 -namespace_packages = True -ignore_missing_imports = False - -# TODO(https://github.com/googleapis/gapic-generator-python/issues/2563): -# Dependencies that historically lacks py.typed markers -[mypy-google.iam.*] -ignore_missing_imports = True - -# Helps mypy navigate the 'google' namespace more reliably in 3.10+ -explicit_package_bases = True - -# Performance: reuse results from previous runs to speed up 'nox' -incremental = True diff --git a/packages/google-cloud-spanner/noxfile.py b/packages/google-cloud-spanner/noxfile.py index fa74716b8142..210f372d177d 100644 --- a/packages/google-cloud-spanner/noxfile.py +++ b/packages/google-cloud-spanner/noxfile.py @@ -69,6 +69,18 @@ SYSTEM_TEST_EXTRAS_BY_PYTHON: Dict[str, List[str]] = {} CURRENT_DIRECTORY = pathlib.Path(__file__).parent.absolute() +# Path to the centralized mypy configuration file at the repository root. +# Search upwards to support running nox from both monorepo packages and integration test goldens. +MYPY_CONFIG_FILE = next( + ( + str(p / "mypy.ini") + for p in CURRENT_DIRECTORY.parents + if (p / "mypy.ini").exists() + ), + str(CURRENT_DIRECTORY.parent.parent / "mypy.ini"), +) + + nox.options.sessions = [ "unit-3.10", @@ -767,8 +779,10 @@ def mypy(session): session.install(".") session.run( "mypy", + f"--config-file={MYPY_CONFIG_FILE}", "-p", "google", + # "--check-untyped-defs", *session.posargs, ) From 28c3233f28c8e08b5c7705ec56279a43a819835f Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Tue, 7 Jul 2026 05:05:31 -0400 Subject: [PATCH 2/6] chore: format noxfile.py for spanner --- packages/google-cloud-spanner/noxfile.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/google-cloud-spanner/noxfile.py b/packages/google-cloud-spanner/noxfile.py index 210f372d177d..7dcb31b45ed7 100644 --- a/packages/google-cloud-spanner/noxfile.py +++ b/packages/google-cloud-spanner/noxfile.py @@ -81,7 +81,6 @@ ) - nox.options.sessions = [ "unit-3.10", "unit-3.11", @@ -782,7 +781,6 @@ def mypy(session): f"--config-file={MYPY_CONFIG_FILE}", "-p", "google", - # "--check-untyped-defs", *session.posargs, ) From b40916d3252f0d7e9062d63c211e6001ed65e111 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Tue, 7 Jul 2026 06:12:41 -0400 Subject: [PATCH 3/6] chore: add aggressive database cleanup to spanner system tests --- .../tests/system/_helpers.py | 27 +++++++++++++++++++ .../tests/system/conftest.py | 4 +++ 2 files changed, 31 insertions(+) diff --git a/packages/google-cloud-spanner/tests/system/_helpers.py b/packages/google-cloud-spanner/tests/system/_helpers.py index 4cd9879e5d2d..c100aa8b2f25 100644 --- a/packages/google-cloud-spanner/tests/system/_helpers.py +++ b/packages/google-cloud-spanner/tests/system/_helpers.py @@ -18,8 +18,10 @@ import uuid from google.api_core import exceptions +from google.api_core import datetime_helpers from test_utils import retry + from google.cloud.spanner_v1 import instance as instance_mod from tests import _fixtures @@ -159,6 +161,31 @@ def cleanup_old_instances(spanner_client): scrub_instance_ignore_not_found(instance) +def cleanup_stale_databases(instance, cutoff_seconds=600): + """Delete stale databases in the given instance older than cutoff_seconds.""" + cutoff_ms = (int(time.time()) - cutoff_seconds) * 1000 + + for database_pb in instance.list_databases(): + if database_pb.create_time is not None: + create_time_ms = datetime_helpers.to_milliseconds(database_pb.create_time) + + if create_time_ms < cutoff_ms: + db = instance.database(database_pb.name.split("/")[-1]) + try: + db.reload() + if db.enable_drop_protection: + db.enable_drop_protection = False + operation = db.update(["enable_drop_protection"]) + operation.result(DATABASE_OPERATION_TIMEOUT_IN_SECONDS) + db.drop() + except exceptions.NotFound: + pass + except exceptions.GoogleAPIError: + # Ignore other API errors during cleanup + pass + + + def unique_id(prefix, separator="-"): # Database name size: Spanner database names are limited to 30 characters. # See: https://docs.cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.database.v1#createdatabaserequest diff --git a/packages/google-cloud-spanner/tests/system/conftest.py b/packages/google-cloud-spanner/tests/system/conftest.py index 740cfc0e02b5..4f19f9efbd8e 100644 --- a/packages/google-cloud-spanner/tests/system/conftest.py +++ b/packages/google-cloud-spanner/tests/system/conftest.py @@ -218,8 +218,12 @@ def shared_instance( instance = spanner_client.instance(shared_instance_id) instance.reload() + _helpers.cleanup_stale_databases(instance) + + yield instance + if _helpers.CREATE_INSTANCE: _helpers.retry_429_503(instance.delete)() From 3b60796522285acf3d5381d47ccca5a6f2d01b23 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Tue, 7 Jul 2026 06:35:35 -0400 Subject: [PATCH 4/6] chore: fix linting errors (sorted imports) in spanner system tests --- packages/google-cloud-spanner/tests/system/_helpers.py | 6 ++---- packages/google-cloud-spanner/tests/system/conftest.py | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/google-cloud-spanner/tests/system/_helpers.py b/packages/google-cloud-spanner/tests/system/_helpers.py index c100aa8b2f25..b0a86ebd0752 100644 --- a/packages/google-cloud-spanner/tests/system/_helpers.py +++ b/packages/google-cloud-spanner/tests/system/_helpers.py @@ -17,12 +17,10 @@ import time import uuid -from google.api_core import exceptions -from google.api_core import datetime_helpers +from google.api_core import datetime_helpers, exceptions +from google.cloud.spanner_v1 import instance as instance_mod from test_utils import retry - -from google.cloud.spanner_v1 import instance as instance_mod from tests import _fixtures CREATE_INSTANCE_ENVVAR = "GOOGLE_CLOUD_TESTS_CREATE_SPANNER_INSTANCE" diff --git a/packages/google-cloud-spanner/tests/system/conftest.py b/packages/google-cloud-spanner/tests/system/conftest.py index 4f19f9efbd8e..d5f3c5a318f3 100644 --- a/packages/google-cloud-spanner/tests/system/conftest.py +++ b/packages/google-cloud-spanner/tests/system/conftest.py @@ -17,7 +17,6 @@ import time import pytest - from google.cloud import spanner_v1 from google.cloud.spanner_admin_database_v1 import DatabaseDialect from google.cloud.spanner_admin_database_v1.types.backup import ( From deb0e99a049cb0c534b4484f9e820fe5bbfe19cb Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Tue, 7 Jul 2026 06:45:09 -0400 Subject: [PATCH 5/6] chore: remove trailing whitespace in helpers --- packages/google-cloud-spanner/tests/system/_helpers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/google-cloud-spanner/tests/system/_helpers.py b/packages/google-cloud-spanner/tests/system/_helpers.py index b0a86ebd0752..8870400faa9b 100644 --- a/packages/google-cloud-spanner/tests/system/_helpers.py +++ b/packages/google-cloud-spanner/tests/system/_helpers.py @@ -162,11 +162,11 @@ def cleanup_old_instances(spanner_client): def cleanup_stale_databases(instance, cutoff_seconds=600): """Delete stale databases in the given instance older than cutoff_seconds.""" cutoff_ms = (int(time.time()) - cutoff_seconds) * 1000 - + for database_pb in instance.list_databases(): if database_pb.create_time is not None: create_time_ms = datetime_helpers.to_milliseconds(database_pb.create_time) - + if create_time_ms < cutoff_ms: db = instance.database(database_pb.name.split("/")[-1]) try: From 2188bce3a10564b15fa415cbf85c89deaa0f5bd9 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Tue, 7 Jul 2026 08:31:40 -0400 Subject: [PATCH 6/6] chore: format spanner system tests --- packages/google-cloud-spanner/tests/system/_helpers.py | 1 - packages/google-cloud-spanner/tests/system/conftest.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/packages/google-cloud-spanner/tests/system/_helpers.py b/packages/google-cloud-spanner/tests/system/_helpers.py index 8870400faa9b..2a4ae64f9e67 100644 --- a/packages/google-cloud-spanner/tests/system/_helpers.py +++ b/packages/google-cloud-spanner/tests/system/_helpers.py @@ -183,7 +183,6 @@ def cleanup_stale_databases(instance, cutoff_seconds=600): pass - def unique_id(prefix, separator="-"): # Database name size: Spanner database names are limited to 30 characters. # See: https://docs.cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.database.v1#createdatabaserequest diff --git a/packages/google-cloud-spanner/tests/system/conftest.py b/packages/google-cloud-spanner/tests/system/conftest.py index d5f3c5a318f3..39bc8a5bcae2 100644 --- a/packages/google-cloud-spanner/tests/system/conftest.py +++ b/packages/google-cloud-spanner/tests/system/conftest.py @@ -219,10 +219,8 @@ def shared_instance( _helpers.cleanup_stale_databases(instance) - yield instance - if _helpers.CREATE_INSTANCE: _helpers.retry_429_503(instance.delete)()