Changelog¶
All notable changes to this project will be documented in this file.
[Unreleased]¶
[1.6.2] - 2026-08-03¶
Fixed¶
- Cancelling an in-flight async query no longer risks hanging the cancelling task forever. The cancellation path fired the driver's
adbc_canceland then immediately invalidated the connection, which closes it — without waiting for the aborted worker thread to come back out of the driver call. Closing a connection while a thread is still inside a call on it is the concurrent access ADBC forbids, and DuckDB deadlocked on it, wedging that worker permanently. Because the offload is deliberately non-abandoning, the awaiting task could then never complete: an enclosingmove_on_aftercould not rescue it, so a client disconnect during a query hung that request task and leaked a thread plus a connection. The poison-recovery now waits for the aborted worker to return before it drops the connection.
Affects AsyncCursor.execute, executemany, the fetch_* methods, adbc_ingest, adbc_execute_partitions, adbc_read_partition, and streaming pulls on AsyncRecordBatchReader — every path that invalidates on abort. The non-poisoning paths (adbc_prepare, adbc_execute_schema, metadata readers) never invalidated and were never affected. No API change.
- A cancellation that arrived just after its query finished no longer evicts a healthy connection. The watcher could not distinguish "the worker is still in the driver" from "the worker just finished", so it fired
adbc_cancelat a completed statement and ran the poison-recovery on a connection nothing had poisoned, dropping it from the pool. It now checks whether the worker is already out and leaves a finished call alone. The cancellation still propagates as before, so the only visible change is that the pool keeps a connection it used to discard.
Documentation¶
The guides were audited against a live database, and the corrections below are behavioural rather than editorial. If you followed any of these, your code was affected.
pre_pingwas documented as an inert no-op on the standaloneQueuePool. It is not inert:pre_ping=TrueraisesNotImplementedErroron the first re-checkout of a pooled connection. The first checkout succeeds, so this passes a smoke test and fails on the second request. Leave it at itsFalsedefault and userecycle.- Nothing said that pooled ADBC connections are not in autocommit mode. A write you never commit is rolled back when the connection checks in, silently and with the driver's row count already reported back to you. The async bulk-ingest example claimed "6 total" rows and then lost them. A new Committing writes section covers what to call and when.
- The SQLAlchemy ORM pattern has been removed rather than fixed.
creator=pool.connectcannot work with any dialect, because a dialect is written against one specific DBAPI and calls that driver's own extras on every connection. It is replaced by a working FastAPI lifespan example and an explanation of the limitation. adbc_execute_schemawas said to raiseNotSupportedErroron DuckDB. DuckDB implements it and returns a schema.- Several config fields were named wrongly:
SnowflakeConfighasoauth_tokenandauth_type(nottoken/authenticator),BigQueryConfighasauth_credentials(notauth_credentials_path), and the Snowflake schema keyword isschema, which its own alias requires —schema_=is rejected.MySQLConfig.databasewas documented as optional and is required. - The raw
driver_pathexample raisedImportError. A driver installed from PyPI ships no ADBC manifest, so a short name does not resolve to it; pass the package's own path helper, such asadbc_driver_duckdb.driver_path(). - Config validation errors surface as Pydantic's
ValidationError, not asConfigurationErrororPoolhouseError, because the validators run inside Pydantic.except PoolhouseErrornever fired there. Corrected across the ClickHouse, MySQL, Databricks and Databricks Python guides.
New coverage: async pool saturation and limiter sizing, choosing a recycle value against a warehouse idle timeout, FastAPI lifespan examples for both pools, a warning against calling the sync pool from an async def handler, and a note that non-ADBC connectors are not a supported extension point.
[1.6.1] - 2026-07-08¶
Added¶
pre_pingis now a field onBaseWarehouseConfig(defaultFalse), so it can be set on any config or loaded from the{PREFIX}_PRE_PINGenvironment variable — previously it was only acreate_poolkeyword. This completes the set of config-tunable pool fields.
Fixed¶
create_pool,managed_pool, and their async counterparts now honor a config's pool-tuning fields (pool_size,max_overflow,timeout,recycle,pre_ping). Previously these were read off the config but never forwarded, socreate_pool(SnowflakeConfig(pool_size=10))and the documentedSNOWFLAKE_POOL_SIZEenvironment override both silently produced a default-sized pool. Precedence is now: an explicitcreate_poolkeyword overrides the config field, which overrides the built-in default used by the raw driver paths.- Closed a related data-loss hazard:
create_pool(DuckDBConfig())(in-memory) previously built a 5-connection pool, giving each connection an isolated empty database. It now honors the config'spool_size=1.
Changed¶
DuckDBConfigandSQLiteConfignow defaultpool_sizeconditionally:1for an in-memory database (the only safe value for their per-connection isolation / shared-state semantics) and5for a file-backed database, matching the other backends. An explicitly setpool_size(keyword or environment) is respected as before. File-backed pools are unaffected in size; in-memory pools now correctly stay at 1 end to end.
[1.6.0] - 2026-07-08¶
Features¶
- Add
DatabricksPythonConfig, a Databricks backend built on thedatabricks-sql-connectorpackage rather than the ADBC driver. It connects over the connector's Statement Execution ("kernel") path instead of Thrift, which is what Lakehouse//RT requires — RT rejects the Thrift protocol that the ADBC and ODBC drivers use. Reach for it only when you need that non-Thrift path;DatabricksConfig(the ADBC driver) stays the default for ordinary SQL warehouses. - Install it with the new
databricks-pythonextra (pip install "adbc-poolhouse[databricks-python]"), which pulls indatabricks-sql-connector[pyarrow]. OAuth machine-to-machine auth also needsdatabricks-sdk; install thedatabricks-python-m2mextra for that, which layers the SDK on top of the base extra. - Supports the same auth methods as
DatabricksConfig: personal access token, OAuth U2M (browser), OAuth M2M (service principal), or a bring-your-owncredentials_providercallable. Fields load fromDATABRICKS_PYTHON_*environment variables, a separate namespace from theDATABRICKS_*prefixDatabricksConfiguses. Selecting OAuth M2M withoutdatabricks-sdkinstalled fails when the pool opens its first connection, with an error that points you at thedatabricks-python-m2mextra. - Pooled connections present the ADBC DBAPI cursor surface, so downstream query code is unchanged, and the backend works with both the sync pool and the async surface. The ADBC-only methods the connector has no equivalent for (
adbc_ingest,adbc_prepare,adbc_execute_partitions, theadbc_get_*metadata methods, and rawfetch_arrow) raiseNotSupportedError.
The existing ADBC backends and public API are unchanged; this release only adds the new backend, so upgrading from 1.5.x needs no code changes.
[1.5.1] - 2026-07-07¶
Features¶
- Add
adbc_execute_partitions()andadbc_read_partition()toAsyncCursor, closing the last gap in async/sync parity for the ADBC methods the sync raw-cursor path exposes. Both are thread-offloaded wrappers over the sync cursor: adbc_execute_partitions(operation, parameters=None)executes a query and returns(partitions, schema)— a list of opaque partition descriptors plus the result-set schema (orNone).adbc_read_partition(partition)reads one descriptor into the cursor's result set; drain it afterwards with the existing asyncfetch_*methods.- Both are cancellable and, like
execute, invalidate the connection on abort (partitioned execution runs the query, so it is poisoning — unlike the non-poisoningadbc_prepare/adbc_execute_schema). Partitioned execution is a distributed/Flight-SQL extension; backends that do not implement it (DuckDB, etc.) surface the driver's nativeNotSupportedErrorunchanged through the offload chokepoint.
The async API stays behind the [async] extra and is still experimental. The sync path is unchanged.
[1.5.0] - 2026-07-05¶
Features¶
- Complete the async cursor surface. The four cursor methods deferred in 1.4.0 are now available on
AsyncCursor, each a thread-offloaded wrapper over the underlying sync ADBC cursor: fetch_record_batch()returns anAsyncRecordBatchReaderfor lazy Arrow streaming (async for batch in reader:), with each batch pull offloaded individually. The reader's lifetime is bound to its checked-out connection; reading after checkin surfaces the driver's native closed-stream error.adbc_ingest(table_name, data, mode=...)bulk-writes Arrow data and returns the affected row count.modeis a typedLiteral; note thatmode="replace"drops the existing table.fetch_df()andfetch_polars()return apandas.DataFrame/polars.DataFrame. pandas and polars stay user-supplied — a missing dependency raises the nativeModuleNotFoundErrorunchanged.- Add the six
adbc_get_*connection metadata methods (adbc_get_info,adbc_get_objects,adbc_get_table_schema,adbc_get_table_types,adbc_get_statistics,adbc_get_statistic_names) onAsyncConnectionas offload wrappers; the streaming ones surface their nativeRecordBatchReader. - Add
adbc_prepare()andadbc_execute_schema()onAsyncCursor;adbc_execute_schema()returns the result Arrow schema without executing the query. - Cancelling or timing out any of these calls fires
adbc_cancelonce and, for the statefuladbc_ingest, invalidates the connection so the pool is never left poisoned. Reads and schema resolutions are cancellable but non-poisoning.
This completes async/sync parity for the ADBC methods the sync raw-cursor path exposes (partitioned result sets remain deferred). The async API stays behind the [async] extra and is still experimental. The sync path is unchanged.
[1.4.0] - 2026-07-01¶
Features¶
- Add an optional
[async]extra providing an anyio-based async surface (asyncio + trio). The async API is experimental: its surface may change between minor releases, and several features are not yet available. - Add the async entry points
create_async_pool,managed_async_pool, andclose_async_pool, mirroring the synccreate_pool/managed_pool/close_poolsignatures. - Add
AsyncPool,AsyncConnection, andAsyncCursorwrappers exposing the awaited DBAPI surface, includingfetch_arrow_table. Each blocking ADBC call runs on a worker thread. - Size each async pool with a per-pool
CapacityLimiterofpool_size + max_overflow, capping concurrent offloaded calls. - Shield connection checkin so a cancelled task returns its connection cleanly, and route query cancellation through
adbc_cancel.
The sync path is unchanged and gains no async dependency: installing without the [async] extra pulls in no anyio or trio.
[1.3.1] - 2026-06-24¶
Bug Fixes¶
- Propagate
catalogandschemato the Databricks connection (DBX-02).DatabricksConfig.to_adbc_kwargs()now appends URL-encoded?catalog=...&schema=...to the DSN in decomposed mode, so unqualified table and view names resolve against the configured default namespace instead of failing withTABLE_OR_VIEW_NOT_FOUND. URI mode is unchanged. Matches howSnowflakeConfigandTrinoConfigalready wire their namespace through.
[1.3.0] - 2026-05-21¶
Refactoring¶
- Route PyPI drivers through their own DBAPI module so pytest-adbc-replay monkeypatches intercept at the correct location
[1.1.0] - 2026-03-07¶
Bug Fixes¶
- Correct SQLite ADBC entrypoint to AdbcDriverSqliteInit
- Add --pre flag to ClickHouse dbc install; backfill SUMMARY requirements-completed
- Mark SQLT-01–05 and DBC-02 complete in REQUIREMENTS.md; fix traceability table
- Fix cassette test connect kwargs for recording
- Revise plan 04 per checker feedback
- Add autouse fixture clearing warehouse env vars before each test
- Use per-warehouse dotenv files in integration tests
- Resolve all v1.0 tech debt items
- Add version headers and filter noise from changelog
Features¶
- Add model_validator to DatabricksConfig (DBX-01)
- Implement decomposed-field URI in translate_databricks() (DBX-02)
- Add SQLiteConfig and translate_sqlite()
- Register SQLiteConfig in _PYPI_PACKAGES and translate_config
- Export SQLiteConfig and add sqlite optional extra
- Add install-dbc and install-foundry-drivers just recipes
- Create MySQLConfig Pydantic BaseSettings class
- Create translate_mysql() pure function
- Wire MySQLConfig into driver registry, translator dispatch, and public API
- Add individual field support to PostgreSQLConfig
- Add individual field support + full backend test coverage
- Implement ClickHouseConfig Pydantic BaseSettings model
- Implement translate_clickhouse() pure translator function
- Register ClickHouseConfig in _FOUNDRY_DRIVERS
- Wire ClickHouseConfig into translators and public API
- Add ClickHouse warehouse guide and update doc surfaces
- Add MySQL and ClickHouse to homepage table and config class list
- Migrate Snowflake/Databricks tests to pytest-adbc-replay cassettes
- Record Snowflake cassettes and unify dotenv loading
Miscellaneous¶
- Bump adbc-driver-manager floor to >=1.8.0
- Add duckdb extra to dev dependency group
- Pass --group docs to uv run in Justfile build/serve recipes
- Remove synthetic cassette files
- Bump version to 1.1.0
Testing¶
- Add SQLite config, translator, and pool-factory tests
- Add MySQLConfig, translate_mysql(), and pool-factory wiring tests
- Add TestPostgreSQLConfig for individual field support
- Add TestClickHouseConfig, TestClickHouseTranslator, and dispatch test
- Add test_clickhouse_returns_short_name and TestClickHousePoolFactory
[1.0.1] - 2026-02-28¶
Features¶
- Rewrite README.md as a consumer-facing landing page
Miscellaneous¶
- Add [project.urls] to pyproject.toml
- Bump version to 1.0.1 and update docs/README
[1.0.0] - 2026-02-28¶
Bug Fixes¶
- Set basedpyright pythonVersion to 3.11
- Add Foundry NOT_FOUND catch-and-reraise to _driver_api.py (DRIV-03)
- Revise plans based on checker feedback
- Revise plans based on checker feedback
- Add duckdb extra to CI sync and pin mkdocs-material<9.7.0
- Call main() unconditionally in gen_ref_pages.py
- Add --extra duckdb to pr workflow sync step
- Fix git-cliff install and config path in release workflow
- Use orhun/git-cliff-action instead of manual binary install
- Remove deploy-docs from release workflow
Features¶
- Declare runtime deps, optional extras, and dev deps
- Commit lock file covering all optional warehouse driver deps
- Add BaseWarehouseConfig abstract base and WarehouseConfig Protocol
- Add DuckDBConfig with in-memory pool_size validator
- Implement MSSQLConfig for SQL Server/Azure SQL/Fabric/Synapse
- Implement TeradataConfig with LOW-confidence source-attributed fields
- Add DatabricksConfig and RedshiftConfig
- Add TrinoConfig
- Add BigQueryConfig and PostgreSQLConfig
- Add FlightSQLConfig with gRPC, auth, TLS, and timeout fields
- Wire all config models into public API via init.py
- Add DuckDB and PostgreSQL translator functions
- Add BigQuery and FlightSQL translator functions
- Implement Foundry backend translators (Databricks, Redshift, Trino, MSSQL, Teradata)
- Add translate_config() dispatch coordinator (_translators.py)
- Add driver detection, ADBC facade, and type scaffold
- All driver detection tests pass
- Create exception hierarchy (_exceptions.py)
- Add _adbc_entrypoint to WarehouseConfig Protocol and BaseWarehouseConfig
- Update DuckDBConfig with ConfigurationError, _adbc_entrypoint, and bounds validators
- Add Snowflake snapshot test infrastructure
- Add Snowflake integration tests and CONTRIBUTING.md
- Create adbc-poolhouse-docs-author skill (TOOL-01)
- Create CLAUDE.md documentation quality gate (TOOL-02)
- Extend release.yml with TestPyPI, smoke test, and docs deploy jobs
- Complete config class docstrings with attribute docstrings
- Restructure mkdocs.yml nav and fix reference generation
- Add Databricks and Redshift warehouse guide pages
- Add Trino, MSSQL, and Teradata warehouse guide pages
- Export close_pool and managed_pool from init.py
- Add Warehouse Guides sub-section to mkdocs.yml nav
Miscellaneous¶
- Initial project structure from cookiecutter
- Add detect-secrets hook and generate baseline
- Resolve 8 audit items from v1.0 milestone
- Add docs/src/reference/ to gitignore
- Add justfile with build and serve recipes
- Bump the github-actions group with 5 updates
- Add --dirtyreload to justfile serve recipe
- Use --livereload flag in justfile serve recipe
- Add mkdocs watch paths for src and docs
- Bump version to 1.0.0
Testing¶
- Add config model unit tests for all 11 warehouse configs (TEST-04)
- Add failing translator unit tests
- Add failing tests for create_pool factory (RED)
- Complete UAT - 6 passed, 0 issues
- Complete UAT - 5 passed, 1 issue
- Diagnose UAT gap - addopts behavior, update marker docs
Ci¶
- Gate release on quality checks passing
Remove¶
- Drop TeradataConfig — no ADBC driver exists