From 61fa309301f157288ab7ed249a4af6843cd50935 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 30 Sep 2026 10:46:49 -0400 Subject: [PATCH 01/16] fix(ci): support modern uv backend in docfx and latest pandas in db-dtypes --- packages/gcp-sphinx-docfx-yaml/noxfile.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/noxfile.py b/packages/gcp-sphinx-docfx-yaml/noxfile.py index c07b64581285..59a5741a796c 100644 --- a/packages/gcp-sphinx-docfx-yaml/noxfile.py +++ b/packages/gcp-sphinx-docfx-yaml/noxfile.py @@ -171,7 +171,9 @@ def lint_setup_py(session): session.run("flake8", "setup.py") -@nox.session(python=UNIT_TEST_PYTHON_VERSIONS) +# Use virtualenv backend to prevent modern uv build isolation from failing on +# legacy sdist dependencies (unify/untokenize) +@nox.session(python=UNIT_TEST_PYTHON_VERSIONS, venv_backend="virtualenv") def unit(session): """Run unit tests.""" # Re-enable 3.11, 3.12, and 3.13 after environment verification. From 4ddde05a9de317f63daf57387aaba04ce79d2b5b Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 30 Sep 2026 10:58:34 -0400 Subject: [PATCH 02/16] fix(ci): use virtualenv backend for sqlalchemy-bigquery and restore to shard tests Explicitly set venv_backend="virtualenv" on sqlalchemy-bigquery Nox sessions to bypass strict PEP 621 duplicate extra name parsing in uv under UV_PRERELEASE=allow (caused by sqlalchemy==2.1.0rc2). Removes sqlalchemy-bigquery from EXCLUDED_PACKAGES in ci/get_package_shards.py. --- ci/get_package_shards.py | 9 +-------- packages/sqlalchemy-bigquery/noxfile.py | 18 +++++++++--------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/ci/get_package_shards.py b/ci/get_package_shards.py index d0dd4e7d4ea2..558abd4a99be 100644 --- a/ci/get_package_shards.py +++ b/ci/get_package_shards.py @@ -49,14 +49,7 @@ } # Packages temporarily excluded from CI test execution. -# NOTE: 'sqlalchemy-bigquery' is temporarily excluded to allow testing in this PR -# to complete due to an upstream packaging issue in sqlalchemy (duplicate normalized -# extra name 'mssql-pymssql' under strict uv PEP 621 parsing in sqlalchemy==2.1.0rc2, -# pulled via global UV_PRERELEASE=allow). Awaiting team feedback on a long-term -# solution (e.g. package migration out of the monorepo or adjusting workflow settings). -EXCLUDED_PACKAGES = { - "sqlalchemy-bigquery", -} +EXCLUDED_PACKAGES = set() def get_package_directories(): diff --git a/packages/sqlalchemy-bigquery/noxfile.py b/packages/sqlalchemy-bigquery/noxfile.py index f9ebdeb8b331..6f53da24c95b 100644 --- a/packages/sqlalchemy-bigquery/noxfile.py +++ b/packages/sqlalchemy-bigquery/noxfile.py @@ -289,7 +289,7 @@ def install_unittest_dependencies(session, *constraints): session.install("-e", ".", *constraints) -@nox.session(python=ALL_PYTHON) +@nox.session(python=ALL_PYTHON, venv_backend="virtualenv") @nox.parametrize( "protobuf_implementation", ["python", "upb"], @@ -450,7 +450,7 @@ def _run_system_test_logic(session, test_type): ) -@nox.session(python="3.12") +@nox.session(python="3.12", venv_backend="virtualenv") @nox.parametrize("test_type", ["system", "system_noextras", "compliance"]) @_calculate_duration def system(session, test_type): @@ -458,21 +458,21 @@ def system(session, test_type): _run_system_test_logic(session, test_type) -@nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) +@nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS, venv_backend="virtualenv") @_calculate_duration def system_noextras(session): """Run the system test suite without extras.""" _run_system_test_logic(session, "system_noextras") -@nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS[-1]) +@nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS[-1], venv_backend="virtualenv") @_calculate_duration def compliance(session): """Run the SQLAlchemy dialect-compliance system tests""" _run_system_test_logic(session, "compliance") -@nox.session(python=DEFAULT_PYTHON_VERSION) +@nox.session(python=DEFAULT_PYTHON_VERSION, venv_backend="virtualenv") @_calculate_duration def cover(session): """Run the final coverage report. @@ -486,7 +486,7 @@ def cover(session): session.run("coverage", "erase") -@nox.session(python="3.10") +@nox.session(python="3.10", venv_backend="virtualenv") @_calculate_duration def docs(session): """Build the docs for this library.""" @@ -524,7 +524,7 @@ def docs(session): ) -@nox.session(python="3.10") +@nox.session(python="3.10", venv_backend="virtualenv") @_calculate_duration def docfx(session): """Build the docfx yaml files for this library.""" @@ -573,7 +573,7 @@ def docfx(session): ) -@nox.session(python=DEFAULT_PYTHON_VERSION) +@nox.session(python=DEFAULT_PYTHON_VERSION, venv_backend="virtualenv") @nox.parametrize( "protobuf_implementation", ["python", "upb"], @@ -697,7 +697,7 @@ def mypy(session): session.skip("mypy tests are not yet supported") -@nox.session(python=DEFAULT_PYTHON_VERSION) +@nox.session(python=DEFAULT_PYTHON_VERSION, venv_backend="virtualenv") @nox.parametrize( "protobuf_implementation", ["python", "upb"], From 39371daa9dca0449a0ea331ed966527c587d3302 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 30 Sep 2026 11:07:38 -0400 Subject: [PATCH 03/16] test(db-dtypes): narrow TypeError substring matching to avoid false positives Address bot review feedback by narrowing the TypeError substring check from "not supported" to "is not supported" in exercise_any and exercise_all. This prevents accidentally suppressing unrelated TypeErrors (e.g. comparison or argument errors) while still matching the pandas datetime64 message ("'any'/'all' with datetime64 dtypes is not supported"). --- packages/db-dtypes/tests/unit/test_dtypes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/db-dtypes/tests/unit/test_dtypes.py b/packages/db-dtypes/tests/unit/test_dtypes.py index b4039c595828..41d618190622 100644 --- a/packages/db-dtypes/tests/unit/test_dtypes.py +++ b/packages/db-dtypes/tests/unit/test_dtypes.py @@ -534,7 +534,7 @@ def exercise_any(): try: return a.any() except TypeError as e: - if "does not support operation" in str(e) or "not supported" in str(e): + if "does not support operation" in str(e) or "is not supported" in str(e): return raise e @@ -571,7 +571,7 @@ def exercise_all(): try: return a.all() except TypeError as e: - if "does not support operation" in str(e) or "not supported" in str(e): + if "does not support operation" in str(e) or "is not supported" in str(e): return raise e From b4644c3b39b95d9c6dc2e1ac295b0e6691162c36 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 30 Sep 2026 11:20:10 -0400 Subject: [PATCH 04/16] test(db-dtypes): anchor reduction TypeError check to datetime64 and document versions Anchors the modern pandas TypeError check in exercise_any and exercise_all to require 'datetime64' alongside 'is not supported'. This completely eliminates the risk of matching unrelated TypeErrors (like comparison or argument errors). Adds self-documenting comments detailing the expected messages across pandas versions (<3.0 vs >=3.0) and local test mocks. --- packages/db-dtypes/tests/unit/test_dtypes.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/db-dtypes/tests/unit/test_dtypes.py b/packages/db-dtypes/tests/unit/test_dtypes.py index 41d618190622..c3283929101a 100644 --- a/packages/db-dtypes/tests/unit/test_dtypes.py +++ b/packages/db-dtypes/tests/unit/test_dtypes.py @@ -534,7 +534,15 @@ def exercise_any(): try: return a.any() except TypeError as e: - if "does not support operation" in str(e) or "is not supported" in str(e): + # Truth reduction ('any'/'all') is disallowed on datetime64 arrays (pandas GH#34479). + # Known messages across pandas versions: + # - pandas < 3.0: "datetime64 type does not support operation 'any'" + # - pandas >= 3.0: "'any' with datetime64 dtypes is not supported" + # - test mock: "does not support operation" + msg = str(e) + if "does not support operation" in msg or ( + "datetime64" in msg and "is not supported" in msg + ): return raise e @@ -571,7 +579,15 @@ def exercise_all(): try: return a.all() except TypeError as e: - if "does not support operation" in str(e) or "is not supported" in str(e): + # Truth reduction ('any'/'all') is disallowed on datetime64 arrays (pandas GH#34479). + # Known messages across pandas versions: + # - pandas < 3.0: "datetime64 type does not support operation 'all'" + # - pandas >= 3.0: "'all' with datetime64 dtypes is not supported" + # - test mock: "does not support operation" + msg = str(e) + if "does not support operation" in msg or ( + "datetime64" in msg and "is not supported" in msg + ): return raise e From f12d525f226025fee3c300cbcc3ee981fb40a59c Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 30 Sep 2026 11:28:59 -0400 Subject: [PATCH 05/16] chore(sqlalchemy-bigquery): add VENV_BACKEND constant and note explaining diversion from uv Defines VENV_BACKEND = "virtualenv" in noxfile.py with explanatory comments highlighting the upstream packaging issue in sqlalchemy==2.1.0rc2 (duplicate normalized extra name 'mssql-pymssql' under strict uv PEP 621 parsing with UV_PRERELEASE=allow). Applies VENV_BACKEND across affected sessions. --- packages/sqlalchemy-bigquery/noxfile.py | 26 ++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/packages/sqlalchemy-bigquery/noxfile.py b/packages/sqlalchemy-bigquery/noxfile.py index 6f53da24c95b..31c58aa4955b 100644 --- a/packages/sqlalchemy-bigquery/noxfile.py +++ b/packages/sqlalchemy-bigquery/noxfile.py @@ -170,6 +170,11 @@ def wrapper(*args, **kwargs): nox.options.stop_on_first_error = True nox.options.error_on_missing_interpreters = True +# NOTE: venv_backend="virtualenv" is used to bypass an upstream packaging issue +# in sqlalchemy (duplicate normalized extra name 'mssql-pymssql' under strict uv +# PEP 621 parsing in sqlalchemy==2.1.0rc2, pulled via global UV_PRERELEASE=allow). +VENV_BACKEND = "virtualenv" + @nox.session(python=DEFAULT_PYTHON_VERSION) @_calculate_duration @@ -289,7 +294,10 @@ def install_unittest_dependencies(session, *constraints): session.install("-e", ".", *constraints) -@nox.session(python=ALL_PYTHON, venv_backend="virtualenv") +# NOTE: venv_backend=VENV_BACKEND is used to bypass an upstream packaging issue +# in sqlalchemy (duplicate normalized extra name 'mssql-pymssql' under strict uv +# PEP 621 parsing in sqlalchemy==2.1.0rc2, pulled via global UV_PRERELEASE=allow). +@nox.session(python=ALL_PYTHON, venv_backend=VENV_BACKEND) @nox.parametrize( "protobuf_implementation", ["python", "upb"], @@ -450,7 +458,7 @@ def _run_system_test_logic(session, test_type): ) -@nox.session(python="3.12", venv_backend="virtualenv") +@nox.session(python="3.12", venv_backend=VENV_BACKEND) @nox.parametrize("test_type", ["system", "system_noextras", "compliance"]) @_calculate_duration def system(session, test_type): @@ -458,21 +466,21 @@ def system(session, test_type): _run_system_test_logic(session, test_type) -@nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS, venv_backend="virtualenv") +@nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS, venv_backend=VENV_BACKEND) @_calculate_duration def system_noextras(session): """Run the system test suite without extras.""" _run_system_test_logic(session, "system_noextras") -@nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS[-1], venv_backend="virtualenv") +@nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS[-1], venv_backend=VENV_BACKEND) @_calculate_duration def compliance(session): """Run the SQLAlchemy dialect-compliance system tests""" _run_system_test_logic(session, "compliance") -@nox.session(python=DEFAULT_PYTHON_VERSION, venv_backend="virtualenv") +@nox.session(python=DEFAULT_PYTHON_VERSION, venv_backend=VENV_BACKEND) @_calculate_duration def cover(session): """Run the final coverage report. @@ -486,7 +494,7 @@ def cover(session): session.run("coverage", "erase") -@nox.session(python="3.10", venv_backend="virtualenv") +@nox.session(python="3.10", venv_backend=VENV_BACKEND) @_calculate_duration def docs(session): """Build the docs for this library.""" @@ -524,7 +532,7 @@ def docs(session): ) -@nox.session(python="3.10", venv_backend="virtualenv") +@nox.session(python="3.10", venv_backend=VENV_BACKEND) @_calculate_duration def docfx(session): """Build the docfx yaml files for this library.""" @@ -573,7 +581,7 @@ def docfx(session): ) -@nox.session(python=DEFAULT_PYTHON_VERSION, venv_backend="virtualenv") +@nox.session(python=DEFAULT_PYTHON_VERSION, venv_backend=VENV_BACKEND) @nox.parametrize( "protobuf_implementation", ["python", "upb"], @@ -697,7 +705,7 @@ def mypy(session): session.skip("mypy tests are not yet supported") -@nox.session(python=DEFAULT_PYTHON_VERSION, venv_backend="virtualenv") +@nox.session(python=DEFAULT_PYTHON_VERSION, venv_backend=VENV_BACKEND) @nox.parametrize( "protobuf_implementation", ["python", "upb"], From 7e7314571179b01fbcd6324045825004828b9ee3 Mon Sep 17 00:00:00 2001 From: Chalmer Lowe Date: Wed, 30 Sep 2026 11:37:54 -0400 Subject: [PATCH 06/16] Apply suggestion from @chalmerlowe --- packages/sqlalchemy-bigquery/noxfile.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/sqlalchemy-bigquery/noxfile.py b/packages/sqlalchemy-bigquery/noxfile.py index 31c58aa4955b..f929f537dce1 100644 --- a/packages/sqlalchemy-bigquery/noxfile.py +++ b/packages/sqlalchemy-bigquery/noxfile.py @@ -294,9 +294,6 @@ def install_unittest_dependencies(session, *constraints): session.install("-e", ".", *constraints) -# NOTE: venv_backend=VENV_BACKEND is used to bypass an upstream packaging issue -# in sqlalchemy (duplicate normalized extra name 'mssql-pymssql' under strict uv -# PEP 621 parsing in sqlalchemy==2.1.0rc2, pulled via global UV_PRERELEASE=allow). @nox.session(python=ALL_PYTHON, venv_backend=VENV_BACKEND) @nox.parametrize( "protobuf_implementation", From 6a27c4270f8ef2a58b4fd9aa009f7ac2ec3b29da Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 30 Sep 2026 12:14:52 -0400 Subject: [PATCH 07/16] test(db-dtypes): pin pandas < 3.1.0dev0 in constraints-3.14.txt to isolate presubmit from pre-release breakage --- .../db-dtypes/testing/constraints-3.14.txt | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/packages/db-dtypes/testing/constraints-3.14.txt b/packages/db-dtypes/testing/constraints-3.14.txt index e69de29bb2d1..4caa7e8ec2de 100644 --- a/packages/db-dtypes/testing/constraints-3.14.txt +++ b/packages/db-dtypes/testing/constraints-3.14.txt @@ -0,0 +1,35 @@ +# ----------------------------------------------------------------------------- +# Constraints for Python 3.14 +# ----------------------------------------------------------------------------- +# +# What is this file? +# This file tells our package installer (like pip or uv) which specific versions +# of external libraries it is allowed to use when running tests on Python 3.14. +# +# Why do we need a limit on pandas here? +# In our automated testing environment on GitHub, the installer is configured to +# allow "pre-releases" (early, unfinished test versions of packages, such as +# alphas, betas, and release candidates). +# +# Because pandas published an early release candidate (version 3.1.0rc0), the +# installer automatically selected that test version instead of the official, +# stable release (version 3.0.x). +# +# Version 3.1 of pandas introduces several breaking changes to how custom data +# types work (specifically, changes to the ExtensionArray interface contracts, +# how missing values are filled with fillna(), and the removal of internal helper +# functions like np_version_gt2). +# +# Updating db-dtypes to support these new pandas 3.1 changes is a separate, +# dedicated feature effort that is being tracked in our project issue tracker. +# +# Until that feature work is finished and merged, this constraint makes sure +# our regular pull request tests run against the latest official, stable release +# of pandas (version 3.0.x), where all 1,174 compliance tests pass cleanly. +# +# Forward-looking tests against upcoming, unreleased versions of pandas and +# other dependencies continue to run in our dedicated nightly pre-release +# test suite. +# ----------------------------------------------------------------------------- + +pandas < 3.1.0dev0 From c43cc6b6281a3edb6b8e8aea3cb9bdf3a2593ea7 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 30 Sep 2026 12:21:35 -0400 Subject: [PATCH 08/16] docs(db-dtypes): simplify explanatory comment in constraints-3.14.txt --- .../db-dtypes/testing/constraints-3.14.txt | 41 ++++--------------- 1 file changed, 8 insertions(+), 33 deletions(-) diff --git a/packages/db-dtypes/testing/constraints-3.14.txt b/packages/db-dtypes/testing/constraints-3.14.txt index 4caa7e8ec2de..72e1e5759b6f 100644 --- a/packages/db-dtypes/testing/constraints-3.14.txt +++ b/packages/db-dtypes/testing/constraints-3.14.txt @@ -1,35 +1,10 @@ -# ----------------------------------------------------------------------------- -# Constraints for Python 3.14 -# ----------------------------------------------------------------------------- -# -# What is this file? -# This file tells our package installer (like pip or uv) which specific versions -# of external libraries it is allowed to use when running tests on Python 3.14. -# -# Why do we need a limit on pandas here? -# In our automated testing environment on GitHub, the installer is configured to -# allow "pre-releases" (early, unfinished test versions of packages, such as -# alphas, betas, and release candidates). -# -# Because pandas published an early release candidate (version 3.1.0rc0), the -# installer automatically selected that test version instead of the official, -# stable release (version 3.0.x). -# -# Version 3.1 of pandas introduces several breaking changes to how custom data -# types work (specifically, changes to the ExtensionArray interface contracts, -# how missing values are filled with fillna(), and the removal of internal helper -# functions like np_version_gt2). -# -# Updating db-dtypes to support these new pandas 3.1 changes is a separate, -# dedicated feature effort that is being tracked in our project issue tracker. -# -# Until that feature work is finished and merged, this constraint makes sure -# our regular pull request tests run against the latest official, stable release -# of pandas (version 3.0.x), where all 1,174 compliance tests pass cleanly. -# -# Forward-looking tests against upcoming, unreleased versions of pandas and -# other dependencies continue to run in our dedicated nightly pre-release -# test suite. -# ----------------------------------------------------------------------------- +# When testing with `pandas >= 3.1.0` (currently in pre-release as `pandas==3.1.0rc0`), +# the `db-dtypes` compliance test suite (`tests/compliance`) fails due to upstream +# changes in pandas internal utilities and ExtensionArray interface contracts. +# To prevent presubmit PR CI from failing unexpectedly on developer branches, a +# temporary ceiling constraint (`pandas < 3.1.0dev0`) was added. +# +# Forward-looking tests against upcoming, unreleased versions of pandas and other +# dependencies continue to run in our dedicated pre-release test suite. pandas < 3.1.0dev0 From acc3afb3ea4c0c9abcf8285454596297c2402f01 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 30 Sep 2026 12:39:11 -0400 Subject: [PATCH 09/16] fix(sqlalchemy-bigquery): support WindowFunctionTest test name across SQLAlchemy versions --- .../test_dialect_compliance.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-bigquery/tests/sqlalchemy_dialect_compliance/test_dialect_compliance.py b/packages/sqlalchemy-bigquery/tests/sqlalchemy_dialect_compliance/test_dialect_compliance.py index dde343c62429..6e5c14a68e7c 100644 --- a/packages/sqlalchemy-bigquery/tests/sqlalchemy_dialect_compliance/test_dialect_compliance.py +++ b/packages/sqlalchemy-bigquery/tests/sqlalchemy_dialect_compliance/test_dialect_compliance.py @@ -644,6 +644,7 @@ def test_no_results_for_non_returning_insert(cls): PostCompileParamsTest ) # BQ adds backticks to bind parameters, causing failure of tests TODO: fix this? del QuotedNameArgumentTest # Quotes aren't allowed in BigQuery table names. -del ( - WindowFunctionTest.test_window_rows_between -) # test expects BQ to return sorted results +# Test expects BQ to return sorted results (renamed to _w_caching in SQLAlchemy 2.1+) +for _test_name in ("test_window_rows_between", "test_window_rows_between_w_caching"): + if hasattr(WindowFunctionTest, _test_name): + delattr(WindowFunctionTest, _test_name) From 75ba6cc9fde024a25b7acccda8f7cd95b5667d4b Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 30 Sep 2026 16:00:35 -0400 Subject: [PATCH 10/16] fix(sqlalchemy-bigquery): bind compliance session to DEFAULT_PYTHON_VERSION Replace SYSTEM_TEST_PYTHON_VERSIONS[-1] with DEFAULT_PYTHON_VERSION in the compliance session. When preview/RC Python runtimes (e.g. 3.15) are added to UNIT_TEST_PYTHON_VERSIONS and ALL_PYTHON before being installed in CI Docker images, taking the tail index causes Nox to abort with missing interpreter errors. DEFAULT_PYTHON_VERSION guarantees execution against the repository-wide verified stable runtime. --- packages/sqlalchemy-bigquery/noxfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sqlalchemy-bigquery/noxfile.py b/packages/sqlalchemy-bigquery/noxfile.py index f929f537dce1..023e62c64b5d 100644 --- a/packages/sqlalchemy-bigquery/noxfile.py +++ b/packages/sqlalchemy-bigquery/noxfile.py @@ -470,7 +470,7 @@ def system_noextras(session): _run_system_test_logic(session, "system_noextras") -@nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS[-1], venv_backend=VENV_BACKEND) +@nox.session(python=DEFAULT_PYTHON_VERSION, venv_backend=VENV_BACKEND) @_calculate_duration def compliance(session): """Run the SQLAlchemy dialect-compliance system tests""" From 83c728d4831ec72556e4f905cbcedfef00552966 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 30 Sep 2026 19:22:39 -0400 Subject: [PATCH 11/16] fix(sqlalchemy-bigquery): exclude TableViaSelectTest in compliance tests BigQuery requires all view definitions to qualify source tables with a dataset. TableViaSelectTest attempts to create views without dataset qualification, causing BigQuery to reject the DDL with a 400 DatabaseError. Exclude TableViaSelectTest from the compliance test suite. --- .../sqlalchemy_dialect_compliance/test_dialect_compliance.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/sqlalchemy-bigquery/tests/sqlalchemy_dialect_compliance/test_dialect_compliance.py b/packages/sqlalchemy-bigquery/tests/sqlalchemy_dialect_compliance/test_dialect_compliance.py index 6e5c14a68e7c..bca5d6e39f27 100644 --- a/packages/sqlalchemy-bigquery/tests/sqlalchemy_dialect_compliance/test_dialect_compliance.py +++ b/packages/sqlalchemy-bigquery/tests/sqlalchemy_dialect_compliance/test_dialect_compliance.py @@ -648,3 +648,7 @@ def test_no_results_for_non_returning_insert(cls): for _test_name in ("test_window_rows_between", "test_window_rows_between_w_caching"): if hasattr(WindowFunctionTest, _test_name): delattr(WindowFunctionTest, _test_name) + +# BigQuery requires dataset qualification for views, which TableViaSelectTest does not provide. +if "TableViaSelectTest" in globals(): + del TableViaSelectTest From a79d0477822cd823be5b4af47498c47b67f6a738 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Thu, 1 Oct 2026 05:23:08 -0400 Subject: [PATCH 12/16] fix(sqlalchemy-bigquery): map DOUBLE and DOUBLE_PRECISION to FLOAT64 In SQLAlchemy 2.0+, Double and Float bindparams emit parameter types such as '%(param:DOUBLE)s'. BigQuery does not recognize DOUBLE as a valid scalar type in DB-API parameter parsing, expecting FLOAT64 instead. Map visit_DOUBLE and visit_DOUBLE_PRECISION to visit_FLOAT in BigQueryTypeCompiler to compile to FLOAT64. --- .../sqlalchemy_bigquery/base.py | 2 +- .../tests/unit/test_compiler.py | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-bigquery/sqlalchemy_bigquery/base.py b/packages/sqlalchemy-bigquery/sqlalchemy_bigquery/base.py index e2922890cea0..db11393d97ae 100644 --- a/packages/sqlalchemy-bigquery/sqlalchemy_bigquery/base.py +++ b/packages/sqlalchemy-bigquery/sqlalchemy_bigquery/base.py @@ -600,7 +600,7 @@ def visit_BOOLEAN(self, type_, **kw): def visit_FLOAT(self, type_, **kw): return "FLOAT64" - visit_REAL = visit_FLOAT + visit_REAL = visit_DOUBLE = visit_DOUBLE_PRECISION = visit_FLOAT def visit_STRING(self, type_, **kw): if (type_.length is not None) and isinstance( diff --git a/packages/sqlalchemy-bigquery/tests/unit/test_compiler.py b/packages/sqlalchemy-bigquery/tests/unit/test_compiler.py index 77f55dd7bf80..4fae78e7b1e6 100644 --- a/packages/sqlalchemy-bigquery/tests/unit/test_compiler.py +++ b/packages/sqlalchemy-bigquery/tests/unit/test_compiler.py @@ -450,3 +450,40 @@ def compile_custom_intersect(element, compiler, **kwargs): found_sql = q.compile(faux_conn).string assert found_sql == expected_sql + + +def test_type_compiler_double_methods(): + from sqlalchemy_bigquery.base import BigQueryTypeCompiler + + assert BigQueryTypeCompiler.visit_DOUBLE == BigQueryTypeCompiler.visit_FLOAT + assert ( + BigQueryTypeCompiler.visit_DOUBLE_PRECISION == BigQueryTypeCompiler.visit_FLOAT + ) + + +_double_types = [ + getattr(sqlalchemy, name) + for name in ("DOUBLE", "DOUBLE_PRECISION", "Double") + if hasattr(sqlalchemy, name) +] + + +@pytest.mark.skipif( + not _double_types, + reason="DOUBLE types not present in this SQLAlchemy version", +) +@pytest.mark.parametrize("type_cls", _double_types or [None]) +def test_double_types_compile_to_float64(type_cls): + import sqlalchemy_bigquery + + dialect = sqlalchemy_bigquery.BigQueryDialect() + assert dialect.type_compiler.process(type_cls()) == "FLOAT64" + + +def test_float_literal_pyformat_bindparam(): + import sqlalchemy_bigquery + + dialect = sqlalchemy_bigquery.BigQueryDialect(paramstyle="pyformat") + stmt = sqlalchemy.select(sqlalchemy.literal(15.7563)) + compiled = stmt.compile(dialect=dialect) + assert "%(param_1:FLOAT64)s" in str(compiled) From 084a8b9809b047ecdcab2c2f2102a92ad8c9addb Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Thu, 1 Oct 2026 05:35:22 -0400 Subject: [PATCH 13/16] fix(db-dtypes): handle unreachable python.org intersphinx inventory in docs When docs.python.org is experiencing service degradation (e.g. 503 Service Unavailable), sphinx-build -W treats the unreachable objects.inv inventory as a fatal error. Conditionally attach the python mapping only when the inventory endpoint is reachable to prevent CI doc build failures. --- packages/db-dtypes/docs/conf.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/db-dtypes/docs/conf.py b/packages/db-dtypes/docs/conf.py index 672dafff8ba7..ef4f0333e805 100644 --- a/packages/db-dtypes/docs/conf.py +++ b/packages/db-dtypes/docs/conf.py @@ -359,7 +359,6 @@ # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { - "python": ("https://python.readthedocs.org/en/latest/", None), "google-auth": ("https://googleapis.dev/python/google-auth/latest/", None), "google.api_core": ( "https://googleapis.dev/python/google-api-core/latest/", @@ -371,6 +370,17 @@ "pandas": ("https://pandas.pydata.org/pandas-docs/stable/", None), } +try: + import urllib.request + + with urllib.request.urlopen("https://docs.python.org/3/objects.inv", timeout=2): + intersphinx_mapping["python"] = ( + "https://python.readthedocs.org/en/latest/", + None, + ) +except Exception: + pass + # Napoleon settings napoleon_google_docstring = True From b8051d552cb9465cb8f897281ef79da097173291 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Thu, 1 Oct 2026 05:46:07 -0400 Subject: [PATCH 14/16] fix(sqlalchemy-bigquery): handle unreachable python.org intersphinx inventory in docs When docs.python.org is experiencing service degradation (e.g. 503 Service Unavailable), sphinx-build -W treats the unreachable objects.inv inventory as a fatal error. Conditionally attach the python mapping only when the inventory endpoint is reachable to prevent CI doc build failures. --- packages/sqlalchemy-bigquery/docs/conf.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-bigquery/docs/conf.py b/packages/sqlalchemy-bigquery/docs/conf.py index 2a3478cc1616..35df80aeaf77 100644 --- a/packages/sqlalchemy-bigquery/docs/conf.py +++ b/packages/sqlalchemy-bigquery/docs/conf.py @@ -359,7 +359,6 @@ # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { - "python": ("https://python.readthedocs.org/en/latest/", None), "google-auth": ("https://googleapis.dev/python/google-auth/latest/", None), "google.api_core": ( "https://googleapis.dev/python/google-api-core/latest/", @@ -370,6 +369,17 @@ "protobuf": ("https://googleapis.dev/python/protobuf/latest/", None), } +try: + import urllib.request + + with urllib.request.urlopen("https://docs.python.org/3/objects.inv", timeout=2): + intersphinx_mapping["python"] = ( + "https://python.readthedocs.org/en/latest/", + None, + ) +except Exception: + pass + # Napoleon settings napoleon_google_docstring = True From 5abe3f1f4f824591976abd98a996eafbb62e0029 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Thu, 1 Oct 2026 05:53:10 -0400 Subject: [PATCH 15/16] docs: add explanatory comment for intersphinx inventory fallback --- packages/db-dtypes/docs/conf.py | 4 ++++ packages/sqlalchemy-bigquery/docs/conf.py | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/packages/db-dtypes/docs/conf.py b/packages/db-dtypes/docs/conf.py index ef4f0333e805..2c755cbc5cbe 100644 --- a/packages/db-dtypes/docs/conf.py +++ b/packages/db-dtypes/docs/conf.py @@ -370,6 +370,10 @@ "pandas": ("https://pandas.pydata.org/pandas-docs/stable/", None), } +# Check reachability of the Python standard library inventory before attaching it. +# Because Sphinx is run with `-W` (warnings as errors) in CI, an external network +# failure or upstream outage on docs.python.org would otherwise treat the missing +# inventory as a fatal error and fail the build. try: import urllib.request diff --git a/packages/sqlalchemy-bigquery/docs/conf.py b/packages/sqlalchemy-bigquery/docs/conf.py index 35df80aeaf77..b9b09445a11f 100644 --- a/packages/sqlalchemy-bigquery/docs/conf.py +++ b/packages/sqlalchemy-bigquery/docs/conf.py @@ -369,6 +369,10 @@ "protobuf": ("https://googleapis.dev/python/protobuf/latest/", None), } +# Check reachability of the Python standard library inventory before attaching it. +# Because Sphinx is run with `-W` (warnings as errors) in CI, an external network +# failure or upstream outage on docs.python.org would otherwise treat the missing +# inventory as a fatal error and fail the build. try: import urllib.request From 441b68b563f53770d52c54ee0875d173427b48eb Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Thu, 1 Oct 2026 05:59:50 -0400 Subject: [PATCH 16/16] chore: move sqlalchemy-bigquery changes to dedicated PR #18534 --- ci/get_package_shards.py | 9 ++++- packages/sqlalchemy-bigquery/docs/conf.py | 16 +------- packages/sqlalchemy-bigquery/noxfile.py | 23 +++++------- .../sqlalchemy_bigquery/base.py | 2 +- .../test_dialect_compliance.py | 11 ++---- .../tests/unit/test_compiler.py | 37 ------------------- 6 files changed, 22 insertions(+), 76 deletions(-) diff --git a/ci/get_package_shards.py b/ci/get_package_shards.py index 558abd4a99be..d0dd4e7d4ea2 100644 --- a/ci/get_package_shards.py +++ b/ci/get_package_shards.py @@ -49,7 +49,14 @@ } # Packages temporarily excluded from CI test execution. -EXCLUDED_PACKAGES = set() +# NOTE: 'sqlalchemy-bigquery' is temporarily excluded to allow testing in this PR +# to complete due to an upstream packaging issue in sqlalchemy (duplicate normalized +# extra name 'mssql-pymssql' under strict uv PEP 621 parsing in sqlalchemy==2.1.0rc2, +# pulled via global UV_PRERELEASE=allow). Awaiting team feedback on a long-term +# solution (e.g. package migration out of the monorepo or adjusting workflow settings). +EXCLUDED_PACKAGES = { + "sqlalchemy-bigquery", +} def get_package_directories(): diff --git a/packages/sqlalchemy-bigquery/docs/conf.py b/packages/sqlalchemy-bigquery/docs/conf.py index b9b09445a11f..2a3478cc1616 100644 --- a/packages/sqlalchemy-bigquery/docs/conf.py +++ b/packages/sqlalchemy-bigquery/docs/conf.py @@ -359,6 +359,7 @@ # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { + "python": ("https://python.readthedocs.org/en/latest/", None), "google-auth": ("https://googleapis.dev/python/google-auth/latest/", None), "google.api_core": ( "https://googleapis.dev/python/google-api-core/latest/", @@ -369,21 +370,6 @@ "protobuf": ("https://googleapis.dev/python/protobuf/latest/", None), } -# Check reachability of the Python standard library inventory before attaching it. -# Because Sphinx is run with `-W` (warnings as errors) in CI, an external network -# failure or upstream outage on docs.python.org would otherwise treat the missing -# inventory as a fatal error and fail the build. -try: - import urllib.request - - with urllib.request.urlopen("https://docs.python.org/3/objects.inv", timeout=2): - intersphinx_mapping["python"] = ( - "https://python.readthedocs.org/en/latest/", - None, - ) -except Exception: - pass - # Napoleon settings napoleon_google_docstring = True diff --git a/packages/sqlalchemy-bigquery/noxfile.py b/packages/sqlalchemy-bigquery/noxfile.py index 023e62c64b5d..f9ebdeb8b331 100644 --- a/packages/sqlalchemy-bigquery/noxfile.py +++ b/packages/sqlalchemy-bigquery/noxfile.py @@ -170,11 +170,6 @@ def wrapper(*args, **kwargs): nox.options.stop_on_first_error = True nox.options.error_on_missing_interpreters = True -# NOTE: venv_backend="virtualenv" is used to bypass an upstream packaging issue -# in sqlalchemy (duplicate normalized extra name 'mssql-pymssql' under strict uv -# PEP 621 parsing in sqlalchemy==2.1.0rc2, pulled via global UV_PRERELEASE=allow). -VENV_BACKEND = "virtualenv" - @nox.session(python=DEFAULT_PYTHON_VERSION) @_calculate_duration @@ -294,7 +289,7 @@ def install_unittest_dependencies(session, *constraints): session.install("-e", ".", *constraints) -@nox.session(python=ALL_PYTHON, venv_backend=VENV_BACKEND) +@nox.session(python=ALL_PYTHON) @nox.parametrize( "protobuf_implementation", ["python", "upb"], @@ -455,7 +450,7 @@ def _run_system_test_logic(session, test_type): ) -@nox.session(python="3.12", venv_backend=VENV_BACKEND) +@nox.session(python="3.12") @nox.parametrize("test_type", ["system", "system_noextras", "compliance"]) @_calculate_duration def system(session, test_type): @@ -463,21 +458,21 @@ def system(session, test_type): _run_system_test_logic(session, test_type) -@nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS, venv_backend=VENV_BACKEND) +@nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) @_calculate_duration def system_noextras(session): """Run the system test suite without extras.""" _run_system_test_logic(session, "system_noextras") -@nox.session(python=DEFAULT_PYTHON_VERSION, venv_backend=VENV_BACKEND) +@nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS[-1]) @_calculate_duration def compliance(session): """Run the SQLAlchemy dialect-compliance system tests""" _run_system_test_logic(session, "compliance") -@nox.session(python=DEFAULT_PYTHON_VERSION, venv_backend=VENV_BACKEND) +@nox.session(python=DEFAULT_PYTHON_VERSION) @_calculate_duration def cover(session): """Run the final coverage report. @@ -491,7 +486,7 @@ def cover(session): session.run("coverage", "erase") -@nox.session(python="3.10", venv_backend=VENV_BACKEND) +@nox.session(python="3.10") @_calculate_duration def docs(session): """Build the docs for this library.""" @@ -529,7 +524,7 @@ def docs(session): ) -@nox.session(python="3.10", venv_backend=VENV_BACKEND) +@nox.session(python="3.10") @_calculate_duration def docfx(session): """Build the docfx yaml files for this library.""" @@ -578,7 +573,7 @@ def docfx(session): ) -@nox.session(python=DEFAULT_PYTHON_VERSION, venv_backend=VENV_BACKEND) +@nox.session(python=DEFAULT_PYTHON_VERSION) @nox.parametrize( "protobuf_implementation", ["python", "upb"], @@ -702,7 +697,7 @@ def mypy(session): session.skip("mypy tests are not yet supported") -@nox.session(python=DEFAULT_PYTHON_VERSION, venv_backend=VENV_BACKEND) +@nox.session(python=DEFAULT_PYTHON_VERSION) @nox.parametrize( "protobuf_implementation", ["python", "upb"], diff --git a/packages/sqlalchemy-bigquery/sqlalchemy_bigquery/base.py b/packages/sqlalchemy-bigquery/sqlalchemy_bigquery/base.py index db11393d97ae..e2922890cea0 100644 --- a/packages/sqlalchemy-bigquery/sqlalchemy_bigquery/base.py +++ b/packages/sqlalchemy-bigquery/sqlalchemy_bigquery/base.py @@ -600,7 +600,7 @@ def visit_BOOLEAN(self, type_, **kw): def visit_FLOAT(self, type_, **kw): return "FLOAT64" - visit_REAL = visit_DOUBLE = visit_DOUBLE_PRECISION = visit_FLOAT + visit_REAL = visit_FLOAT def visit_STRING(self, type_, **kw): if (type_.length is not None) and isinstance( diff --git a/packages/sqlalchemy-bigquery/tests/sqlalchemy_dialect_compliance/test_dialect_compliance.py b/packages/sqlalchemy-bigquery/tests/sqlalchemy_dialect_compliance/test_dialect_compliance.py index bca5d6e39f27..dde343c62429 100644 --- a/packages/sqlalchemy-bigquery/tests/sqlalchemy_dialect_compliance/test_dialect_compliance.py +++ b/packages/sqlalchemy-bigquery/tests/sqlalchemy_dialect_compliance/test_dialect_compliance.py @@ -644,11 +644,6 @@ def test_no_results_for_non_returning_insert(cls): PostCompileParamsTest ) # BQ adds backticks to bind parameters, causing failure of tests TODO: fix this? del QuotedNameArgumentTest # Quotes aren't allowed in BigQuery table names. -# Test expects BQ to return sorted results (renamed to _w_caching in SQLAlchemy 2.1+) -for _test_name in ("test_window_rows_between", "test_window_rows_between_w_caching"): - if hasattr(WindowFunctionTest, _test_name): - delattr(WindowFunctionTest, _test_name) - -# BigQuery requires dataset qualification for views, which TableViaSelectTest does not provide. -if "TableViaSelectTest" in globals(): - del TableViaSelectTest +del ( + WindowFunctionTest.test_window_rows_between +) # test expects BQ to return sorted results diff --git a/packages/sqlalchemy-bigquery/tests/unit/test_compiler.py b/packages/sqlalchemy-bigquery/tests/unit/test_compiler.py index 4fae78e7b1e6..77f55dd7bf80 100644 --- a/packages/sqlalchemy-bigquery/tests/unit/test_compiler.py +++ b/packages/sqlalchemy-bigquery/tests/unit/test_compiler.py @@ -450,40 +450,3 @@ def compile_custom_intersect(element, compiler, **kwargs): found_sql = q.compile(faux_conn).string assert found_sql == expected_sql - - -def test_type_compiler_double_methods(): - from sqlalchemy_bigquery.base import BigQueryTypeCompiler - - assert BigQueryTypeCompiler.visit_DOUBLE == BigQueryTypeCompiler.visit_FLOAT - assert ( - BigQueryTypeCompiler.visit_DOUBLE_PRECISION == BigQueryTypeCompiler.visit_FLOAT - ) - - -_double_types = [ - getattr(sqlalchemy, name) - for name in ("DOUBLE", "DOUBLE_PRECISION", "Double") - if hasattr(sqlalchemy, name) -] - - -@pytest.mark.skipif( - not _double_types, - reason="DOUBLE types not present in this SQLAlchemy version", -) -@pytest.mark.parametrize("type_cls", _double_types or [None]) -def test_double_types_compile_to_float64(type_cls): - import sqlalchemy_bigquery - - dialect = sqlalchemy_bigquery.BigQueryDialect() - assert dialect.type_compiler.process(type_cls()) == "FLOAT64" - - -def test_float_literal_pyformat_bindparam(): - import sqlalchemy_bigquery - - dialect = sqlalchemy_bigquery.BigQueryDialect(paramstyle="pyformat") - stmt = sqlalchemy.select(sqlalchemy.literal(15.7563)) - compiled = stmt.compile(dialect=dialect) - assert "%(param_1:FLOAT64)s" in str(compiled)