spanner-adbc
Experimental: this package is AI-generated and has not yet seen real-world use.
A Python ADBC driver for Google Cloud Spanner and Spanner Omni. It provides a DBAPI 2.0 interface that returns Apache Arrow data for pandas, Polars, DuckDB or PyArrow. Only GoogleSQL databases are supported, not the PostgreSQL dialect.
Install
Requires Python 3.11 or later and adbc-driver-manager 1.8 or later, which pip installs. Wheels bundle the native driver; see supported platforms.
pip install "spanner-adbc[dbapi]" # includes PyArrow and pandas
Plain spanner-adbc installs only the low-level ADBC API.
Quickstart
Connect to an existing GoogleSQL database using Application Default Credentials. This query needs no tables:
import spanner_adbc.dbapi as spanner
uri = "spanner:///projects/my-project/instances/my-instance/databases/my-db"
with spanner.connect(uri) as conn:
with conn.cursor() as cur:
cur.execute("SELECT @name AS name", {"name": "Alice"})
print(cur.fetch_arrow_table())
Parameters use the GoogleSQL @name syntax, and ? placeholders are rejected. A dict binds
parameters by name. A tuple binds them in the order they first appear in the SQL.
The later table examples use this sample table:
CREATE TABLE Singers (
SingerId INT64 NOT NULL,
FirstName STRING(MAX)
) PRIMARY KEY (SingerId);
INSERT INTO Singers (SingerId, FirstName) VALUES (1, 'Alice'), (2, 'Bob');
Run the CREATE TABLE and INSERT separately with autocommit=True; the driver doesn't accept
DDL and DML in the same call.
Connecting
The driver uses Application Default Credentials unless db_kwargs sets other
credentials. The option enums name every key, and raw strings such as "spanner.endpoint" work
too:
import spanner_adbc.dbapi as spanner
from spanner_adbc import DatabaseOptions
with spanner.connect(
"spanner:///projects/p/instances/i/databases/d",
{DatabaseOptions.KEYFILE: "/path/to/service-account.json"},
) as conn:
...
To use the emulator, set SPANNER_EMULATOR_HOST, or set DatabaseOptions.EMULATOR
to "true" and DatabaseOptions.ENDPOINT to its host:port. For Spanner Omni, set
DatabaseOptions.INSTANCE_TYPE to "omni" and DatabaseOptions.ENDPOINT to the server.
Authentication covers the credential options and when the driver connects anonymously.
Connections don't carry over into a forked process. With multiprocessing's fork start
method, the default on Linux before Python 3.14, connect in each worker; see
forked processes.
Options
connect(uri, db_kwargs, conn_kwargs, *, autocommit=False) takes database and connection
options, and conn.cursor(adbc_stmt_kwargs=...) takes statement options. DatabaseOptions,
ConnectionOptions and StatementOptions list the keys. They are StrEnums, so members work as
dictionary keys, but the typed driver manager getters, such as get_option_int, need .value.
Use string values in db_kwargs and conn_kwargs for compatibility with driver manager 1.8.
The autocommit keyword overrides ConnectionOptions.AUTOCOMMIT in conn_kwargs.
The option reference lists types, defaults and accepted values.
import spanner_adbc.dbapi as spanner
from spanner_adbc import ConnectionOptions, StatementOptions
with spanner.connect(
"spanner:///projects/p/instances/i/databases/d",
conn_kwargs={ConnectionOptions.READ_STALENESS: "max:10s"},
autocommit=True,
) as conn:
with conn.cursor(adbc_stmt_kwargs={StatementOptions.ROWS_PER_BATCH: "1024"}) as cur:
cur.execute("SELECT * FROM Singers")
Transactions
Following DBAPI, connections start with autocommit=False. Manual transactions differ from most
databases:
- A transaction runs either queries or writes, whichever comes first. Mixing them raises
ProgrammingErroruntil you commit or roll back. Queries share one snapshot, and there is no read-your-writes. - DML is buffered and runs at
commit(), so errors such as a duplicate key come fromcommit(), androwcountis -1. A failed commit keeps the buffered writes. If a commit times out or loses its connection, it may already have applied; userollback()to discard the buffer before deciding whether to retry the work. - Closing the connection, including leaving its
withblock, discards uncommitted writes. - DDL runs immediately, and rollback can't undo it.
THEN RETURNand partitioned DML needautocommit=True.
import spanner_adbc.dbapi as spanner
with spanner.connect("spanner:///projects/p/instances/i/databases/d") as conn:
with conn.cursor() as cur:
cur.execute("CREATE TABLE AdbcExample (Id INT64 NOT NULL) PRIMARY KEY (Id)")
cur.execute("INSERT INTO AdbcExample (Id) VALUES (1)")
conn.commit()
with conn.cursor() as cur:
cur.execute("SELECT COUNT(*) FROM AdbcExample")
assert cur.fetchone() == (1,)
conn.rollback() # end the read snapshot
with conn.cursor() as cur:
cur.execute("DROP TABLE AdbcExample")
See transactions for the details.
Errors
Errors are the PEP 249 exceptions that adbc_driver_manager.dbapi raises for each ADBC status,
also exported by spanner_adbc.dbapi. Errors lists the status for each Spanner error
code, and exc.details includes the numeric code as spanner.vendor_code.
DataFrames
fetch_arrow_table() and fetch_df() load the whole result into memory, and
fetch_record_batch() streams it while the cursor is open. With Polars 2.0, fetch_polars()
returns a struct Series rather than a DataFrame, so use pl.from_arrow(cur.fetch_arrow_table())
or pl.read_database() instead.
import spanner_adbc.dbapi as spanner
with spanner.connect("spanner:///projects/p/instances/i/databases/d") as conn:
with conn.cursor() as cur:
cur.execute("SELECT SingerId, FirstName FROM Singers")
with cur.fetch_record_batch() as reader:
for batch in reader:
print(batch.num_rows)
pandas and Polars accept the connection directly:
import pandas as pd
import polars as pl
import spanner_adbc.dbapi as spanner
with spanner.connect("spanner:///projects/p/instances/i/databases/d", autocommit=True) as conn:
frame = pd.read_sql("SELECT SingerId, FirstName FROM Singers", conn)
frame.to_sql("SingersCopy", conn, if_exists="append", index=False)
df = pl.read_database("SELECT SingerId, FirstName FROM Singers", connection=conn)
df.write_database("SingersCopy", connection=conn, if_table_exists="append")
pandas can't pass params to an ADBC connection, so bind parameters with cur.execute() and
cur.fetch_df() instead. pd.read_sql_table() and to_sql(if_exists="replace") fail because
pandas quotes table names with ", which GoogleSQL reads as a string. Polars'
read_database_uri() doesn't work either, since it looks for a module named
adbc_driver_spanner. Both libraries write through bulk ingest, so use
autocommit for large writes. In manual mode, end a read with conn.rollback() before writing.
Results follow the type mapping. Polars 2.0 reads JSON columns as
Extension('arrow.json', String). Spanner allows duplicate STRUCT field names: pandas and
DuckDB keep only the last field of each name, and Polars raises DuplicateError when unnesting
such a struct. pyarrow and Polars infer List(Null) for [] and [None], which bind
untyped.
DuckDB can query fetched Arrow data in-process:
import duckdb
import spanner_adbc.dbapi as spanner
with spanner.connect("spanner:///projects/p/instances/i/databases/d") as conn:
with conn.cursor() as cur:
cur.execute("SELECT SingerId, FirstName FROM Singers")
singers = cur.fetch_arrow_table()
print(duckdb.sql("SELECT COUNT(*) FROM singers").fetchall())
Bulk ingest
cur.adbc_ingest(table, data, mode=...) inserts Arrow data, or anything that exports the Arrow
PyCapsule interface, such as a Polars DataFrame:
import pyarrow as pa
import spanner_adbc.dbapi as spanner
data = pa.table({"SingerId": [10, 11], "FirstName": ["Carol", "Dave"]})
with spanner.connect("spanner:///projects/p/instances/i/databases/d", autocommit=True) as conn:
with conn.cursor() as cur:
rows = cur.adbc_ingest("Singers", data, mode="append")
The modes are create (the default), append, create_append and replace. Tables that ingest
creates have Spanner's hidden rowid as primary key, so create the table yourself to choose the
key.
With autocommit=True, ingest commits in chunks, so a failed load can leave rows behind. In
manual mode, ingest returns -1 and the rows apply at commit() in one commit, which Spanner caps
at 80,000 mutations: one per cell, plus index entries. Use autocommit for large loads, including
pandas' to_sql() and Polars' write_database().
Partitioned reads
adbc_execute_partitions() splits a query into partitions that any connection can read with
adbc_read_partition(), in parallel if you like. On Cloud Spanner, set
StatementOptions.DATA_BOOST to "true" on the partitioning cursor to read them on
Data Boost.
import spanner_adbc.dbapi as spanner
with spanner.connect("spanner:///projects/p/instances/i/databases/d") as conn:
with conn.cursor() as cur:
partitions, schema = cur.adbc_execute_partitions("SELECT SingerId FROM Singers")
for partition in partitions:
with conn.cursor() as cur:
cur.adbc_read_partition(partition)
table = cur.fetch_arrow_table()
Spanner only partitions some queries, such as simple scans; see reading data in parallel. Only read partitions from trusted sources: they aren't authenticated, as the limitations explain.
Loading by name
spanner.connect() loads the bundled library directly. To load the driver by name through
adbc_driver_manager 1.9.0 or later, install an ADBC driver manifest:
python -m spanner_adbc.manifest install # or spanner-adbc-install-manifest
import adbc_driver_manager.dbapi
with adbc_driver_manager.dbapi.connect(
driver="spanner", uri="spanner:///projects/p/instances/i/databases/d"
) as conn:
...
From version 1.11.0, driver can be left out, and the driver manager picks the driver from the
URI scheme. The manifest goes in <sys.prefix>/etc/adbc/drivers in a virtual environment and in
the user configuration directory otherwise, and python -m spanner_adbc.manifest path prints
where. It records the library's absolute path, so install it again after upgrading or moving the
environment. Use install --dir to write it into a directory on ADBC_DRIVER_PATH instead.
Supported platforms
| Platform | Wheel tag |
|---|---|
| Linux x86-64 and aarch64, glibc 2.35+ | manylinux_2_35 |
| Linux x86-64 and aarch64, musl 1.2+ | musllinux_1_2 |
| macOS 11+ arm64 | macosx_11_0_arm64 |
| macOS 10.15+ x86-64 | macosx_10_15_x86_64 |
| Windows x86-64 and arm64 | win_amd64, win_arm64 |
On other systems, build the library and package it yourself. The Python build doesn't compile
Rust; it packages the one library staged in python/spanner_adbc/, such as
libspanner_adbc.so on Linux:
cargo build --release --features strip-logging
cp target/release/libspanner_adbc.so python/spanner_adbc/
pip install './python[dbapi]'
The release wheels use the strip-logging feature too; without it, the library is larger but
behaves the same.
See CONTRIBUTING.md for development and releases.
Metadata
Release files for spanner-adbc 0.12.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| spanner_adbc-0.12.0-py3-none-win_arm64.whl | Python 3 | none | Windows ARM64 | Details |
| spanner_adbc-0.12.0-py3-none-win_amd64.whl | Python 3 | none | Windows x86-64 | Details |
| spanner_adbc-0.12.0-py3-none-musllinux_1_2_x86_64.whl | Python 3 | none | Linux musl 1.2+ x86-64 | Details |
| spanner_adbc-0.12.0-py3-none-musllinux_1_2_aarch64.whl | Python 3 | none | Linux musl 1.2+ ARM64 | Details |
| spanner_adbc-0.12.0-py3-none-manylinux_2_35_x86_64.whl | Python 3 | none | Linux glibc 2.35+ x86-64 | Details |
| spanner_adbc-0.12.0-py3-none-manylinux_2_35_aarch64.whl | Python 3 | none | Linux glibc 2.35+ ARM64 | Details |
| spanner_adbc-0.12.0-py3-none-macosx_11_0_arm64.whl | Python 3 | none | macOS 11.0+ ARM64 | Details |
| spanner_adbc-0.12.0-py3-none-macosx_10_15_x86_64.whl | Python 3 | none | macOS 10.15+ x86-64 | Details |
Total release size: 42.3 MB
Release files / spanner_adbc-0.12.0-py3-none-win_arm64.whl
| Download URL | spanner_adbc-0.12.0-py3-none-win_arm64.whl |
|---|---|
| Size | 5.4 MB |
| Tags | Python 3 Windows ARM64 |
|
SHA-256 checksum How to use checksums |
7337e0c00f2b1c63b98136c23ae616e56b52d220df00037fea0f050a7d0dd678
|
|
BLAKE2b-256 checksum How to use checksums |
573e31ed9529c9606415833c3d359178b4c2dbac9777c20ff0598484d93d080f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logRelease files / spanner_adbc-0.12.0-py3-none-win_amd64.whl
| Download URL | spanner_adbc-0.12.0-py3-none-win_amd64.whl |
|---|---|
| Size | 5.8 MB |
| Tags | Python 3 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
67026a4c36a7a82c7844c19869f591563fcac8f7f96f2fdca772fb30a13c69b6
|
|
BLAKE2b-256 checksum How to use checksums |
47eaead180cfd2d5c33a40600d0d71d63fef76ca99091e22c475e838765319c1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logRelease files / spanner_adbc-0.12.0-py3-none-musllinux_1_2_x86_64.whl
| Download URL | spanner_adbc-0.12.0-py3-none-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 5.4 MB |
| Tags | Linux musl 1.2+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
33e86f7668b2409a7cd448d7188a069e40e1b0500ca51d202e922acf64b9d409
|
|
BLAKE2b-256 checksum How to use checksums |
d5be67ea8adbbd7f9d2ff794809f2f67de3d4bf6b3af3412d9cd21acc7973f00
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logRelease files / spanner_adbc-0.12.0-py3-none-musllinux_1_2_aarch64.whl
| Download URL | spanner_adbc-0.12.0-py3-none-musllinux_1_2_aarch64.whl |
|---|---|
| Size | 5.1 MB |
| Tags | Linux musl 1.2+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
ecc34f80807a463ebfe3272cda99f34e1359fd9292dbb3dcce97b70e0bd7fb6e
|
|
BLAKE2b-256 checksum How to use checksums |
cb8b256ab77cf395afb07986822178180a0f37a6dbf1a0281a9ca751369cd1ac
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logRelease files / spanner_adbc-0.12.0-py3-none-manylinux_2_35_x86_64.whl
| Download URL | spanner_adbc-0.12.0-py3-none-manylinux_2_35_x86_64.whl |
|---|---|
| Size | 5.5 MB |
| Tags | Linux glibc 2.35+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
de4817dfe537727f6970f91c8b9e1dc2cad4986f77cfb3ce89493012365b4f8c
|
|
BLAKE2b-256 checksum How to use checksums |
4d2c05aee84f8cbcc9a6cded11723cdf781af609228b29d9d313ff5ccabae8d3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logRelease files / spanner_adbc-0.12.0-py3-none-manylinux_2_35_aarch64.whl
| Download URL | spanner_adbc-0.12.0-py3-none-manylinux_2_35_aarch64.whl |
|---|---|
| Size | 5.1 MB |
| Tags | Linux glibc 2.35+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
143f3d65f19b21aee1449650b0d0c724022b7738bea6f850766b183b4dbf68a6
|
|
BLAKE2b-256 checksum How to use checksums |
719a529d7d9db3431b1c8f4a892116e1d2afd0375fce219426aa1a0c366c5a4f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logRelease files / spanner_adbc-0.12.0-py3-none-macosx_11_0_arm64.whl
| Download URL | spanner_adbc-0.12.0-py3-none-macosx_11_0_arm64.whl |
|---|---|
| Size | 4.9 MB |
| Tags | Python 3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
e03fb5bfa49aa0d9b8b635c5c90f76cda010cf58f9581f5efb874a332202773d
|
|
BLAKE2b-256 checksum How to use checksums |
bf5656ae2251a38512672d3d78288d4cbb4d703adc58c475bf58a70b8c5a6c96
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logRelease files / spanner_adbc-0.12.0-py3-none-macosx_10_15_x86_64.whl
| Download URL | spanner_adbc-0.12.0-py3-none-macosx_10_15_x86_64.whl |
|---|---|
| Size | 5.2 MB |
| Tags | Python 3 macOS 10.15+ x86-64 |
|
SHA-256 checksum How to use checksums |
2ee943d885584fc4d63bae829f6f5fcd7a0e71111ef87cee0c7fd5e6db7e55b8
|
|
BLAKE2b-256 checksum How to use checksums |
a1a9b5d829e34d6e0a29e2d2e583f705a79bcee669b4d6f16eceefb7a320fddb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logSecurity for spanner-adbc 0.12.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 8 files in this release have been uploaded with provenance metadata.
Attestation for spanner_adbc-0.12.0-py3-none-win_arm64.whl
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.