sqlalchemy-adbc 0.1.0__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sqlalchemy_adbc-0.3.0/.github/workflows/ci.yml +66 -0
- {sqlalchemy_adbc-0.1.0 → sqlalchemy_adbc-0.3.0}/.github/workflows/publish.yml +54 -0
- sqlalchemy_adbc-0.3.0/CHANGELOG.md +142 -0
- {sqlalchemy_adbc-0.1.0 → sqlalchemy_adbc-0.3.0}/PKG-INFO +49 -9
- {sqlalchemy_adbc-0.1.0 → sqlalchemy_adbc-0.3.0}/README.md +41 -6
- {sqlalchemy_adbc-0.1.0 → sqlalchemy_adbc-0.3.0}/pyproject.toml +36 -4
- sqlalchemy_adbc-0.3.0/src/sqlalchemy_adbc/base.py +253 -0
- {sqlalchemy_adbc-0.1.0 → sqlalchemy_adbc-0.3.0}/src/sqlalchemy_adbc/bigquery.py +2 -2
- {sqlalchemy_adbc-0.1.0 → sqlalchemy_adbc-0.3.0}/src/sqlalchemy_adbc/flightsql.py +35 -12
- sqlalchemy_adbc-0.3.0/src/sqlalchemy_adbc/postgresql.py +186 -0
- sqlalchemy_adbc-0.3.0/src/sqlalchemy_adbc/postgresql_types.py +150 -0
- sqlalchemy_adbc-0.3.0/src/sqlalchemy_adbc/reflection.py +316 -0
- sqlalchemy_adbc-0.3.0/src/sqlalchemy_adbc/snowflake.py +48 -0
- sqlalchemy_adbc-0.3.0/src/sqlalchemy_adbc/sqlite.py +95 -0
- sqlalchemy_adbc-0.3.0/tests/test_alembic_autogenerate.py +223 -0
- sqlalchemy_adbc-0.3.0/tests/test_base.py +81 -0
- sqlalchemy_adbc-0.3.0/tests/test_bigquery_url.py +45 -0
- {sqlalchemy_adbc-0.1.0 → sqlalchemy_adbc-0.3.0}/tests/test_flightsql_url.py +21 -3
- sqlalchemy_adbc-0.3.0/tests/test_postgresql_types.py +336 -0
- sqlalchemy_adbc-0.3.0/tests/test_postgresql_url.py +83 -0
- sqlalchemy_adbc-0.3.0/tests/test_reflection.py +469 -0
- sqlalchemy_adbc-0.3.0/tests/test_snowflake_url.py +63 -0
- {sqlalchemy_adbc-0.1.0 → sqlalchemy_adbc-0.3.0}/tests/test_sqlite.py +5 -2
- sqlalchemy_adbc-0.1.0/.github/workflows/ci.yml +0 -42
- sqlalchemy_adbc-0.1.0/src/sqlalchemy_adbc/base.py +0 -110
- sqlalchemy_adbc-0.1.0/src/sqlalchemy_adbc/postgresql.py +0 -31
- sqlalchemy_adbc-0.1.0/src/sqlalchemy_adbc/snowflake.py +0 -38
- sqlalchemy_adbc-0.1.0/src/sqlalchemy_adbc/sqlite.py +0 -27
- {sqlalchemy_adbc-0.1.0 → sqlalchemy_adbc-0.3.0}/.gitignore +0 -0
- {sqlalchemy_adbc-0.1.0 → sqlalchemy_adbc-0.3.0}/LICENSE +0 -0
- {sqlalchemy_adbc-0.1.0 → sqlalchemy_adbc-0.3.0}/src/sqlalchemy_adbc/__init__.py +0 -0
- {sqlalchemy_adbc-0.1.0 → sqlalchemy_adbc-0.3.0}/tests/__init__.py +0 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
lint:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
- uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.12"
|
|
21
|
+
- name: Install
|
|
22
|
+
run: pip install -e ".[dev]"
|
|
23
|
+
- name: Ruff check
|
|
24
|
+
run: ruff check src/ tests/
|
|
25
|
+
- name: Ruff format
|
|
26
|
+
run: ruff format --check src/ tests/
|
|
27
|
+
- name: Mypy
|
|
28
|
+
run: mypy src tests
|
|
29
|
+
|
|
30
|
+
test:
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
strategy:
|
|
33
|
+
fail-fast: false
|
|
34
|
+
matrix:
|
|
35
|
+
# Matrix tracks active Python versions only — 3.9 hit EOL in
|
|
36
|
+
# October 2025, so it's dropped. Bump when a new minor ships;
|
|
37
|
+
# drop when Python marks one end-of-life.
|
|
38
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
39
|
+
# Postgres service for integration tests (test_postgresql_types.py,
|
|
40
|
+
# issue #3). Gated by DRLS_PG_URL — tests skip when the env var is
|
|
41
|
+
# absent, so local `pytest` runs without a local PG also pass.
|
|
42
|
+
services:
|
|
43
|
+
postgres:
|
|
44
|
+
image: postgres:16
|
|
45
|
+
env:
|
|
46
|
+
POSTGRES_USER: test
|
|
47
|
+
POSTGRES_PASSWORD: test
|
|
48
|
+
POSTGRES_DB: test
|
|
49
|
+
ports:
|
|
50
|
+
- 5432:5432
|
|
51
|
+
options: >-
|
|
52
|
+
--health-cmd "pg_isready -U test"
|
|
53
|
+
--health-interval 10s
|
|
54
|
+
--health-timeout 5s
|
|
55
|
+
--health-retries 5
|
|
56
|
+
env:
|
|
57
|
+
DRLS_PG_URL: "adbc+postgresql://test:test@localhost:5432/test"
|
|
58
|
+
steps:
|
|
59
|
+
- uses: actions/checkout@v4
|
|
60
|
+
- uses: actions/setup-python@v5
|
|
61
|
+
with:
|
|
62
|
+
python-version: ${{ matrix.python-version }}
|
|
63
|
+
- name: Install
|
|
64
|
+
run: pip install -e ".[dev,postgresql]"
|
|
65
|
+
- name: Pytest
|
|
66
|
+
run: pytest tests/ --cov=sqlalchemy_adbc --cov-report=term-missing
|
|
@@ -87,3 +87,57 @@ jobs:
|
|
|
87
87
|
name: dist
|
|
88
88
|
path: dist/
|
|
89
89
|
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
90
|
+
|
|
91
|
+
github-release:
|
|
92
|
+
# Creates a GitHub Release for every tag push, using the matching
|
|
93
|
+
# CHANGELOG.md section as the release body. Runs AFTER the PyPI
|
|
94
|
+
# publish succeeds so we don't advertise a version that failed
|
|
95
|
+
# to upload. No binary assets attached — PyPI is the distribution
|
|
96
|
+
# channel; duplicating wheels here invites drift.
|
|
97
|
+
name: Create GitHub Release
|
|
98
|
+
needs: publish-pypi
|
|
99
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
100
|
+
runs-on: ubuntu-latest
|
|
101
|
+
permissions:
|
|
102
|
+
contents: write
|
|
103
|
+
steps:
|
|
104
|
+
- uses: actions/checkout@v4
|
|
105
|
+
- name: Extract release notes from CHANGELOG
|
|
106
|
+
id: notes
|
|
107
|
+
run: |
|
|
108
|
+
TAG="${GITHUB_REF#refs/tags/v}"
|
|
109
|
+
# Grab the section under `## [X.Y.Z]` up to the next `## `
|
|
110
|
+
# heading (or EOF). `awk` keeps this portable across bash
|
|
111
|
+
# versions without depending on gh's CHANGELOG conventions.
|
|
112
|
+
NOTES=$(awk -v ver="$TAG" '
|
|
113
|
+
/^## \[/ {
|
|
114
|
+
if (found) exit
|
|
115
|
+
if ($0 ~ "\\[" ver "\\]") { found = 1; next }
|
|
116
|
+
}
|
|
117
|
+
found { print }
|
|
118
|
+
' CHANGELOG.md)
|
|
119
|
+
if [ -z "$NOTES" ]; then
|
|
120
|
+
echo "::warning::No CHANGELOG entry found for version $TAG"
|
|
121
|
+
NOTES="Release v$TAG. See [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/main/CHANGELOG.md) for details."
|
|
122
|
+
fi
|
|
123
|
+
# Append PyPI link so the Release page directs installers
|
|
124
|
+
# back to the canonical distribution.
|
|
125
|
+
NOTES="$NOTES
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
📦 **Install:** \`pip install sqlalchemy-adbc==$TAG\` —
|
|
130
|
+
[view on PyPI](https://pypi.org/project/sqlalchemy-adbc/$TAG/)"
|
|
131
|
+
{
|
|
132
|
+
echo "notes<<EOF"
|
|
133
|
+
echo "$NOTES"
|
|
134
|
+
echo "EOF"
|
|
135
|
+
} >> "$GITHUB_OUTPUT"
|
|
136
|
+
- name: Create Release
|
|
137
|
+
env:
|
|
138
|
+
GH_TOKEN: ${{ github.token }}
|
|
139
|
+
run: |
|
|
140
|
+
TAG="${GITHUB_REF#refs/tags/v}"
|
|
141
|
+
gh release create "v$TAG" \
|
|
142
|
+
--title "v$TAG" \
|
|
143
|
+
--notes "${{ steps.notes.outputs.notes }}"
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `sqlalchemy-adbc` are documented here. Format
|
|
4
|
+
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
|
|
5
|
+
this project adheres to [Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.3.0] — 2026-04-21
|
|
10
|
+
|
|
11
|
+
Largest release so far: table reflection, Alembic autogenerate,
|
|
12
|
+
PostgreSQL type decorators, and breaking fixes to dialect naming
|
|
13
|
+
and Python version support. Not backwards-compatible for callers
|
|
14
|
+
that read `engine.dialect.name` or run on Python 3.9.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **Table reflection via `adbc_get_objects`** — the full SQLAlchemy
|
|
19
|
+
Inspector contract now works for any ADBC driver that implements
|
|
20
|
+
the GetObjects metadata call. Covers `get_columns`,
|
|
21
|
+
`get_pk_constraint`, `get_foreign_keys`, `get_unique_constraints`,
|
|
22
|
+
`get_table_names`, `get_view_names`, `get_schema_names`, and
|
|
23
|
+
`has_table`. `MetaData.reflect(bind=engine)` works end-to-end.
|
|
24
|
+
([#5](https://github.com/drls-io/sqlalchemy-adbc/pull/5),
|
|
25
|
+
closes [#1](https://github.com/drls-io/sqlalchemy-adbc/issues/1))
|
|
26
|
+
- **Native `get_indexes` for SQLite and PostgreSQL** — ADBC's
|
|
27
|
+
GetObjects spec doesn't carry per-index column lists, so we
|
|
28
|
+
query the backend's native catalog (PRAGMA `index_list` /
|
|
29
|
+
`index_info` for SQLite; `pg_index` / `pg_class` / `pg_attribute`
|
|
30
|
+
with `LATERAL unnest WITH ORDINALITY` for PG). Identifiers are
|
|
31
|
+
properly escaped — PRAGMA can't be parameterized.
|
|
32
|
+
([#6](https://github.com/drls-io/sqlalchemy-adbc/pull/6))
|
|
33
|
+
- **Alembic autogenerate support** — fallout from the dialect-name
|
|
34
|
+
fix below. Alembic's DDL impl registry now finds the correct
|
|
35
|
+
per-backend impl (`SQLiteImpl`, `PostgresqlImpl`) for free.
|
|
36
|
+
Covers create/drop table, add/drop column, and roundtrip
|
|
37
|
+
idempotency (apply autogenerate output → re-run → no-op).
|
|
38
|
+
([#7](https://github.com/drls-io/sqlalchemy-adbc/pull/7),
|
|
39
|
+
closes [#2](https://github.com/drls-io/sqlalchemy-adbc/issues/2))
|
|
40
|
+
- **PostgreSQL type decorators** — `JSONB`, `JSON`, `UUID`, `INET`,
|
|
41
|
+
`CIDR`, `MACADDR`, `MACADDR8`. Round-trip PG-specific types
|
|
42
|
+
through ADBC as the Python objects SQLAlchemy users expect:
|
|
43
|
+
JSONB → dict/list, UUID → `uuid.UUID` (or `str` with
|
|
44
|
+
`as_uuid=False`), INET/CIDR/MAC as strings. PG column reflection
|
|
45
|
+
now queries `information_schema.columns.udt_name` directly
|
|
46
|
+
(ADBC's `xdbc_type_name` is unreliable for PG-extension types),
|
|
47
|
+
so `MetaData.reflect()` surfaces these as TypeDecorators, not
|
|
48
|
+
`NullType`. ([#8](https://github.com/drls-io/sqlalchemy-adbc/pull/8),
|
|
49
|
+
closes [#3](https://github.com/drls-io/sqlalchemy-adbc/issues/3))
|
|
50
|
+
- **CI Postgres service** — integration tests (`test_postgresql_types.py`)
|
|
51
|
+
now run against a real `postgres:16` container, gated by
|
|
52
|
+
`DRLS_PG_URL`. Local `pytest` runs without Postgres continue to
|
|
53
|
+
skip these cleanly.
|
|
54
|
+
|
|
55
|
+
### Changed
|
|
56
|
+
|
|
57
|
+
- **BREAKING — dialect `name` and `driver` attributes flipped** to
|
|
58
|
+
match SQLAlchemy's convention: `name` is the backend identity
|
|
59
|
+
(`sqlite`, `postgresql`, `flightsql`, `snowflake`, `bigquery`),
|
|
60
|
+
`driver` is the wire path (`adbc`). Previously every dialect
|
|
61
|
+
reported `name="adbc"`, which caused Alembic's DDL-impl lookup
|
|
62
|
+
to `KeyError`. URL forms (`adbc+sqlite://`, etc.) are unchanged.
|
|
63
|
+
Callers inspecting `engine.dialect.name` must update expectations.
|
|
64
|
+
- **BREAKING — dropped Python 3.9.** Python 3.9 reached end-of-life
|
|
65
|
+
in October 2025. `requires-python` is now `>=3.10`; the CI matrix
|
|
66
|
+
covers 3.10–3.13.
|
|
67
|
+
- **Development Status classifier: Alpha → Beta.** Matches the
|
|
68
|
+
README's scope statement — core functionality is stable enough
|
|
69
|
+
for real use, but a few months of external feedback still needed
|
|
70
|
+
before 1.0.
|
|
71
|
+
|
|
72
|
+
### Fixed
|
|
73
|
+
|
|
74
|
+
- **PG `paramstyle` — `numeric_dollar`.** Forces SQLAlchemy to emit
|
|
75
|
+
`$1, $2, ...` (libpq's native wire form) instead of `:name` binds
|
|
76
|
+
via ADBC's `adbc.statement.bind_by_name` (which libpq rejects
|
|
77
|
+
with `NOT_IMPLEMENTED`) or `:1, :2, ...` (which PG's parser
|
|
78
|
+
rejects with `syntax error at or near ":"`). Set via
|
|
79
|
+
`__init__(kwargs.setdefault(...))` because `DefaultDialect.__init__`
|
|
80
|
+
clobbers the class-level attribute from `dbapi.paramstyle`.
|
|
81
|
+
- `get_columns` now honors SQLAlchemy's `ReflectedColumn` shape
|
|
82
|
+
([#5](https://github.com/drls-io/sqlalchemy-adbc/pull/5))
|
|
83
|
+
- Mypy is gated in CI with proper `sqlalchemy.engine.interfaces`
|
|
84
|
+
return types
|
|
85
|
+
- `cache_ok = True` declared explicitly on `JSON` and `CIDR`
|
|
86
|
+
subclasses — the attribute does not inherit across `TypeDecorator`
|
|
87
|
+
subclasses, so the absence silenced statement caching and
|
|
88
|
+
emitted SAWarning on every engine.
|
|
89
|
+
|
|
90
|
+
## [0.2.0] — 2026-04-19
|
|
91
|
+
|
|
92
|
+
Security + correctness release. Not backwards-compatible for
|
|
93
|
+
Flight SQL users relying on the plaintext-by-default behavior.
|
|
94
|
+
|
|
95
|
+
### Changed
|
|
96
|
+
|
|
97
|
+
- **BREAKING — Flight SQL TLS is now default-on** (`tls=true`).
|
|
98
|
+
Send a bearer token over plaintext gRPC was an unmissable
|
|
99
|
+
credential-leak shape. Local/dev users on plaintext listeners
|
|
100
|
+
must now opt out with `?tls=false`. Default port auto-picks
|
|
101
|
+
443 for TLS, 50051 for plaintext (Arrow Flight convention).
|
|
102
|
+
|
|
103
|
+
### Fixed
|
|
104
|
+
|
|
105
|
+
- **URL → DSN special-character escaping** for PostgreSQL and
|
|
106
|
+
Snowflake. A password containing `@`, `:`, `/`, `#`, `%` was
|
|
107
|
+
previously concatenated into the DSN unquoted and would silently
|
|
108
|
+
re-route libpq to the wrong host. Username/password now routed
|
|
109
|
+
through `urllib.parse.quote`; database path stays as-is since
|
|
110
|
+
SQLAlchemy's URL parser leaves it percent-encoded.
|
|
111
|
+
- mypy errors in the Flight SQL dialect around `URL.query`
|
|
112
|
+
tuple vs str handling. A `_scalar()` helper normalizes repeated
|
|
113
|
+
keys to their last value (HTTP/shell convention).
|
|
114
|
+
- Formatting drift on three files.
|
|
115
|
+
|
|
116
|
+
### Added
|
|
117
|
+
|
|
118
|
+
- CI gates `mypy src tests` alongside the existing ruff check.
|
|
119
|
+
- Extensive URL-parse test coverage: 13 PG, 9 Snowflake, 5 BigQuery
|
|
120
|
+
tests covering special-char escaping, no-credentials paths, and
|
|
121
|
+
edge cases. Total suite: 51 (up from 16).
|
|
122
|
+
- Documentation of known gaps in the README (table reflection,
|
|
123
|
+
Alembic autogenerate, PG-specific types) with links to tracking
|
|
124
|
+
issues.
|
|
125
|
+
|
|
126
|
+
## [0.1.0] — 2026-04-18
|
|
127
|
+
|
|
128
|
+
Initial public release.
|
|
129
|
+
|
|
130
|
+
### Added
|
|
131
|
+
|
|
132
|
+
- Generic `ADBCDialect` base class with per-driver subclasses for
|
|
133
|
+
Flight SQL, SQLite, PostgreSQL, Snowflake, and BigQuery
|
|
134
|
+
- URL → `db_kwargs` translation per driver
|
|
135
|
+
- Entry-point registration under `sqlalchemy.dialects` so any
|
|
136
|
+
`adbc+<driver>://` URL resolves automatically
|
|
137
|
+
- PyPI trusted publishing via OIDC
|
|
138
|
+
|
|
139
|
+
[Unreleased]: https://github.com/drls-io/sqlalchemy-adbc/compare/v0.3.0...HEAD
|
|
140
|
+
[0.3.0]: https://github.com/drls-io/sqlalchemy-adbc/compare/v0.2.0...v0.3.0
|
|
141
|
+
[0.2.0]: https://github.com/drls-io/sqlalchemy-adbc/compare/v0.1.0...v0.2.0
|
|
142
|
+
[0.1.0]: https://github.com/drls-io/sqlalchemy-adbc/releases/tag/v0.1.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlalchemy-adbc
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Generic SQLAlchemy dialect for any ADBC driver (Flight SQL, PostgreSQL, SQLite, Snowflake, BigQuery).
|
|
5
5
|
Project-URL: Homepage, https://github.com/drls-io/sqlalchemy-adbc
|
|
6
6
|
Project-URL: Repository, https://github.com/drls-io/sqlalchemy-adbc
|
|
@@ -9,13 +9,17 @@ Author: DRLS Contributors
|
|
|
9
9
|
License: Apache-2.0
|
|
10
10
|
License-File: LICENSE
|
|
11
11
|
Keywords: adbc,arrow,dialect,flight-sql,sqlalchemy
|
|
12
|
-
Classifier: Development Status ::
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
|
16
16
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
21
|
Classifier: Topic :: Database
|
|
18
|
-
Requires-Python: >=3.
|
|
22
|
+
Requires-Python: >=3.10
|
|
19
23
|
Requires-Dist: adbc-driver-manager>=1.0
|
|
20
24
|
Requires-Dist: pyarrow>=14.0
|
|
21
25
|
Requires-Dist: sqlalchemy>=2.0
|
|
@@ -23,6 +27,7 @@ Provides-Extra: bigquery
|
|
|
23
27
|
Requires-Dist: adbc-driver-bigquery>=1.0; extra == 'bigquery'
|
|
24
28
|
Provides-Extra: dev
|
|
25
29
|
Requires-Dist: adbc-driver-sqlite>=1.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: alembic>=1.13; extra == 'dev'
|
|
26
31
|
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
27
32
|
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
28
33
|
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
@@ -117,12 +122,47 @@ df = pd.read_sql("SELECT 1 AS n", engine)
|
|
|
117
122
|
|
|
118
123
|
## Status
|
|
119
124
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
125
|
+
**Beta.** Core dialect + reflection + Alembic autogenerate work on
|
|
126
|
+
the ADBC drivers we exercise in CI (SQLite end-to-end, PostgreSQL
|
|
127
|
+
via service container). Not 1.0 yet — we want a few months of
|
|
128
|
+
real-world use and at least one release without breaking changes
|
|
129
|
+
before committing to a stable API.
|
|
130
|
+
|
|
131
|
+
Full history in [CHANGELOG.md](CHANGELOG.md). Download tags on
|
|
132
|
+
[GitHub Releases](https://github.com/drls-io/sqlalchemy-adbc/releases);
|
|
133
|
+
published wheels on [PyPI](https://pypi.org/project/sqlalchemy-adbc/).
|
|
134
|
+
|
|
135
|
+
### What works
|
|
136
|
+
|
|
137
|
+
- `SELECT` / `INSERT` / `CREATE TABLE` / `DROP TABLE` / `ALTER TABLE`
|
|
138
|
+
for every advertised driver
|
|
139
|
+
- `MetaData.reflect(bind=engine)` — full Inspector contract backed
|
|
140
|
+
by ADBC `GetObjects`, including columns, PK, FK, unique
|
|
141
|
+
constraints, indexes (native PRAGMA / `pg_catalog` queries on
|
|
142
|
+
SQLite and PG)
|
|
143
|
+
- Alembic `autogenerate` — end-to-end, reusing SQLAlchemy's native
|
|
144
|
+
backend DDL impls via standard dialect-name lookup
|
|
145
|
+
- URL forms for Flight SQL, PostgreSQL, SQLite, Snowflake, BigQuery
|
|
146
|
+
with correct special-character escaping in passwords
|
|
147
|
+
|
|
148
|
+
### Known limitations
|
|
149
|
+
|
|
150
|
+
- **PostgreSQL range types** (tstzrange, tstzmultirange, int4range,
|
|
151
|
+
…) and **hstore** — not yet mapped to typed decorators; returned
|
|
152
|
+
as raw strings. JSONB / JSON / UUID / INET / CIDR / MACADDR /
|
|
153
|
+
MACADDR8 all round-trip through typed decorators as of 0.3.0
|
|
154
|
+
([#3](https://github.com/drls-io/sqlalchemy-adbc/issues/3) —
|
|
155
|
+
JSONB/UUID/INET portion closed)
|
|
156
|
+
- **Drivers exercised in CI** — SQLite fully, PostgreSQL
|
|
157
|
+
integration-tested via service container. Snowflake / BigQuery /
|
|
158
|
+
Flight SQL inherit the shared reflection path but have no
|
|
159
|
+
per-driver CI
|
|
160
|
+
- **ADBC SQLite NOT NULL reporting** — upstream driver always
|
|
161
|
+
reports nullable=True; reflection faithfully reflects that
|
|
162
|
+
(tracked, auto-reactivating xfail)
|
|
163
|
+
|
|
164
|
+
Tests: 106 passing on Python 3.10–3.13, including 17 PostgreSQL
|
|
165
|
+
integration tests against a service-container Postgres.
|
|
126
166
|
|
|
127
167
|
## Development
|
|
128
168
|
|
|
@@ -78,12 +78,47 @@ df = pd.read_sql("SELECT 1 AS n", engine)
|
|
|
78
78
|
|
|
79
79
|
## Status
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
81
|
+
**Beta.** Core dialect + reflection + Alembic autogenerate work on
|
|
82
|
+
the ADBC drivers we exercise in CI (SQLite end-to-end, PostgreSQL
|
|
83
|
+
via service container). Not 1.0 yet — we want a few months of
|
|
84
|
+
real-world use and at least one release without breaking changes
|
|
85
|
+
before committing to a stable API.
|
|
86
|
+
|
|
87
|
+
Full history in [CHANGELOG.md](CHANGELOG.md). Download tags on
|
|
88
|
+
[GitHub Releases](https://github.com/drls-io/sqlalchemy-adbc/releases);
|
|
89
|
+
published wheels on [PyPI](https://pypi.org/project/sqlalchemy-adbc/).
|
|
90
|
+
|
|
91
|
+
### What works
|
|
92
|
+
|
|
93
|
+
- `SELECT` / `INSERT` / `CREATE TABLE` / `DROP TABLE` / `ALTER TABLE`
|
|
94
|
+
for every advertised driver
|
|
95
|
+
- `MetaData.reflect(bind=engine)` — full Inspector contract backed
|
|
96
|
+
by ADBC `GetObjects`, including columns, PK, FK, unique
|
|
97
|
+
constraints, indexes (native PRAGMA / `pg_catalog` queries on
|
|
98
|
+
SQLite and PG)
|
|
99
|
+
- Alembic `autogenerate` — end-to-end, reusing SQLAlchemy's native
|
|
100
|
+
backend DDL impls via standard dialect-name lookup
|
|
101
|
+
- URL forms for Flight SQL, PostgreSQL, SQLite, Snowflake, BigQuery
|
|
102
|
+
with correct special-character escaping in passwords
|
|
103
|
+
|
|
104
|
+
### Known limitations
|
|
105
|
+
|
|
106
|
+
- **PostgreSQL range types** (tstzrange, tstzmultirange, int4range,
|
|
107
|
+
…) and **hstore** — not yet mapped to typed decorators; returned
|
|
108
|
+
as raw strings. JSONB / JSON / UUID / INET / CIDR / MACADDR /
|
|
109
|
+
MACADDR8 all round-trip through typed decorators as of 0.3.0
|
|
110
|
+
([#3](https://github.com/drls-io/sqlalchemy-adbc/issues/3) —
|
|
111
|
+
JSONB/UUID/INET portion closed)
|
|
112
|
+
- **Drivers exercised in CI** — SQLite fully, PostgreSQL
|
|
113
|
+
integration-tested via service container. Snowflake / BigQuery /
|
|
114
|
+
Flight SQL inherit the shared reflection path but have no
|
|
115
|
+
per-driver CI
|
|
116
|
+
- **ADBC SQLite NOT NULL reporting** — upstream driver always
|
|
117
|
+
reports nullable=True; reflection faithfully reflects that
|
|
118
|
+
(tracked, auto-reactivating xfail)
|
|
119
|
+
|
|
120
|
+
Tests: 106 passing on Python 3.10–3.13, including 17 PostgreSQL
|
|
121
|
+
integration tests against a service-container Postgres.
|
|
87
122
|
|
|
88
123
|
## Development
|
|
89
124
|
|
|
@@ -4,19 +4,23 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "sqlalchemy-adbc"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
description = "Generic SQLAlchemy dialect for any ADBC driver (Flight SQL, PostgreSQL, SQLite, Snowflake, BigQuery)."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "Apache-2.0" }
|
|
11
|
-
requires-python = ">=3.
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
12
|
authors = [{ name = "DRLS Contributors" }]
|
|
13
13
|
keywords = ["sqlalchemy", "adbc", "arrow", "flight-sql", "dialect"]
|
|
14
14
|
classifiers = [
|
|
15
|
-
"Development Status ::
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
16
|
"Intended Audience :: Developers",
|
|
17
17
|
"License :: OSI Approved :: Apache Software License",
|
|
18
18
|
"Programming Language :: Python :: 3",
|
|
19
19
|
"Programming Language :: Python :: 3 :: Only",
|
|
20
|
+
"Programming Language :: Python :: 3.10",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
20
24
|
"Topic :: Database",
|
|
21
25
|
]
|
|
22
26
|
dependencies = [
|
|
@@ -41,6 +45,10 @@ dev = [
|
|
|
41
45
|
"ruff>=0.6",
|
|
42
46
|
"mypy>=1.10",
|
|
43
47
|
"adbc-driver-sqlite>=1.0",
|
|
48
|
+
# Alembic autogenerate tests (test_alembic_autogenerate.py) rely on
|
|
49
|
+
# the Inspector contract we implemented in #1 — pinning the dev
|
|
50
|
+
# pin ensures CI exercises that integration path.
|
|
51
|
+
"alembic>=1.13",
|
|
44
52
|
]
|
|
45
53
|
|
|
46
54
|
[project.urls]
|
|
@@ -64,12 +72,36 @@ packages = ["src/sqlalchemy_adbc"]
|
|
|
64
72
|
|
|
65
73
|
[tool.ruff]
|
|
66
74
|
line-length = 100
|
|
67
|
-
target-version = "
|
|
75
|
+
target-version = "py310"
|
|
68
76
|
|
|
69
77
|
[tool.ruff.lint]
|
|
70
78
|
select = ["E", "F", "W", "I", "B", "UP"]
|
|
71
79
|
ignore = ["E501"]
|
|
72
80
|
|
|
81
|
+
[tool.mypy]
|
|
82
|
+
# Intentionally 3.10 (not 3.9) — mypy traverses third-party packages
|
|
83
|
+
# via follow-imports, and pytest itself uses `match`/`case` syntax that
|
|
84
|
+
# the 3.9 parser can't even tokenize. Our own source is still
|
|
85
|
+
# 3.9-compatible; runtime compat is covered by the pytest matrix.
|
|
86
|
+
python_version = "3.10"
|
|
87
|
+
strict_optional = true
|
|
88
|
+
warn_redundant_casts = true
|
|
89
|
+
warn_unused_ignores = true
|
|
90
|
+
follow_imports = "silent"
|
|
91
|
+
|
|
92
|
+
# ADBC driver wheels don't ship type stubs; lazy imports in the dialect
|
|
93
|
+
# modules guard on ImportError so we only pay the type-ignore cost here.
|
|
94
|
+
[[tool.mypy.overrides]]
|
|
95
|
+
module = [
|
|
96
|
+
"adbc_driver_manager.*",
|
|
97
|
+
"adbc_driver_flightsql.*",
|
|
98
|
+
"adbc_driver_postgresql.*",
|
|
99
|
+
"adbc_driver_sqlite.*",
|
|
100
|
+
"adbc_driver_snowflake.*",
|
|
101
|
+
"adbc_driver_bigquery.*",
|
|
102
|
+
]
|
|
103
|
+
ignore_missing_imports = true
|
|
104
|
+
|
|
73
105
|
[tool.pytest.ini_options]
|
|
74
106
|
testpaths = ["tests"]
|
|
75
107
|
addopts = "-v"
|