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..7dcb31b45ed7 100644 --- a/packages/google-cloud-spanner/noxfile.py +++ b/packages/google-cloud-spanner/noxfile.py @@ -69,6 +69,17 @@ 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,6 +778,7 @@ def mypy(session): session.install(".") session.run( "mypy", + f"--config-file={MYPY_CONFIG_FILE}", "-p", "google", # "--check-untyped-defs", diff --git a/packages/google-cloud-spanner/tests/system/_helpers.py b/packages/google-cloud-spanner/tests/system/_helpers.py index 4cd9879e5d2d..2a4ae64f9e67 100644 --- a/packages/google-cloud-spanner/tests/system/_helpers.py +++ b/packages/google-cloud-spanner/tests/system/_helpers.py @@ -17,10 +17,10 @@ import time import uuid -from google.api_core import exceptions +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" @@ -159,6 +159,30 @@ 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..39bc8a5bcae2 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 ( @@ -218,6 +217,8 @@ def shared_instance( instance = spanner_client.instance(shared_instance_id) instance.reload() + _helpers.cleanup_stale_databases(instance) + yield instance if _helpers.CREATE_INSTANCE: