adbc_poolhouse¶
adbc_poolhouse
¶
Connection pooling for ADBC drivers from typed warehouse configs.
BaseWarehouseConfig
¶
Bases: BaseSettings, ABC
Base class for all warehouse config models.
Provides pool tuning fields with library defaults. Not intended to be instantiated directly — use a concrete subclass (e.g. DuckDBConfig).
Pool tuning fields are inherited by all concrete configs, and each concrete config's env_prefix applies to these fields automatically. For example, DUCKDB_POOL_SIZE populates DuckDBConfig.pool_size.
pool_size
class-attribute
instance-attribute
¶
Number of connections to keep open in the pool. Default: 5.
max_overflow
class-attribute
instance-attribute
¶
Connections allowed above pool_size when pool is exhausted. Default: 3.
timeout
class-attribute
instance-attribute
¶
Seconds to wait for a connection before raising
sqlalchemy.exc.TimeoutError. Default: 30.
recycle
class-attribute
instance-attribute
¶
Seconds before a connection is closed and replaced. Default: 3600.
to_adbc_kwargs
abstractmethod
¶
Convert config to ADBC driver connection kwargs.
Subclasses must override this method to provide backend-specific serialization.
WarehouseConfig
¶
Bases: Protocol
Structural type for warehouse config objects.
Any class with these attributes and methods can be passed to
create_pool or managed_pool. The built-in config
classes all satisfy this protocol through
BaseWarehouseConfig.
Third-party authors: inherit from BaseWarehouseConfig
for pool-tuning defaults and _resolve_driver_path, or
implement the full protocol from scratch.
BigQueryConfig
¶
Bases: BaseWarehouseConfig
BigQuery warehouse configuration.
Supports SDK default auth (ADC), JSON credential file, JSON credential string, and user authentication flows.
Pool tuning fields are inherited and loaded from BIGQUERY_* env vars.
auth_type
class-attribute
instance-attribute
¶
Auth method: 'bigquery' (SDK default/ADC), 'json_credential_file', 'json_credential_string', 'user_authentication'. Env: BIGQUERY_AUTH_TYPE.
auth_credentials
class-attribute
instance-attribute
¶
JSON credentials file path or encoded credential string, depending on auth_type. Env: BIGQUERY_AUTH_CREDENTIALS.
auth_client_id
class-attribute
instance-attribute
¶
OAuth client ID for user_authentication flow. Env: BIGQUERY_AUTH_CLIENT_ID.
auth_client_secret
class-attribute
instance-attribute
¶
OAuth client secret for user_authentication flow. Env: BIGQUERY_AUTH_CLIENT_SECRET.
auth_refresh_token
class-attribute
instance-attribute
¶
OAuth refresh token for user_authentication flow. Env: BIGQUERY_AUTH_REFRESH_TOKEN.
project_id
class-attribute
instance-attribute
¶
GCP project ID. Env: BIGQUERY_PROJECT_ID.
dataset_id
class-attribute
instance-attribute
¶
Default dataset. Env: BIGQUERY_DATASET_ID.
to_adbc_kwargs
¶
Convert config to ADBC driver connection kwargs.
All keys use the adbc.bigquery.sql.* prefix verified from the
adbc_driver_bigquery.DatabaseOptions enum. Only non-None fields
are included.
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
Dict of ADBC driver kwargs. Empty when no fields are set. |
Source code in src/adbc_poolhouse/_bigquery_config.py
ClickHouseConfig
¶
Bases: BaseWarehouseConfig
ClickHouse warehouse configuration.
Uses the Columnar ADBC ClickHouse driver (Foundry-distributed, not on PyPI). Install via the ADBC Driver Foundry:
dbc install --pre clickhouse
The --pre flag is required — only alpha releases are available
(v0.1.0-alpha.1).
Supports two connection modes:
- URI mode: set
uriwith the full ClickHouse connection string. - Decomposed mode: set
hostandusernametogether.password,database, andportare optional.portdefaults to 8123 (HTTP interface).
At least one mode must be fully specified — construction raises
ConfigurationError if neither is provided.
Note: The field name is username, not user. The Columnar
ClickHouse driver uses username as the kwarg key. Passing user
causes a silent auth failure.
Pool tuning fields are inherited and loaded from CLICKHOUSE_* env vars.
Note: This driver is distributed via the ADBC Driver Foundry, not PyPI. See the installation guide for Foundry setup instructions.
uri
class-attribute
instance-attribute
¶
Full ClickHouse connection URI. May contain credentials — stored as SecretStr. Env: CLICKHOUSE_URI.
host
class-attribute
instance-attribute
¶
ClickHouse hostname. Alternative to embedding host in URI. Env: CLICKHOUSE_HOST.
port
class-attribute
instance-attribute
¶
ClickHouse HTTP interface port. Default: 8123. Env: CLICKHOUSE_PORT.
username
class-attribute
instance-attribute
¶
ClickHouse username. Maps to the username driver kwarg (not user).
Env: CLICKHOUSE_USERNAME.
password
class-attribute
instance-attribute
¶
ClickHouse password. Optional. Env: CLICKHOUSE_PASSWORD.
database
class-attribute
instance-attribute
¶
ClickHouse database name. Optional. Env: CLICKHOUSE_DATABASE.
to_adbc_kwargs
¶
Convert config to ADBC driver connection kwargs.
Supports two modes:
- URI mode (
uriset): returns{uri: ...}with the secret value extracted. - Decomposed mode (
host+usernameset): returns individual kwargs withportas a string.passwordanddatabaseare omitted whenNone.
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
Dict of ADBC driver kwargs for |
Source code in src/adbc_poolhouse/_clickhouse_config.py
check_connection_spec
¶
Raise ConfigurationError if neither uri nor minimum decomposed fields are set.
Source code in src/adbc_poolhouse/_clickhouse_config.py
DatabricksConfig
¶
Bases: BaseWarehouseConfig
Databricks warehouse configuration.
Uses the Columnar ADBC Databricks driver (Foundry-distributed, not on PyPI). Install via the ADBC Driver Foundry.
Supports PAT (personal access token) and OAuth (U2M and M2M) auth. Supports two connection modes:
- URI mode: set
uriwith the full DSN string. - Decomposed mode: set
host,http_path, andtokentogether.
At least one mode must be fully specified — construction raises
ConfigurationError if neither is provided.
Pool tuning fields are inherited and loaded from DATABRICKS_* env vars.
Note: This driver is distributed via the ADBC Driver Foundry, not PyPI. See the installation guide for Foundry setup instructions.
uri
class-attribute
instance-attribute
¶
Full connection URI: databricks://token:
host
class-attribute
instance-attribute
¶
Databricks workspace hostname (e.g. 'adb-xxx.azuredatabricks.net'). Alternative to embedding host in URI. Env: DATABRICKS_HOST.
http_path
class-attribute
instance-attribute
¶
SQL warehouse HTTP path (e.g. '/sql/1.0/warehouses/abc123'). Env: DATABRICKS_HTTP_PATH.
token
class-attribute
instance-attribute
¶
Personal access token for PAT auth. Env: DATABRICKS_TOKEN.
auth_type
class-attribute
instance-attribute
¶
OAuth auth type: 'OAuthU2M' (browser-based) or 'OAuthM2M' (service principal). Omit for PAT auth. Env: DATABRICKS_AUTH_TYPE.
client_id
class-attribute
instance-attribute
¶
OAuth M2M service principal client ID. Env: DATABRICKS_CLIENT_ID.
client_secret
class-attribute
instance-attribute
¶
OAuth M2M service principal client secret. Env: DATABRICKS_CLIENT_SECRET.
catalog
class-attribute
instance-attribute
¶
Default Unity Catalog. Env: DATABRICKS_CATALOG.
schema_
class-attribute
instance-attribute
¶
Default schema. Python attribute is schema_ to avoid Pydantic conflicts. Env: DATABRICKS_SCHEMA.
check_connection_spec
¶
Raise ConfigurationError if neither uri nor all minimum decomposed fields are set.
Source code in src/adbc_poolhouse/_databricks_config.py
to_adbc_kwargs
¶
Convert Databricks config fields to ADBC driver kwargs.
Supports two modes:
- URI mode (
uriset): extracts theSecretStrvalue and returns it verbatim as{"uri": ...}. The URI is never mutated, so any catalog/schema you want must already be in the DSN. - Decomposed mode: builds
databricks://token:{encoded}@{host}:443{http_path}fromhost,http_path, andtoken. The token is URL-encoded viaurllib.parse.quotewithsafe="". Whencatalogorschema_is set, each is appended to the DSN as a URL-encoded query parameter (?catalog=...&schema=...) so unqualified table and view names resolve against that default namespace. When both are unset, no query string is added.
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
ADBC driver kwargs for |
Source code in src/adbc_poolhouse/_databricks_config.py
DuckDBConfig
¶
Bases: BaseWarehouseConfig
DuckDB warehouse configuration.
Covers all DuckDB ADBC connection parameters. Pool tuning fields (pool_size, max_overflow, timeout, recycle) are inherited from BaseWarehouseConfig and loaded from DUCKDB_* environment variables.
Example
database
class-attribute
instance-attribute
¶
File path or ':memory:'. Env: DUCKDB_DATABASE.
pool_size
class-attribute
instance-attribute
¶
Number of connections in the pool. Default 1 for in-memory DuckDB.
In-memory DuckDB databases are isolated per connection — each pool connection gets a different empty DB. Use pool_size=1 for ':memory:', or set database to a file path if you need pool_size > 1. Setting pool_size > 1 with database=':memory:' raises ValidationError. Env: DUCKDB_POOL_SIZE.
read_only
class-attribute
instance-attribute
¶
Open the database in read-only mode. Env: DUCKDB_READ_ONLY.
to_adbc_kwargs
¶
Convert config to ADBC driver connection kwargs.
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
Dict with |
dict[str, str]
|
|
Source code in src/adbc_poolhouse/_duckdb_config.py
ConfigurationError
¶
Bases: PoolhouseError, ValueError
Raised when a config model contains invalid field values.
Inherits from both PoolhouseError (library hierarchy) and ValueError (pydantic model_validator compatibility). When raised inside a pydantic @model_validator, pydantic wraps it in ValidationError --- which itself inherits from ValueError --- satisfying 'raises ValueError' test expectations.
ConnectionBusyError
¶
Bases: PoolhouseError
Raised when one async connection is used concurrently from two tasks.
An ADBC connection permits serialized access (one call at a time) but not
concurrent access. Each AsyncConnection belongs to exactly one task for
its lifetime; sharing it across tasks in a task group is a bug. Rather than
silently serialize the calls --- which would still let two tasks' statements
interleave inside one transaction (driver-safe, logically corrupt) and hide
the bug --- the async layer rejects the second concurrent caller with this
error. The fix is to check out a separate connection per task from the pool.
Unlike ConfigurationError, this inherits PoolhouseError only (not
ValueError): it signals a runtime misuse of the connection, not an invalid
value.
Example
Initialize with the canonical message, or an override.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
str | None
|
Custom error text. Defaults to the canonical connection-aliasing message. |
None
|
Source code in src/adbc_poolhouse/_exceptions.py
PoolhouseError
¶
Bases: Exception
Base exception for all adbc-poolhouse errors.
All library-specific exceptions inherit from this class.
Consumers can use except PoolhouseError to catch any library error.
FlightSQLConfig
¶
Bases: BaseWarehouseConfig
FlightSQL warehouse configuration.
Connects to any Apache Arrow Flight SQL server (e.g. Dremio, InfluxDB, DuckDB server mode, custom Flight SQL implementations).
Pool tuning fields are inherited and loaded from FLIGHTSQL_* env vars.
uri
class-attribute
instance-attribute
¶
gRPC endpoint URI. Env: FLIGHTSQL_URI. Format: grpc://host:port (plaintext) or grpc+tls://host:port (TLS).
username
class-attribute
instance-attribute
¶
Username for HTTP-style basic auth. Env: FLIGHTSQL_USERNAME.
password
class-attribute
instance-attribute
¶
Password for HTTP-style basic auth. Env: FLIGHTSQL_PASSWORD.
authorization_header
class-attribute
instance-attribute
¶
Custom authorization header value (overrides username/password if set). Env: FLIGHTSQL_AUTHORIZATION_HEADER.
mtls_cert_chain
class-attribute
instance-attribute
¶
mTLS certificate chain (PEM). Env: FLIGHTSQL_MTLS_CERT_CHAIN.
mtls_private_key
class-attribute
instance-attribute
¶
mTLS private key (PEM). Env: FLIGHTSQL_MTLS_PRIVATE_KEY.
tls_root_certs
class-attribute
instance-attribute
¶
Root CA certificate(s) in PEM format. Env: FLIGHTSQL_TLS_ROOT_CERTS.
tls_skip_verify
class-attribute
instance-attribute
¶
Disable TLS certificate verification. Env: FLIGHTSQL_TLS_SKIP_VERIFY.
tls_override_hostname
class-attribute
instance-attribute
¶
Override the TLS hostname for SNI. Env: FLIGHTSQL_TLS_OVERRIDE_HOSTNAME.
connect_timeout
class-attribute
instance-attribute
¶
Connection timeout in seconds. Env: FLIGHTSQL_CONNECT_TIMEOUT.
query_timeout
class-attribute
instance-attribute
¶
Query execution timeout in seconds. Env: FLIGHTSQL_QUERY_TIMEOUT.
fetch_timeout
class-attribute
instance-attribute
¶
Result fetch timeout in seconds. Env: FLIGHTSQL_FETCH_TIMEOUT.
update_timeout
class-attribute
instance-attribute
¶
DML update timeout in seconds. Env: FLIGHTSQL_UPDATE_TIMEOUT.
authority
class-attribute
instance-attribute
¶
Override gRPC authority header. Env: FLIGHTSQL_AUTHORITY.
max_msg_size
class-attribute
instance-attribute
¶
Maximum gRPC message size in bytes (driver default: 16 MiB). Env: FLIGHTSQL_MAX_MSG_SIZE.
with_cookie_middleware
class-attribute
instance-attribute
¶
Enable gRPC cookie middleware (required by some servers for session management). Env: FLIGHTSQL_WITH_COOKIE_MIDDLEWARE.
to_adbc_kwargs
¶
Convert config to ADBC driver connection kwargs.
Maps FlightSQL config fields to their adbc.flight.sql.* key
equivalents. Boolean defaults (tls_skip_verify,
with_cookie_middleware) are always included as 'true'/
'false' strings. Optional fields are omitted when None.
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
Dict of ADBC driver kwargs for |
Source code in src/adbc_poolhouse/_flightsql_config.py
MSSQLConfig
¶
Bases: BaseWarehouseConfig
Microsoft SQL Server / Azure SQL / Azure Fabric / Synapse Analytics configuration.
Uses the Columnar ADBC MSSQL driver (Foundry-distributed, not on PyPI). One class covers all Microsoft SQL variants via optional variant-specific fields: - SQL Server: use host + port + instance (or URI) - Azure SQL: use host + port, optionally fedauth for Entra ID / Azure AD auth - Azure Fabric / Synapse Analytics: use fedauth for managed identity or service principal authentication
Pool tuning fields are inherited and loaded from MSSQL_* env vars.
Note: This driver is distributed via the ADBC Driver Foundry, not PyPI. See the installation guide for Foundry setup instructions.
uri
class-attribute
instance-attribute
¶
Connection URI. Format: mssql://user:pass@host[:port][/instance][?params] # pragma: allowlist secret
Also accepts the sqlserver:// scheme. Env: MSSQL_URI.
host
class-attribute
instance-attribute
¶
Hostname or IP address. Alternative to URI-based connection. Env: MSSQL_HOST.
port
class-attribute
instance-attribute
¶
Port number. Default: 1433. Env: MSSQL_PORT.
instance
class-attribute
instance-attribute
¶
SQL Server named instance (e.g. 'SQLExpress'). Env: MSSQL_INSTANCE.
user
class-attribute
instance-attribute
¶
SQL auth username. Env: MSSQL_USER.
password
class-attribute
instance-attribute
¶
SQL auth password. Env: MSSQL_PASSWORD.
database
class-attribute
instance-attribute
¶
Target database name. Env: MSSQL_DATABASE.
trust_server_certificate
class-attribute
instance-attribute
¶
Accept self-signed TLS certificates. Enable for local development. Env: MSSQL_TRUST_SERVER_CERTIFICATE.
connection_timeout
class-attribute
instance-attribute
¶
Connection timeout in seconds. Env: MSSQL_CONNECTION_TIMEOUT.
fedauth
class-attribute
instance-attribute
¶
Federated authentication method for Entra ID / Azure AD. Used for Azure SQL, Azure Fabric, and Synapse Analytics. Values: 'ActiveDirectoryPassword', 'ActiveDirectoryMsi', 'ActiveDirectoryServicePrincipal', 'ActiveDirectoryInteractive'. Env: MSSQL_FEDAUTH.
to_adbc_kwargs
¶
Convert config to ADBC driver connection kwargs.
Supports two modes:
- URI mode (
uriset): returns{uri: ...}. - Decomposed mode: maps individual fields to their ADBC key
equivalents.
trust_server_certificateis always included as a'true'/'false'string.
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
Dict of ADBC driver kwargs for |
Source code in src/adbc_poolhouse/_mssql_config.py
MySQLConfig
¶
Bases: BaseWarehouseConfig
MySQL warehouse configuration.
Uses the Columnar ADBC MySQL driver (Foundry-distributed, not on PyPI). Install via the ADBC Driver Foundry (see DEVELOP.md for setup instructions).
Supports two connection modes:
- URI mode: set
uriwith the full MySQL connection string. - Decomposed mode: set
host,user, anddatabasetogether.passwordis optional — MySQL supports passwordless connections.portdefaults to 3306.
At least one mode must be fully specified — construction raises
ConfigurationError if neither is provided.
Pool tuning fields are inherited and loaded from MYSQL_* env vars.
Note: This driver is distributed via the ADBC Driver Foundry, not PyPI. See the installation guide for Foundry setup instructions.
uri
class-attribute
instance-attribute
¶
Full MySQL connection URI. May contain credentials — stored as SecretStr. Env: MYSQL_URI.
host
class-attribute
instance-attribute
¶
MySQL hostname. Alternative to embedding host in URI. Env: MYSQL_HOST.
port
class-attribute
instance-attribute
¶
MySQL port. Default: 3306. Env: MYSQL_PORT.
password
class-attribute
instance-attribute
¶
MySQL password. Optional — MySQL supports passwordless connections. Env: MYSQL_PASSWORD.
database
class-attribute
instance-attribute
¶
MySQL database name. Env: MYSQL_DATABASE.
check_connection_spec
¶
Raise ConfigurationError if neither uri nor all minimum decomposed fields are set.
Source code in src/adbc_poolhouse/_mysql_config.py
to_adbc_kwargs
¶
Convert MySQL config fields to ADBC driver kwargs.
Supports two modes:
- URI mode (
uriset): extractsSecretStrvalue and returns{"uri": ...}. - Decomposed mode: builds a Go DSN from
user,password,host,port, anddatabase. Password is URL-encoded viaurllib.parse.quotewithsafe="".
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
ADBC driver kwargs for |
Source code in src/adbc_poolhouse/_mysql_config.py
PostgreSQLConfig
¶
Bases: BaseWarehouseConfig
PostgreSQL warehouse configuration.
The PostgreSQL ADBC driver wraps libpq. Specify the connection either as
a full URI or via individual fields. If neither is provided, libpq falls
back to its own environment variables (PGHOST, PGUSER, etc.).
Pool tuning fields are inherited and loaded from POSTGRESQL_* env vars.
Example
uri
class-attribute
instance-attribute
¶
libpq connection URI. Takes precedence over individual fields.
Format: postgresql://[user[:password]@][host][:port][/dbname][?params]
Env: POSTGRESQL_URI.
host
class-attribute
instance-attribute
¶
Database hostname or IP address. Env: POSTGRESQL_HOST.
port
class-attribute
instance-attribute
¶
Database port. Defaults to 5432 when omitted. Env: POSTGRESQL_PORT.
user
class-attribute
instance-attribute
¶
Database username. Env: POSTGRESQL_USER.
password
class-attribute
instance-attribute
¶
Database password. Env: POSTGRESQL_PASSWORD.
database
class-attribute
instance-attribute
¶
Database name. Env: POSTGRESQL_DATABASE.
sslmode
class-attribute
instance-attribute
¶
SSL mode. Accepted values: disable, allow, prefer,
require, verify-ca, verify-full. Env: POSTGRESQL_SSLMODE.
use_copy
class-attribute
instance-attribute
¶
Use PostgreSQL COPY protocol for bulk query execution (driver default: True). Disable if COPY triggers permission errors. Env: POSTGRESQL_USE_COPY.
to_adbc_kwargs
¶
Convert PostgreSQL config fields to ADBC driver kwargs.
Supports three modes:
- URI mode (
uriset): passed directly as{"uri": ...}. - Decomposed mode: builds a libpq URI from
host,port,user,password,database, andsslmode. Password is URL-encoded viaurllib.parse.quotewithsafe="". - Empty mode: returns
{}so libpq resolves from env vars.
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
ADBC driver kwargs for |
Source code in src/adbc_poolhouse/_postgresql_config.py
QuackConfig
¶
Bases: BaseWarehouseConfig
Quack warehouse configuration.
Targets the DuckDB Quack remote protocol via the
adbc-driver-quack PyPI
driver. The driver is on an alpha release track, so install with the
--pre flag (the version constraint is in pyproject.toml):
pip install --pre adbc-poolhouse[quack]
Two connection modes are supported:
- URI mode: set
urito a fullquack://host[:port]string. - Decomposed mode: set
hostand optionallyport. The URI is rebuilt asquack://{host}:{port}whenportis set, orquack://{host}whenportisNone.
Exactly one mode must be specified. Setting both uri and host,
or neither, raises ConfigurationError (wrapped as a
pydantic ValidationError).
The driver's URI cannot embed credentials, so uri is a plain
str (not SecretStr). The token field passes via the
adbc.quack.token kwarg and is never embedded in the URI. The
tls flag emits adbc.quack.tls only when True — when False
(the default), the kwarg is omitted entirely so the driver's own
default applies.
Pool tuning fields are inherited and loaded from QUACK_* env vars.
Example
See create_pool for pool creation.
uri
class-attribute
instance-attribute
¶
Full connection URI quack://host[:port]. The driver's URI cannot
embed credentials, so this is a plain str (not SecretStr). Env: QUACK_URI.
host
class-attribute
instance-attribute
¶
Quack server hostname. Alternative to URI mode. Env: QUACK_HOST.
port
class-attribute
instance-attribute
¶
Quack server port. Optional even in decomposed mode. Env: QUACK_PORT.
token
class-attribute
instance-attribute
¶
Bearer token. Passes via adbc.quack.token kwarg, never embedded
in the URI, never URL-encoded. Env: QUACK_TOKEN.
tls
class-attribute
instance-attribute
¶
Enable TLS. When False (default), the adbc.quack.tls kwarg is
omitted entirely (driver default is "false"). Env: QUACK_TLS.
check_connection_spec
¶
Raise ConfigurationError when both modes are set or neither is set.
Source code in src/adbc_poolhouse/_quack_config.py
to_adbc_kwargs
¶
Convert config to ADBC driver connection kwargs.
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
A dict with |
dict[str, str]
|
when |
dict[str, str]
|
|
Source code in src/adbc_poolhouse/_quack_config.py
RedshiftConfig
¶
Bases: BaseWarehouseConfig
Redshift warehouse configuration.
Uses the Columnar ADBC Redshift driver (Foundry-distributed, not on PyPI). Supports provisioned clusters (standard and IAM auth) and Redshift Serverless.
Pool tuning fields are inherited and loaded from REDSHIFT_* env vars.
Note: This driver is distributed via the ADBC Driver Foundry, not PyPI. See the installation guide for Foundry setup instructions.
uri
class-attribute
instance-attribute
¶
Connection URI: redshift://[user:password@]host[:port]/dbname[?params] Use redshift:///dbname for automatic endpoint discovery. Env: REDSHIFT_URI.
host
class-attribute
instance-attribute
¶
Redshift cluster hostname. Alternative to URI. Env: REDSHIFT_HOST.
port
class-attribute
instance-attribute
¶
Port number. Default: 5439. Env: REDSHIFT_PORT.
user
class-attribute
instance-attribute
¶
Database username. Env: REDSHIFT_USER.
password
class-attribute
instance-attribute
¶
Database password. Env: REDSHIFT_PASSWORD.
database
class-attribute
instance-attribute
¶
Target database name. Env: REDSHIFT_DATABASE.
cluster_type
class-attribute
instance-attribute
¶
Cluster variant: 'redshift' (standard), 'redshift-iam', or 'redshift-serverless'. Env: REDSHIFT_CLUSTER_TYPE.
cluster_identifier
class-attribute
instance-attribute
¶
Provisioned cluster identifier (required for IAM auth). Env: REDSHIFT_CLUSTER_IDENTIFIER.
workgroup_name
class-attribute
instance-attribute
¶
Serverless workgroup name. Env: REDSHIFT_WORKGROUP_NAME.
aws_region
class-attribute
instance-attribute
¶
AWS region (e.g. 'us-west-2'). Env: REDSHIFT_AWS_REGION.
aws_access_key_id
class-attribute
instance-attribute
¶
AWS IAM access key ID. Env: REDSHIFT_AWS_ACCESS_KEY_ID.
aws_secret_access_key
class-attribute
instance-attribute
¶
AWS IAM secret access key. Env: REDSHIFT_AWS_SECRET_ACCESS_KEY.
sslmode
class-attribute
instance-attribute
¶
SSL mode (e.g. 'require', 'verify-full'). Env: REDSHIFT_SSLMODE.
to_adbc_kwargs
¶
Convert Redshift config fields to ADBC driver kwargs.
Supports two connection modes:
- URI mode (
uriset): passed directly as{"uri": ...}. - Decomposed mode: builds a
redshift://URI fromhost,port,user,password,database, andsslmode. Password is URL-encoded viaurllib.parse.quotewithsafe="".
IAM and cluster fields (cluster_type, cluster_identifier,
workgroup_name, aws_region, aws_access_key_id,
aws_secret_access_key) are always translated as separate driver
kwargs when set, regardless of connection mode.
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
ADBC driver kwargs for |
Source code in src/adbc_poolhouse/_redshift_config.py
SnowflakeConfig
¶
Bases: BaseWarehouseConfig
Snowflake warehouse configuration.
Supports all authentication methods provided by adbc-driver-snowflake: password, JWT (private_key_path / private_key_pem), external browser, OAuth, MFA, Okta, PAT, and workload identity federation (WIF).
Pool tuning fields (pool_size, max_overflow, timeout, recycle) are inherited and loaded from SNOWFLAKE_* environment variables.
Example
account
instance-attribute
¶
Snowflake account identifier (e.g. 'myorg-myaccount'). Env: SNOWFLAKE_ACCOUNT.
user
class-attribute
instance-attribute
¶
Username. Required for most auth methods. Env: SNOWFLAKE_USER.
password
class-attribute
instance-attribute
¶
Password for basic auth. Env: SNOWFLAKE_PASSWORD.
auth_type
class-attribute
instance-attribute
¶
Auth method: auth_jwt, auth_ext_browser, auth_oauth, auth_mfa, auth_okta, auth_pat, auth_wif. Env: SNOWFLAKE_AUTH_TYPE.
private_key_path
class-attribute
instance-attribute
¶
File path to a PKCS1 or PKCS8 private key file. Mutually exclusive with private_key_pem. Env: SNOWFLAKE_PRIVATE_KEY_PATH.
private_key_pem
class-attribute
instance-attribute
¶
Inline PEM-encoded PKCS8 private key (encrypted or unencrypted). Mutually exclusive with private_key_path. Env: SNOWFLAKE_PRIVATE_KEY_PEM.
private_key_passphrase
class-attribute
instance-attribute
¶
Passphrase to decrypt an encrypted PKCS8 key. Env: SNOWFLAKE_PRIVATE_KEY_PASSPHRASE.
jwt_expire_timeout
class-attribute
instance-attribute
¶
JWT expiry duration (e.g. '300ms', '1m30s'). Env: SNOWFLAKE_JWT_EXPIRE_TIMEOUT.
oauth_token
class-attribute
instance-attribute
¶
Bearer token for auth_oauth. Env: SNOWFLAKE_OAUTH_TOKEN.
okta_url
class-attribute
instance-attribute
¶
Okta server URL required for auth_okta. Env: SNOWFLAKE_OKTA_URL.
identity_provider
class-attribute
instance-attribute
¶
Identity provider for auth_wif. Env: SNOWFLAKE_IDENTITY_PROVIDER.
database
class-attribute
instance-attribute
¶
Default database. Env: SNOWFLAKE_DATABASE.
schema_
class-attribute
instance-attribute
¶
Default schema. Python attribute is schema_ to avoid Pydantic conflicts; env var is SNOWFLAKE_SCHEMA. Env: SNOWFLAKE_SCHEMA.
warehouse
class-attribute
instance-attribute
¶
Snowflake virtual warehouse. Env: SNOWFLAKE_WAREHOUSE.
role
class-attribute
instance-attribute
¶
Snowflake role. Env: SNOWFLAKE_ROLE.
region
class-attribute
instance-attribute
¶
Snowflake region (if not embedded in account). Env: SNOWFLAKE_REGION.
host
class-attribute
instance-attribute
¶
Explicit hostname (alternative to account-derived URI). Env: SNOWFLAKE_HOST.
port
class-attribute
instance-attribute
¶
Connection port. Env: SNOWFLAKE_PORT.
protocol
class-attribute
instance-attribute
¶
Protocol: 'http' or 'https'. Env: SNOWFLAKE_PROTOCOL.
login_timeout
class-attribute
instance-attribute
¶
Login retry timeout duration string. Env: SNOWFLAKE_LOGIN_TIMEOUT.
request_timeout
class-attribute
instance-attribute
¶
Request retry timeout duration string. Env: SNOWFLAKE_REQUEST_TIMEOUT.
client_timeout
class-attribute
instance-attribute
¶
Network roundtrip timeout duration string. Env: SNOWFLAKE_CLIENT_TIMEOUT.
tls_skip_verify
class-attribute
instance-attribute
¶
Disable TLS certificate verification. Env: SNOWFLAKE_TLS_SKIP_VERIFY.
ocsp_fail_open_mode
class-attribute
instance-attribute
¶
OCSP fail-open mode (True = allow connection on OCSP errors). Env: SNOWFLAKE_OCSP_FAIL_OPEN_MODE.
keep_session_alive
class-attribute
instance-attribute
¶
Prevent session expiry during long operations. Env: SNOWFLAKE_KEEP_SESSION_ALIVE.
app_name
class-attribute
instance-attribute
¶
Application identifier sent to Snowflake. Env: SNOWFLAKE_APP_NAME.
disable_telemetry
class-attribute
instance-attribute
¶
Disable Snowflake usage telemetry. Env: SNOWFLAKE_DISABLE_TELEMETRY.
cache_mfa_token
class-attribute
instance-attribute
¶
Cache MFA token for subsequent connections. Env: SNOWFLAKE_CACHE_MFA_TOKEN.
store_temp_creds
class-attribute
instance-attribute
¶
Cache ID token for SSO. Env: SNOWFLAKE_STORE_TEMP_CREDS.
check_private_key_exclusion
¶
Raise ValidationError if both private_key_path and private_key_pem are set.
Source code in src/adbc_poolhouse/_snowflake_config.py
to_adbc_kwargs
¶
Convert config to ADBC driver connection kwargs.
Returns a dict[str, str] suitable for passing as db_kwargs to
adbc_driver_manager.dbapi.connect(). All values are strings;
None fields are omitted. Boolean fields are always included as
'true'/'false' strings.
Key names follow adbc_driver_snowflake DatabaseOptions and
AuthType enums. 'username' and 'password' are plain
string keys (not prefixed with 'adbc.snowflake.sql.*').
Source code in src/adbc_poolhouse/_snowflake_config.py
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | |
SQLiteConfig
¶
Bases: BaseWarehouseConfig
SQLite warehouse configuration.
Covers SQLite ADBC connection parameters. Pool tuning fields (pool_size, max_overflow, timeout, recycle) are inherited from BaseWarehouseConfig and loaded from SQLITE_* environment variables.
Unlike DuckDB, an SQLite in-memory database is shared across all connections in the pool. This means pool_size > 1 with database=':memory:' is almost always unintended (connection state races across a single shared DB), so it is rejected by a validator.
Example
database
class-attribute
instance-attribute
¶
File path or ':memory:'. Env: SQLITE_DATABASE.
pool_size
class-attribute
instance-attribute
¶
Number of connections in the pool. Default 1 for in-memory SQLite.
SQLite in-memory databases are shared across all connections in the pool — unlike DuckDB, where each connection gets its own isolated empty DB. Use pool_size=1 for ':memory:', or set database to a file path if you need pool_size > 1. Setting pool_size > 1 with database=':memory:' raises ValidationError. Env: SQLITE_POOL_SIZE.
to_adbc_kwargs
¶
Convert config to ADBC driver connection kwargs.
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
Dict with a single |
dict[str, str]
|
(or |
Source code in src/adbc_poolhouse/_sqlite_config.py
TrinoConfig
¶
Bases: BaseWarehouseConfig
Trino warehouse configuration.
Uses the Columnar ADBC Trino driver (Foundry-distributed, not on PyPI). Supports URI-based or decomposed field connection specification.
Pool tuning fields are inherited and loaded from TRINO_* env vars.
Note: This driver is distributed via the ADBC Driver Foundry, not PyPI. See the installation guide for Foundry setup instructions.
uri
class-attribute
instance-attribute
¶
Connection URI. Format: trino://[user[:password]@]host[:port][/catalog[/schema]][?params]
Env: TRINO_URI.
host
class-attribute
instance-attribute
¶
Trino coordinator hostname. Alternative to URI. Env: TRINO_HOST.
port
class-attribute
instance-attribute
¶
Trino coordinator port. Defaults: 8080 (HTTP), 8443 (HTTPS). Env: TRINO_PORT.
password
class-attribute
instance-attribute
¶
Password (HTTPS connections only). Env: TRINO_PASSWORD.
catalog
class-attribute
instance-attribute
¶
Default catalog. Env: TRINO_CATALOG.
schema_
class-attribute
instance-attribute
¶
Default schema. Python attribute is schema_ to avoid Pydantic conflicts. Env: TRINO_SCHEMA.
ssl
class-attribute
instance-attribute
¶
Use HTTPS. Disable for local development clusters. Env: TRINO_SSL.
ssl_verify
class-attribute
instance-attribute
¶
Verify SSL certificate. Env: TRINO_SSL_VERIFY.
source
class-attribute
instance-attribute
¶
Application identifier sent to Trino coordinator. Env: TRINO_SOURCE.
to_adbc_kwargs
¶
Convert config to ADBC driver connection kwargs.
Supports two modes:
- URI mode (
uriset): returns{uri: ...}. - Decomposed mode: maps individual fields to their ADBC key
equivalents. Boolean defaults (
ssl,ssl_verify) are always included as'true'/'false'strings.
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
Dict of ADBC driver kwargs for |
Source code in src/adbc_poolhouse/_trino_config.py
close_pool
¶
Dispose a pool and close its underlying ADBC source connection.
Replaces the two-step pattern pool.dispose() followed by
pool._adbc_source.close(). Always call this instead of calling
pool.dispose() directly to avoid leaving the ADBC source connection open.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pool
|
QueuePool
|
A pool returned by |
required |
Example
Source code in src/adbc_poolhouse/_pool_factory.py
create_pool
¶
create_pool(
config: WarehouseConfig,
*,
pool_size: int = 5,
max_overflow: int = 3,
timeout: int = 30,
recycle: int = 3600,
pre_ping: bool = False,
) -> sqlalchemy.pool.QueuePool
Create a SQLAlchemy QueuePool backed by an ADBC driver.
Three call patterns are supported:
pool = create_pool(DuckDBConfig(...)) # from a config object
pool = create_pool(driver_path="...", ...) # native ADBC driver
pool = create_pool(dbapi_module="...", ...) # Python dbapi module
The config path extracts driver information from the config object's methods. The two raw paths accept driver arguments directly, bypassing config objects entirely.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
WarehouseConfig | None
|
A warehouse config model instance (e.g. |
None
|
driver_path
|
str | None
|
Path to a native ADBC driver shared library, or a
short driver name for manifest-based resolution. Requires
|
None
|
db_kwargs
|
dict[str, str] | None
|
ADBC connection keyword arguments as |
None
|
entrypoint
|
str | None
|
ADBC entry-point symbol. Only used with |
None
|
dbapi_module
|
str | None
|
Dotted module name for a Python package implementing
the ADBC dbapi interface (e.g. |
None
|
pool_size
|
int
|
Number of connections to keep in the pool. Default: 5. |
5
|
max_overflow
|
int
|
Extra connections allowed above pool_size. Default: 3. |
3
|
timeout
|
int
|
Seconds to wait for a connection before raising. Default: 30. |
30
|
recycle
|
int
|
Seconds before a connection is recycled. Default: 3600. |
3600
|
pre_ping
|
bool
|
Whether to ping connections before checkout. Default: False. Pre-ping does not function on a standalone QueuePool without a SQLAlchemy dialect; recycle is the preferred health mechanism. |
False
|
Returns:
| Type | Description |
|---|---|
QueuePool
|
A configured |
Raises:
| Type | Description |
|---|---|
TypeError
|
If none of |
ImportError
|
If the required ADBC driver is not installed. |
Example
Config path:
from adbc_poolhouse import create_pool, close_pool
from adbc_poolhouse import DuckDBConfig
pool = create_pool(DuckDBConfig(database="/tmp/my.db"))
close_pool(pool)
Raw native driver path:
Source code in src/adbc_poolhouse/_pool_factory.py
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | |
managed_pool
¶
managed_pool(
config: WarehouseConfig,
*,
pool_size: int = 5,
max_overflow: int = 3,
timeout: int = 30,
recycle: int = 3600,
pre_ping: bool = False,
) -> contextlib.AbstractContextManager[
sqlalchemy.pool.QueuePool
]
Context manager that creates a pool and closes it on exit.
The pool is created when the with block is entered and disposed
(via close_pool) when the block exits, whether normally or by
exception.
Three call patterns are supported:
with managed_pool(DuckDBConfig(...)) as pool: ... # config
with managed_pool(driver_path="...", ...) as pool: ... # native
with managed_pool(dbapi_module="...", ...) as pool: ... # dbapi
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
WarehouseConfig | None
|
A warehouse config model instance (e.g. |
None
|
driver_path
|
str | None
|
Path to a native ADBC driver shared library, or a
short driver name for manifest-based resolution. Requires
|
None
|
db_kwargs
|
dict[str, str] | None
|
ADBC connection keyword arguments as |
None
|
entrypoint
|
str | None
|
ADBC entry-point symbol. Only used with |
None
|
dbapi_module
|
str | None
|
Dotted module name for a Python package implementing
the ADBC dbapi interface (e.g. |
None
|
pool_size
|
int
|
Number of connections to keep in the pool. Default: 5. |
5
|
max_overflow
|
int
|
Extra connections allowed above pool_size. Default: 3. |
3
|
timeout
|
int
|
Seconds to wait for a connection before raising. Default: 30. |
30
|
recycle
|
int
|
Seconds before a connection is recycled. Default: 3600. |
3600
|
pre_ping
|
bool
|
Whether to ping connections before checkout. Default: False. |
False
|
Yields:
| Type | Description |
|---|---|
QueuePool
|
A configured |
QueuePool
|
closed when the |
Raises:
| Type | Description |
|---|---|
TypeError
|
If none of |
ImportError
|
If the required ADBC driver is not installed. |
Example
Config path:
from adbc_poolhouse import DuckDBConfig, managed_pool
with managed_pool(DuckDBConfig(database="/tmp/wh.db")) as pool:
with pool.connect() as conn:
cursor = conn.cursor()
cursor.execute("SELECT 1")
Raw native driver path:
Source code in src/adbc_poolhouse/_pool_factory.py
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 | |
close_async_pool
async
¶
Dispose an AsyncPool and close its underlying ADBC source.
The async analog of close_pool. The blocking
teardown runs on a worker thread inside a shielded cancel scope (in
AsyncPool.close), so a cancellation cannot abandon the pool mid-close and
leak driver resources.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pool
|
AsyncPool
|
A pool returned by |
required |
Example
Source code in src/adbc_poolhouse/_async/_factory.py
create_async_pool
¶
create_async_pool(
config: WarehouseConfig,
*,
pool_size: int = 5,
max_overflow: int = 3,
timeout: int = 30,
recycle: int = 3600,
pre_ping: bool = False,
) -> AsyncPool
Create an AsyncPool backed by an ADBC driver.
The signature mirrors create_pool exactly,
with the same three call patterns and keyword defaults. The pool is built
synchronously by the shared sync core (_create_pool_impl), then wrapped in an
AsyncPool that owns a dedicated anyio.CapacityLimiter(pool_size +
max_overflow). There is no per-backend code, so any of the supported
warehouse configs works.
Three call patterns are supported:
pool = create_async_pool(DuckDBConfig(...)) # from a config object
pool = create_async_pool(driver_path="...", ...) # native ADBC driver
pool = create_async_pool(dbapi_module="...", ...) # Python dbapi module
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
WarehouseConfig | None
|
A warehouse config model instance (e.g. |
None
|
driver_path
|
str | None
|
Path to a native ADBC driver shared library, or a short
driver name for manifest-based resolution. Requires |
None
|
db_kwargs
|
dict[str, str] | None
|
ADBC connection keyword arguments as |
None
|
entrypoint
|
str | None
|
ADBC entry-point symbol. Only used with |
None
|
dbapi_module
|
str | None
|
Dotted module name for a Python package implementing the ADBC
dbapi interface (e.g. |
None
|
pool_size
|
int
|
Number of connections to keep in the pool. Default: 5. |
5
|
max_overflow
|
int
|
Extra connections allowed above |
3
|
timeout
|
int
|
Seconds to wait for a connection before raising. Default: 30. |
30
|
recycle
|
int
|
Seconds before a connection is recycled. Default: 3600. |
3600
|
pre_ping
|
bool
|
Whether to ping connections before checkout. Default: False. |
False
|
Returns:
| Type | Description |
|---|---|
AsyncPool
|
A configured |
Raises:
| Type | Description |
|---|---|
TypeError
|
If none of |
ImportError
|
If the required ADBC driver is not installed. |
Example
import anyio
from adbc_poolhouse import DuckDBConfig, create_async_pool, close_async_pool
async def main():
pool = create_async_pool(DuckDBConfig(database="/tmp/wh.db"))
try:
async with await pool.connect() as conn:
cur = conn.cursor()
await cur.execute("SELECT 1")
finally:
await close_async_pool(pool)
anyio.run(main)
Source code in src/adbc_poolhouse/_async/_factory.py
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | |
managed_async_pool
async
¶
managed_async_pool(
config: WarehouseConfig,
*,
pool_size: int = 5,
max_overflow: int = 3,
timeout: int = 30,
recycle: int = 3600,
pre_ping: bool = False,
) -> contextlib.AbstractAsyncContextManager[AsyncPool]
Async context manager that creates an AsyncPool and closes it on exit.
The async analog of managed_pool. The pool is
created when the async with block is entered and closed (via
close_async_pool, whose teardown is shielded from cancellation) when the
block exits, whether normally or by exception.
Three call patterns are supported:
async with managed_async_pool(DuckDBConfig(...)) as pool: ... # config
async with managed_async_pool(driver_path="...", ...) as pool: ... # native
async with managed_async_pool(dbapi_module="...", ...) as pool: ... # dbapi
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
WarehouseConfig | None
|
A warehouse config model instance (e.g. |
None
|
driver_path
|
str | None
|
Path to a native ADBC driver shared library, or a short
driver name for manifest-based resolution. Requires |
None
|
db_kwargs
|
dict[str, str] | None
|
ADBC connection keyword arguments as |
None
|
entrypoint
|
str | None
|
ADBC entry-point symbol. Only used with |
None
|
dbapi_module
|
str | None
|
Dotted module name for a Python package implementing the ADBC
dbapi interface (e.g. |
None
|
pool_size
|
int
|
Number of connections to keep in the pool. Default: 5. |
5
|
max_overflow
|
int
|
Extra connections allowed above |
3
|
timeout
|
int
|
Seconds to wait for a connection before raising. Default: 30. |
30
|
recycle
|
int
|
Seconds before a connection is recycled. Default: 3600. |
3600
|
pre_ping
|
bool
|
Whether to ping connections before checkout. Default: False. |
False
|
Yields:
| Type | Description |
|---|---|
AsyncGenerator[AsyncPool, None]
|
A configured |
Raises:
| Type | Description |
|---|---|
TypeError
|
If none of |
ImportError
|
If the required ADBC driver is not installed. |
Example
Source code in src/adbc_poolhouse/_async/_factory.py
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 | |
Async API (experimental)¶
You never construct these classes yourself. They are returned by the async
entry-point functions above (create_async_pool returns an AsyncPool, whose
connect yields an AsyncConnection, whose cursor yields an AsyncCursor).
They are documented here at their real module paths because the async surface is
experimental and is not part of the constructible public API.
adbc_poolhouse._async._pool.AsyncPool
¶
Async wrapper over a synchronous ADBC QueuePool.
Created by create_async_pool. The pool
construction itself is synchronous (it does no per-call I/O); only connect
and close are offloaded to worker threads.
The pool owns one dedicated anyio.CapacityLimiter sized to
pool_size + max_overflow, shared by every offloaded call on the pool and its
connections. A limiter token is borrowed only for the duration of each
individual call (transient-token model, D-24-01), so a checked-out connection
holds no token between calls and the worst-case in-flight offload count
exactly fits the limiter.
Attributes:
| Name | Type | Description |
|---|---|---|
_limiter |
The pool's dedicated |
Example
import anyio
from adbc_poolhouse import DuckDBConfig, create_async_pool, close_async_pool
async def main():
pool = create_async_pool(DuckDBConfig(database="/tmp/wh.db"))
try:
async with await pool.connect() as conn:
cur = conn.cursor() # synchronous, no await
await cur.execute("SELECT 42")
table = await cur.fetch_arrow_table()
print(table.num_rows)
finally:
await close_async_pool(pool)
anyio.run(main)
Wrap a sync pool and build its dedicated limiter.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sync_pool
|
QueuePool
|
The synchronous |
required |
pool_size
|
int
|
The pool's steady-state connection count. Must match the value passed to the sync pool. |
required |
max_overflow
|
int
|
Extra connections allowed above |
required |
Source code in src/adbc_poolhouse/_async/_pool.py
connect
async
¶
Check out a connection from the pool on a worker thread.
The blocking QueuePool.connect() runs through the offload chokepoint
under the pool limiter; the borrowed token is released as soon as the
checkout returns (transient-token model). The returned AsyncConnection
belongs to exactly one task --- do not share it across concurrent tasks.
Returns:
| Type | Description |
|---|---|
AsyncConnection
|
An |
Source code in src/adbc_poolhouse/_async/_pool.py
close
async
¶
Dispose the pool and close its ADBC source, shielded from cancellation.
The blocking teardown (close_pool, which disposes the pool and closes
the underlying ADBC source connection) is offloaded under the pool limiter
and wrapped in anyio.CancelScope(shield=True), so a cancellation
arriving mid-close cannot abandon the pool with leaked driver resources.
Source code in src/adbc_poolhouse/_async/_pool.py
adbc_poolhouse._async._connection.AsyncConnection
¶
Async wrapper over a pooled ADBC connection.
Returned by AsyncPool.connect.
It holds a checked-out sync pool connection (a SQLAlchemy
PoolProxiedConnection) for its lifetime but borrows a limiter token only for
the duration of each individual offloaded call (transient-token model,
D-24-01) --- it retains no token between calls.
One AsyncConnection belongs to exactly one task. A cheap _in_use guard
rejects a second concurrent caller (another task using a cursor on this
connection, or a concurrent commit/close) with
ConnectionBusyError rather than
silently serializing (D-24-03). The check-in (close / __aexit__) is
shielded from cancellation so a connection is never returned to the pool in an
unknown state.
Two-tier entry guard (D-29-10). The entry method layers a persistent
reader-lifetime tier on top of the per-call _in_use tier:
- Foreign callers (
execute,commit, another cursor, a newfetch_record_batch) are rejected while a reader is live --- they hit_in_useor_reader_openand getConnectionBusyError. - A live reader's own per-batch pulls pass
from_reader=True, which exempts them from the_reader_opentier only (the reentrancy exemption --- a reader must not deadlock on its own lifetime lock) while STILL taking the per-call_in_useC-access tier.
Attributes:
| Name | Type | Description |
|---|---|---|
_in_use |
True while an offloaded call on this connection (or one of its cursors) is in flight. The single-task aliasing guard; deliberately a plain bool, never a serializing lock, so a second concurrent caller is rejected rather than queued (D-24-03). |
|
_reader_open |
True for the WHOLE lifetime of a live Arrow reader on this
connection (Model B, D-29-08/09), distinct from the per-call |
|
_teardown_limiter |
CapacityLimiter
|
A dedicated 1-token |
Example
import adbc_poolhouse
pool = await adbc_poolhouse.create_async_pool(config)
async with await pool.connect() as conn:
cursor = conn.cursor() # synchronous, no await
await cursor.execute("SELECT 42")
table = await cursor.fetch_arrow_table()
await conn.commit()
await adbc_poolhouse.close_async_pool(pool)
Bind a checked-out sync connection to its pool limiter.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fairy
|
PoolProxiedConnection
|
The checked-out sync pool connection (SQLAlchemy
|
required |
limiter
|
CapacityLimiter
|
The owning pool's |
required |
Source code in src/adbc_poolhouse/_async/_connection.py
_enter_offload
¶
Claim this connection for one offloaded call, or reject an aliased caller.
Applies the two-tier entry guard (D-29-10). First the per-call C-access tier:
raise ConnectionBusyError if the connection is already executing a call
(from this task or another) --- this tier is unconditional, so from_reader
never bypasses it. Then the reader-lifetime tier: raise ConnectionBusyError
if a reader is live (_reader_open) UNLESS the caller is that reader's own
pull (from_reader=True), which is exempt from this tier only (the
reentrancy exemption --- a reader must not deadlock on its own lifetime
lock). If both tiers pass, mark the connection busy.
The read of _in_use and the write that sets it run in one synchronous span
with NO await between them, so on the single-threaded event loop two tasks
can never both observe _in_use == False and both proceed (Pitfall 3 / the
check-and-set race). Always paired with _exit_offload in a finally.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
from_reader
|
bool
|
True only for a live reader's own per-batch pull, exempting
it from the |
False
|
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If an offloaded call on this connection is already
in flight ( |
Source code in src/adbc_poolhouse/_async/_connection.py
_exit_offload
¶
_offloading
¶
Hold the two-tier entry guard for the span of one offloaded call.
Claims the connection on entry (raising ConnectionBusyError if it is
already executing a call, or if a reader is live and the caller is foreign)
and releases the per-call _in_use tier on exit, so every offloading method
on this connection --- and on its cursors --- brackets its work identically
without repeating the try/finally (D-24-03). If the guard rejects the
caller the body never runs and the flags are left untouched for the call
that legitimately holds them.
_reader_open is deliberately NOT cleared here: its lifetime spans many
offload calls and is owned by reader.close() / checkin (D-29-11), so
_exit_offload only clears _in_use.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
from_reader
|
bool
|
Forwarded to |
False
|
Yields:
| Type | Description |
|---|---|
Generator[None]
|
|
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If an offloaded call on this connection is already in flight, or a reader is live and the caller is foreign. |
Source code in src/adbc_poolhouse/_async/_connection.py
cursor
¶
Open a cursor on this connection.
This is a plain synchronous accessor (NOT async): the dbapi cursor()
does no I/O, so there is nothing to offload and no token to borrow. The
returned cursor guards this connection's _in_use flag, so concurrent use
of two cursors on one connection --- like concurrent use of the connection
itself --- raises ConnectionBusyError.
Returns:
| Type | Description |
|---|---|
AsyncCursor
|
An |
Source code in src/adbc_poolhouse/_async/_connection.py
commit
async
¶
Commit the current transaction on a worker thread.
Offloads fairy.commit() through the pool limiter while holding the
_in_use guard, so a concurrent commit/query on this connection is
rejected with ConnectionBusyError.
Unlike the cursor's execute/fetch*, this call is not cooperatively
cancellable: it runs through the non-interruptible offload with no
adbc_cancel hook, so a surrounding timeout or cancellation cannot abort an
in-flight commit. The loop defers the cancellation and waits for the driver
call to return before raising it. Keep commits short, or enforce a
server-side statement timeout, if you need a bound on how long a commit can
block.
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on this connection is already in flight. |
Source code in src/adbc_poolhouse/_async/_connection.py
rollback
async
¶
Roll back the current transaction on a worker thread.
Offloads fairy.rollback() through the pool limiter while holding the
_in_use guard.
Like commit, this call is not cooperatively cancellable: a surrounding
timeout or cancellation cannot abort an in-flight rollback. The loop defers
the cancellation and waits for the driver call to return before raising it.
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on this connection is already in flight. |
Source code in src/adbc_poolhouse/_async/_connection.py
adbc_get_info
async
¶
Read the driver and vendor info codes on a worker thread.
Offloads the sync adbc_get_info() through the pool limiter while holding
the _in_use guard, so a concurrent call on this connection is rejected with
ConnectionBusyError. The driver's own dict is returned unchanged --- keys
are ADBC info codes (str or int), values the backend's reported metadata.
Like commit, this call is not cooperatively cancellable: it runs
through the non-interruptible offload with no cancel hook, so a surrounding
timeout or cancellation cannot abort an in-flight metadata read. The loop
defers the cancellation and waits for the driver call to return before
raising it.
Returns:
| Type | Description |
|---|---|
dict[str | int, Any]
|
The driver's info mapping, keyed by ADBC info code. Returned unchanged. |
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on this connection is already in flight. |
Example
Source code in src/adbc_poolhouse/_async/_connection.py
adbc_get_table_types
async
¶
List the backend's table-type names on a worker thread.
Offloads the sync adbc_get_table_types() through the pool limiter while
holding the _in_use guard, so a concurrent call on this connection is
rejected with ConnectionBusyError. The driver's own list of table-type
strings (for example "table", "view") is returned unchanged.
Like commit, this call is not cooperatively cancellable: a surrounding
timeout or cancellation cannot abort an in-flight metadata read. The loop
defers the cancellation and waits for the driver call to return before
raising it.
Returns:
| Type | Description |
|---|---|
list[str]
|
The backend's table-type strings, in the driver's order. Returned |
list[str]
|
unchanged. |
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on this connection is already in flight. |
Example
Source code in src/adbc_poolhouse/_async/_connection.py
adbc_get_table_schema
async
¶
adbc_get_table_schema(
table_name: str,
*,
catalog_filter: str | None = None,
db_schema_filter: str | None = None,
) -> pyarrow.Schema
Read a single table's Arrow schema on a worker thread.
Offloads the sync adbc_get_table_schema() through the pool limiter while
holding the _in_use guard, so a concurrent call on this connection is
rejected with ConnectionBusyError. The driver's own pyarrow.Schema is
returned unchanged. The arguments forward through functools.partial so the
keyword-only filters reach the driver arity-checked.
Like commit, this call is not cooperatively cancellable: a surrounding
timeout or cancellation cannot abort an in-flight metadata read. The loop
defers the cancellation and waits for the driver call to return before
raising it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
table_name
|
str
|
The table to describe. Passed straight to the driver as an identifier; poolhouse does not quote or sanitize it. |
required |
catalog_filter
|
str | None
|
Restrict the lookup to this catalog. Forwarded to the
driver unchanged; |
None
|
db_schema_filter
|
str | None
|
Restrict the lookup to this schema. Forwarded to the
driver unchanged; |
None
|
Returns:
| Type | Description |
|---|---|
Schema
|
The table's |
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on this connection is already in flight. |
Example
Source code in src/adbc_poolhouse/_async/_connection.py
adbc_get_objects
async
¶
adbc_get_objects(
*,
depth: Literal[
"all", "catalogs", "db_schemas", "tables", "columns"
] = "all",
catalog_filter: str | None = None,
db_schema_filter: str | None = None,
table_name_filter: str | None = None,
table_types_filter: list[str] | None = None,
column_name_filter: str | None = None,
) -> AsyncRecordBatchReader
Stream the catalog/schema/table hierarchy as an AsyncRecordBatchReader.
Offloads the sync adbc_get_objects() through the pool limiter to create the
native pyarrow.RecordBatchReader, then wraps it in an
AsyncRecordBatchReader whose every batch pull is itself offloaded --- the
result is never materialized to a pyarrow.Table. The filter arguments
forward through functools.partial so they reach the driver arity-checked.
Like commit, creating the reader is not cooperatively cancellable: a
surrounding timeout or cancellation cannot abort the in-flight metadata call,
which runs through the non-interruptible offload.
The returned reader is a live stream bound to this connection's C Arrow
stream, so it locks the connection for its WHOLE lifetime: a foreign op
(commit, a cursor, another metadata call) raises ConnectionBusyError
until the reader is closed (STREAM-06), and a read after the reader is closed
/ the connection is checked in surfaces the driver's native
pyarrow.lib.ArrowInvalid (never a segfault). The _reader_open lifetime
lock is set AFTER the _offloading() span exits and ONLY on the success
path, so a failed creation leaves the connection usable.
The reader has no cancel of its own (the connection has no adbc_cancel), so
a cancelled per-batch pull cannot abort the in-flight C call: the worker
finishes its read, the cancellation is then re-raised, and the pulled batch is
discarded. The connection is NOT invalidated --- it was never poisoned, and
invalidating would race a second thread against the still-running read on the
same connection (CR-34-01) --- so it returns to the pool on the normal checkin.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
depth
|
Literal['all', 'catalogs', 'db_schemas', 'tables', 'columns']
|
How deep to descend the hierarchy --- |
'all'
|
catalog_filter
|
str | None
|
Restrict to this catalog. Forwarded unchanged; |
None
|
db_schema_filter
|
str | None
|
Restrict to this schema. Forwarded unchanged; |
None
|
table_name_filter
|
str | None
|
Restrict to this table name. Forwarded unchanged;
|
None
|
table_types_filter
|
list[str] | None
|
Restrict to these table types. Forwarded unchanged;
|
None
|
column_name_filter
|
str | None
|
Restrict to this column name. Forwarded unchanged;
|
None
|
Returns:
| Type | Description |
|---|---|
AsyncRecordBatchReader
|
An |
AsyncRecordBatchReader
|
offloaded through the pool limiter. |
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on this connection is already in flight. |
Example
Source code in src/adbc_poolhouse/_async/_connection.py
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 | |
adbc_get_statistics
async
¶
adbc_get_statistics(
*,
catalog_filter: str | None = None,
db_schema_filter: str | None = None,
table_name_filter: str | None = None,
approximate: bool = True,
) -> AsyncRecordBatchReader
Stream table statistics as an AsyncRecordBatchReader.
Offloads the sync adbc_get_statistics() through the pool limiter to create
the native pyarrow.RecordBatchReader, then wraps it in an
AsyncRecordBatchReader whose every batch pull is itself offloaded --- never
materialized. The filter arguments forward through functools.partial. A
backend that does not implement statistics (for example DuckDB) surfaces the
driver's native NotSupportedError unchanged (locked decision #6).
Like commit, creating the reader is not cooperatively cancellable: a
surrounding timeout or cancellation cannot abort the in-flight metadata call.
The returned reader locks the connection for its WHOLE lifetime: a foreign op
raises ConnectionBusyError until the reader is closed (STREAM-06), and a
read after close / check-in surfaces the driver's native
pyarrow.lib.ArrowInvalid. The _reader_open lifetime lock is set AFTER the
_offloading() span exits and ONLY on the success path. The reader has no
cancel of its own, so a cancelled per-batch pull cannot abort the C call: the
worker finishes its read and the cancellation is re-raised. The connection is
NOT invalidated (it was never poisoned) --- it returns to the pool on the
normal checkin (CR-34-01).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
catalog_filter
|
str | None
|
Restrict to this catalog. Forwarded unchanged; |
None
|
db_schema_filter
|
str | None
|
Restrict to this schema. Forwarded unchanged; |
None
|
table_name_filter
|
str | None
|
Restrict to this table name. Forwarded unchanged;
|
None
|
approximate
|
bool
|
Allow the backend to return approximate statistics. |
True
|
Returns:
| Type | Description |
|---|---|
AsyncRecordBatchReader
|
An |
AsyncRecordBatchReader
|
through the pool limiter. |
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on this connection is already in flight. |
Example
Source code in src/adbc_poolhouse/_async/_connection.py
adbc_get_statistic_names
async
¶
Stream the backend's statistic names as an AsyncRecordBatchReader.
Offloads the sync adbc_get_statistic_names() through the pool limiter to
create the native pyarrow.RecordBatchReader, then wraps it in an
AsyncRecordBatchReader whose every batch pull is itself offloaded --- never
materialized. A backend that does not implement statistics (for example
DuckDB) surfaces the driver's native NotSupportedError unchanged (locked
decision #6).
Like commit, creating the reader is not cooperatively cancellable: a
surrounding timeout or cancellation cannot abort the in-flight metadata call.
The returned reader locks the connection for its WHOLE lifetime: a foreign op
raises ConnectionBusyError until the reader is closed (STREAM-06), and a
read after close / check-in surfaces the driver's native
pyarrow.lib.ArrowInvalid. The _reader_open lifetime lock is set AFTER the
_offloading() span exits and ONLY on the success path. The reader has no
cancel of its own, so a cancelled per-batch pull cannot abort the C call: the
worker finishes its read and the cancellation is re-raised. The connection is
NOT invalidated (it was never poisoned) --- it returns to the pool on the
normal checkin (CR-34-01).
Returns:
| Type | Description |
|---|---|
AsyncRecordBatchReader
|
An |
AsyncRecordBatchReader
|
offloaded through the pool limiter. |
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on this connection is already in flight. |
Example
Source code in src/adbc_poolhouse/_async/_connection.py
close
async
¶
Return the connection to the pool (shielded check-in).
Offloads fairy.close() --- which returns the connection to the sync pool
and fires the pool's reset event (_release_arrow_allocators) unchanged
--- inside anyio.CancelScope(shield=True), so a cancellation arriving
mid-check-in cannot abandon the connection in an unknown state (ACONN-02).
The _in_use guard is held across the shielded offload.
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on this connection is already in flight. |
Source code in src/adbc_poolhouse/_async/_connection.py
invalidate
async
¶
Drop a poisoned connection from the pool (offloaded, shielded).
A connection whose in-flight call was cancelled is genuinely poisoned ---
the driver leaves it with an aborted transaction, so reusing it fails
(D-25-03). This drops it instead of returning it: it offloads the fairy's
invalidate(), which detaches the underlying dbapi connection and drives
the sync pool's checkedout() to 0, inside anyio.CancelScope(shield=True)
so a second cancellation arriving mid-recovery cannot leave the pool
accounting wrong (CANCEL-02 / D-25-07).
Like __aexit__, it bypasses the _in_use guard: the cursor method that
drives this recovery still holds _in_use across its own try/finally,
so a connection left marked busy by the cancelled call is still reclaimed.
It offloads through a DEDICATED 1-token teardown limiter, NOT the pool's
shared limiter (WR-03): on a single-token pool the just-aborted worker
still holds the only pool token until its thread returns, so borrowing the
pool token here would deadlock recovery behind the very worker it just
aborted. Teardown is not throughput-bounded, so giving it a private token
is correct and removes the unenforced scheduler-ordering dependency.
It is the poison-recovery counterpart to close: invalidate is the cancel
path, close the normal check-in. A close() after an invalidate() is a
safe no-op (probe-confirmed).
Releasing a live reader's lifetime lock (D-29-16): if a streaming
AsyncRecordBatchReader held this connection (_reader_open == True) when its
pull was cancelled, dropping the connection also clears _reader_open. The
connection is being detached from the pool, so its reader-lifetime lock is
meaningless --- and a subsequent explicit close() (which takes the foreign
tier) must stay the documented safe no-op rather than raise
ConnectionBusyError on the now-defunct lock. The per-connect() fresh
AsyncConnection is the ultimate backstop (D-29-13), but clearing it here
keeps close-after-invalidate correct on the same handle.
Source code in src/adbc_poolhouse/_async/_connection.py
adbc_poolhouse._async._cursor.AsyncCursor
¶
Async wrapper over a sync ADBC cursor.
Opened synchronously by
AsyncConnection.cursor.
One AsyncCursor belongs to exactly one task, mirroring the synchronous
connection-per-thread convention. Every blocking call is offloaded through the
owning pool's limiter and guards the parent connection's _in_use flag, so a
second concurrent caller is rejected with
ConnectionBusyError.
description, rowcount, and arraysize are synchronous property reads (no
await, no offload). fetch_arrow_table returns a fully-materialized
pyarrow.Table, safe after the connection is checked in.
Example
import adbc_poolhouse
pool = await adbc_poolhouse.create_async_pool(config)
async with await pool.connect() as conn:
cursor = conn.cursor()
await cursor.execute("SELECT * FROM events WHERE day = ?", ["2026-06-27"])
table = await cursor.fetch_arrow_table() # materialized pyarrow.Table
print(cursor.rowcount) # sync property, no await
await adbc_poolhouse.close_async_pool(pool)
Bind a sync cursor to its limiter and owning connection.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sync_cursor
|
_SyncCursor
|
The underlying ADBC dbapi cursor to wrap. |
required |
limiter
|
CapacityLimiter
|
The owning pool's |
required |
owner
|
AsyncConnection
|
The |
required |
Source code in src/adbc_poolhouse/_async/_cursor.py
description
property
¶
The dbapi description of the last query (synchronous; no offload).
Returns:
| Type | Description |
|---|---|
object
|
The underlying cursor's |
object
|
tuples, or |
object
|
I/O, so it is not offloaded. |
rowcount
property
¶
The dbapi rowcount of the last operation (synchronous; no offload).
Returns:
| Type | Description |
|---|---|
int
|
The underlying cursor's |
int
|
directly --- it touches no I/O, so it is not offloaded. |
arraysize
property
¶
The dbapi arraysize (default fetchmany batch size; synchronous).
Returns:
| Type | Description |
|---|---|
int
|
The underlying cursor's |
int
|
I/O, so it is not offloaded. |
_adbc_cancel
¶
Fire the driver's thread-safe adbc_cancel to abort an in-flight call.
Resolved lazily and called only by cancellable_offload when a
genuinely-running offload is cancelled (never on the success path). The
ADBC dbapi cursor always exposes adbc_cancel; a replay/cassette backend
that does not block (and so never aborts mid-flight) need not provide it,
so its absence is tolerated as a no-op rather than surfaced --- the abort
path is unreachable for an instant, non-blocking backend.
Source code in src/adbc_poolhouse/_async/_cursor.py
execute
async
¶
Execute a statement on a worker thread.
Offloads the dbapi execute through the pool limiter while holding the
parent connection's _in_use guard, so a concurrent call on the same
connection is rejected with ConnectionBusyError (EDGE-15).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
operation
|
str
|
The SQL text to execute. |
required |
parameters
|
object
|
Optional bound parameters, forwarded to the dbapi cursor. |
None
|
If the surrounding scope is cancelled or times out while the statement is
in flight, the in-flight C call is aborted with cursor.adbc_cancel, the
now-poisoned connection is invalidated (shielded), and the cancellation is
re-raised --- the connection never returns to the pool busy (CANCEL-01/02).
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on the owning connection is already in flight. |
Source code in src/adbc_poolhouse/_async/_cursor.py
executemany
async
¶
Execute a statement once per parameter set on a worker thread.
Offloads the dbapi executemany through the pool limiter while holding the
parent connection's _in_use guard.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
operation
|
str
|
The SQL text to execute. |
required |
seq_of_parameters
|
object
|
The sequence of parameter sets, forwarded to the dbapi cursor. |
required |
If the surrounding scope is cancelled mid-flight, the in-flight call is
aborted with cursor.adbc_cancel, the poisoned connection is invalidated
(shielded), and the cancellation is re-raised (CANCEL-01/02).
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on the owning connection is already in flight. |
Source code in src/adbc_poolhouse/_async/_cursor.py
fetchone
async
¶
Fetch the next row on a worker thread.
If the surrounding scope is cancelled mid-fetch, the in-flight call is
aborted with cursor.adbc_cancel, the poisoned connection is invalidated
(shielded), and the cancellation is re-raised (CANCEL-01/02).
Returns:
| Type | Description |
|---|---|
object
|
The next row (a tuple), or |
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on the owning connection is already in flight. |
Source code in src/adbc_poolhouse/_async/_cursor.py
fetchmany
async
¶
Fetch the next batch of rows on a worker thread.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
size
|
int | None
|
The number of rows to fetch. When |
None
|
If the surrounding scope is cancelled mid-fetch, the in-flight call is
aborted with cursor.adbc_cancel, the poisoned connection is invalidated
(shielded), and the cancellation is re-raised (CANCEL-01/02).
Returns:
| Type | Description |
|---|---|
object
|
A sequence of rows (possibly empty when the result set is exhausted). |
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on the owning connection is already in flight. |
Source code in src/adbc_poolhouse/_async/_cursor.py
fetchall
async
¶
Fetch all remaining rows on a worker thread.
If the surrounding scope is cancelled mid-fetch, the in-flight call is
aborted with cursor.adbc_cancel, the poisoned connection is invalidated
(shielded), and the cancellation is re-raised (CANCEL-01/02).
Returns:
| Type | Description |
|---|---|
object
|
A sequence of all remaining rows. |
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on the owning connection is already in flight. |
Source code in src/adbc_poolhouse/_async/_cursor.py
fetch_arrow_table
async
¶
Materialize the full result set as a pyarrow.Table on a worker thread.
Offloads the dbapi fetch_arrow_table through the pool limiter and returns
its result unchanged: a fully-materialized pyarrow.Table that owns its own
buffers. The table is safe to read after the connection is checked in --- it
is never a streaming RecordBatchReader bound to the (soon-closed) cursor
(EDGE-21 / Pitfall 7).
If the surrounding scope is cancelled or times out while the result is
being materialized, the in-flight C call is aborted with
cursor.adbc_cancel, the now-poisoned connection is invalidated
(shielded), and the cancellation is re-raised (CANCEL-01/02).
Returns:
| Type | Description |
|---|---|
Table
|
The materialized |
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on the owning connection is already in flight. |
Source code in src/adbc_poolhouse/_async/_cursor.py
fetch_df
async
¶
Materialize the full result set as a pandas.DataFrame on a worker thread.
Offloads the driver's native fetch_df through the pool limiter and returns
its result unchanged: a fully-materialized pandas.DataFrame that owns its
own buffers. The frame is safe to read after the connection is checked in ---
it is never bound to the (soon-closed) cursor's C stream (EDGE-21 / Pitfall 7).
pandas is not a poolhouse dependency --- you install it yourself. poolhouse
never imports it: the driver imports pandas inside the worker, so a missing
install surfaces the native ModuleNotFoundError unchanged, with no
pre-check and no wrapping.
If the surrounding scope is cancelled or times out while the result is
being materialized, the in-flight C call is aborted with
cursor.adbc_cancel, the now-poisoned connection is invalidated
(shielded), and the cancellation is re-raised (CANCEL-01/02).
Returns:
| Type | Description |
|---|---|
DataFrame
|
The materialized |
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on the owning connection is already in flight. |
ModuleNotFoundError
|
If |
Example
Source code in src/adbc_poolhouse/_async/_cursor.py
fetch_polars
async
¶
Materialize the full result set as a polars.DataFrame on a worker thread.
Offloads the driver's native fetch_polars through the pool limiter and
returns its result unchanged: a fully-materialized polars.DataFrame that
owns its own buffers. The frame is safe to read after the connection is
checked in --- it is never bound to the (soon-closed) cursor's C stream
(EDGE-21 / Pitfall 7).
polars is not a poolhouse dependency --- you install it yourself. poolhouse
never imports it: the driver imports polars inside the worker, so a missing
install surfaces the native ModuleNotFoundError unchanged, with no
pre-check and no wrapping.
If the surrounding scope is cancelled or times out while the result is
being materialized, the in-flight C call is aborted with
cursor.adbc_cancel, the now-poisoned connection is invalidated
(shielded), and the cancellation is re-raised (CANCEL-01/02).
Returns:
| Type | Description |
|---|---|
DataFrame
|
The materialized |
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on the owning connection is already in flight. |
ModuleNotFoundError
|
If |
Example
Source code in src/adbc_poolhouse/_async/_cursor.py
adbc_ingest
async
¶
adbc_ingest(
table_name: str,
data: RecordBatch
| Table
| RecordBatchReader
| CapsuleType,
*,
mode: Literal[
"create", "append", "replace", "create_append"
] = "create",
catalog_name: str | None = None,
db_schema_name: str | None = None,
temporary: bool = False,
) -> int
Bulk-load an Arrow dataset into a table on a worker thread.
Offloads the dbapi adbc_ingest through the pool limiter while holding the
parent connection's _in_use guard, so a concurrent call on the same
connection is rejected with ConnectionBusyError (EDGE-15). This is a
single whole-operation offload --- the connection checks back in the moment
the ingest returns, unlike fetch_record_batch, which holds the connection
for a reader's whole lifetime.
data is handed to the driver untouched: poolhouse performs no conversion
and no validation. The driver owns the Arrow binding and the table
identifier, so a malformed dataset or a bad identifier surfaces the driver's
native error unchanged.
If the surrounding scope is cancelled or times out while the ingest is in
flight, the in-flight C call is aborted with cursor.adbc_cancel, the
now-poisoned connection is invalidated (shielded), and the cancellation is
re-raised --- the connection never returns to the pool busy (CANCEL-01/02).
Recovery restores the connection, not the table: an aborted bulk load
can leave rows already written, and poolhouse does not roll that back. Treat
a cancelled ingest as leaving the table in an undefined state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
table_name
|
str
|
The target table. Passed straight to the driver as a SQL identifier; poolhouse does not quote or sanitize it. |
required |
data
|
RecordBatch | Table | RecordBatchReader | CapsuleType
|
The Arrow dataset to load --- a |
required |
mode
|
Literal['create', 'append', 'replace', 'create_append']
|
How to write the data. |
'create'
|
catalog_name
|
str | None
|
EXPERIMENTAL. Target catalog for the table. No stability guarantee; surfaced as-is from the driver. |
None
|
db_schema_name
|
str | None
|
EXPERIMENTAL. Target schema for the table. No stability guarantee; surfaced as-is from the driver. |
None
|
temporary
|
bool
|
EXPERIMENTAL. Create the table as temporary. No stability guarantee; surfaced as-is from the driver. |
False
|
Returns:
| Type | Description |
|---|---|
int
|
The number of rows written, or |
int
|
count. Poolhouse returns the driver's value unchanged. |
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on the owning connection is already in flight. |
Example
Source code in src/adbc_poolhouse/_async/_cursor.py
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 | |
adbc_prepare
async
¶
Prepare a statement without executing it, on a worker thread.
Offloads the dbapi adbc_prepare through the pool limiter while holding the
parent connection's _in_use guard, so a concurrent call on the same
connection is rejected with ConnectionBusyError (EDGE-15). The query is
prepared but NOT executed --- no rows are read and no data is written.
Returns the schema of the query's BIND PARAMETERS, or None when the driver
cannot determine it. Poolhouse forwards the driver's value unchanged; treat a
None result as "the backend does not report a parameter schema", not an
error.
If the surrounding scope is cancelled or times out while the prepare is in
flight, the in-flight C call is aborted with cursor.adbc_cancel and the
cancellation is re-raised. Because a prepare writes no table data, the
connection is NOT invalidated --- it is cancellable but non-poisoning, returning
clean to the pool (D-35-04). This is the deliberate difference from execute,
which invalidates on abort. The non-poisoning guarantee assumes the driver
leaves no lingering session state after a cancelled prepare (true for DuckDB); a
backend whose cancel aborts the surrounding transaction may need the connection
rolled back before reuse.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
operation
|
bytes | str
|
The SQL text to prepare. Passed to the driver verbatim; poolhouse constructs no SQL and adds no sanitization. |
required |
Returns:
| Type | Description |
|---|---|
Schema | None
|
The |
Schema | None
|
when the driver cannot determine a parameter schema. |
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on the owning connection is already in flight. |
Example
Source code in src/adbc_poolhouse/_async/_cursor.py
adbc_execute_schema
async
¶
Get a query's result-set schema without executing it, on a worker thread.
Offloads the dbapi adbc_execute_schema through the pool limiter while
holding the parent connection's _in_use guard, so a concurrent call on the
same connection is rejected with ConnectionBusyError (EDGE-15). The query is
planned but NOT run --- no rows are fetched and no side effects occur; only the
result-set schema is returned.
If the surrounding scope is cancelled or times out while the call is in
flight, the in-flight C call is aborted with cursor.adbc_cancel and the
cancellation is re-raised. Because the query never executes, the connection is
NOT invalidated --- it is cancellable but non-poisoning, returning clean to the
pool (D-35-04). As with adbc_prepare, this assumes the driver leaves no
lingering session state after a cancelled call (true for DuckDB); a backend
whose cancel aborts the surrounding transaction may need a rollback before reuse.
An unsupported backend surfaces the driver's native error unchanged: poolhouse
does not catch, wrap, or find_spec-pre-check it (D-35-06). DuckDB, for
example, does not implement result-schema introspection and raises
NotSupportedError straight through the single offload chokepoint (EDGE-17).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
operation
|
bytes | str
|
The SQL text whose result schema to resolve. Passed to the driver verbatim; poolhouse constructs no SQL and adds no sanitization. |
required |
parameters
|
object
|
Optional bound parameters, forwarded to the dbapi cursor. |
None
|
Returns:
| Type | Description |
|---|---|
Schema
|
The |
Schema
|
executing the query. |
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on the owning connection is already in flight. |
NotSupportedError
|
If the driver does not implement result-schema introspection (e.g. DuckDB). Raised by the driver in the worker and propagated unchanged through the offload chokepoint (EDGE-17). |
Example
Source code in src/adbc_poolhouse/_async/_cursor.py
fetch_record_batch
async
¶
Stream the result set as an AsyncRecordBatchReader off a worker thread.
Offloads the dbapi fetch_record_batch through the pool limiter to create
the sync pyarrow.RecordBatchReader, then wraps it in an
AsyncRecordBatchReader whose every batch pull is itself offloaded (D-29-03).
Unlike
fetch_arrow_table, the result is a live stream bound to this connection's C
Arrow stream, so the reader locks the connection for its WHOLE lifetime: a
foreign op raises ConnectionBusyError until the reader is closed (STREAM-06),
and a read after the reader is closed / the connection is checked in surfaces
the driver's native pyarrow.lib.ArrowInvalid (never a segfault, T-29-01).
The _reader_open lifetime lock is set AFTER the _offloading() span exits
(which already cleared the per-call _in_use) and ONLY on the success path,
so a cancelled or failed creation leaves the connection usable rather than
permanently busy (Pitfall 5).
If the surrounding scope is cancelled or times out while the reader is being
created, the in-flight C call is aborted with cursor.adbc_cancel, the
now-poisoned connection is invalidated (shielded), and the cancellation is
re-raised --- the connection never returns to the pool busy (CANCEL-01/02).
Returns:
| Type | Description |
|---|---|
AsyncRecordBatchReader
|
An |
AsyncRecordBatchReader
|
with this cursor's |
AsyncRecordBatchReader
|
cursor (the reader has no cancel of its own, Pitfall 4). |
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on the owning connection is already in flight. |
Example
Source code in src/adbc_poolhouse/_async/_cursor.py
close
async
¶
Close the underlying cursor on a worker thread (shielded).
Offloads the dbapi close inside anyio.CancelScope(shield=True), so a
cancellation arriving mid-close cannot abandon an open cursor (which would
pin Arrow readers). The parent connection's _in_use guard is held across
the shielded offload.
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
If another offloaded call on the owning connection is already in flight. |
Source code in src/adbc_poolhouse/_async/_cursor.py
adbc_poolhouse._async._reader.AsyncRecordBatchReader
¶
AsyncRecordBatchReader(
sync_reader: _SyncReader,
limiter: CapacityLimiter,
owner: AsyncConnection,
adbc_cancel: Callable[[], None],
*,
poison_on_cancel: bool = True,
)
Async wrapper over a sync pyarrow.RecordBatchReader.
Created by
AsyncCursor.fetch_record_batch
and reached only through await cursor.fetch_record_batch(). Holds the sync
reader by composition (never subclasses it, D-29-01) and offloads each batch pull
and the final close through the owning pool's limiter, so no blocking Arrow C
call ever runs on the event loop.
A live reader locks its owning connection for its WHOLE lifetime, so a foreign op
on the same connection raises
ConnectionBusyError while the reader is
open (STREAM-06). The lock is cleared by close() --- NOT at drain (D-29-11) ---
so the reader must be closed; async with is the canonical usage and its
finalizer only warns.
schema is a synchronous property read (no await, no offload). Reading after
the reader is closed --- or after the connection is checked in, which closes the
underlying cursor --- surfaces the driver's native pyarrow.lib.ArrowInvalid,
never a poolhouse error and never a segfault (T-29-01).
Example
import adbc_poolhouse
pool = await adbc_poolhouse.create_async_pool(config)
async with await pool.connect() as conn:
cursor = conn.cursor()
await cursor.execute("SELECT * FROM events WHERE day = ?", ["2026-06-27"])
async with await cursor.fetch_record_batch() as reader:
async for batch in reader: # each pull offloaded off-loop
process(batch) # a pyarrow.RecordBatch
await adbc_poolhouse.close_async_pool(pool)
Bind a sync reader to its limiter, owning connection, and the cursor's cancel.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sync_reader
|
_SyncReader
|
The underlying sync |
required |
limiter
|
CapacityLimiter
|
The owning pool's |
required |
owner
|
AsyncConnection
|
The |
required |
adbc_cancel
|
Callable[[], None]
|
The cancel callback fired to abort an in-flight pull. For a
cursor-backed reader this is the owning CURSOR's |
required |
poison_on_cancel
|
bool
|
Whether a cancelled pull invalidates the owning
connection. |
True
|
Source code in src/adbc_poolhouse/_async/_reader.py
schema
property
¶
The reader's Arrow schema (synchronous; no offload --- touches no I/O).
Returns:
| Type | Description |
|---|---|
Schema
|
The wrapped sync reader's |
Schema
|
schema touches no I/O, so it is not offloaded and not |
Schema
|
coroutine property would be the "coroutine was never awaited" footgun). |
close
async
¶
Close the underlying sync reader on a worker thread (shielded, idempotent).
Offloads the sync reader's close inside anyio.CancelScope(shield=True), so
a cancellation arriving mid-close cannot abandon an open C stream (which would
pin the connection's Arrow allocators). Idempotent via _detached: a second
close --- or a close after the connection was already checked in --- is a
safe no-op.
The owning connection's _reader_open lock is cleared in a finally, so even
a close whose offloaded sync_reader.close raises still releases the
connection (never stranding it busy) and chains the raised body error via
__context__ (EDGE-20 / D-29-16).
Raises:
| Type | Description |
|---|---|
Exception
|
Whatever the sync reader's |