duckdb-sqlalchemy 0.19.2__tar.gz → 0.19.3__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.
Files changed (71) hide show
  1. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/.github/workflows/lint.yml +7 -0
  2. duckdb_sqlalchemy-0.19.3/.github/workflows/pages.yml +42 -0
  3. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/.github/workflows/publish.yaml +0 -33
  4. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/.github/workflows/pythonapp.yaml +10 -1
  5. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/CHANGELOG.md +12 -0
  6. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/PKG-INFO +30 -5
  7. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/README.md +12 -2
  8. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/docs/README.md +4 -0
  9. duckdb_sqlalchemy-0.19.3/docs/_config.yml +6 -0
  10. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/docs/alembic.md +5 -0
  11. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/docs/configuration.md +5 -0
  12. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/docs/connection-urls.md +5 -0
  13. duckdb_sqlalchemy-0.19.3/docs/getting-started.md +81 -0
  14. duckdb_sqlalchemy-0.19.3/docs/index.md +26 -0
  15. duckdb_sqlalchemy-0.19.3/docs/migration-from-duckdb-engine.md +30 -0
  16. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/docs/motherduck.md +5 -0
  17. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/docs/olap.md +5 -0
  18. duckdb_sqlalchemy-0.19.3/docs/overview.md +43 -0
  19. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/docs/pandas-jupyter.md +5 -0
  20. duckdb_sqlalchemy-0.19.3/docs/robots.txt +3 -0
  21. duckdb_sqlalchemy-0.19.3/docs/seo-checklist.md +24 -0
  22. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/docs/types-and-caveats.md +5 -0
  23. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/__init__.py +1 -1
  24. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/tests/test_core_units.py +145 -0
  25. duckdb_sqlalchemy-0.19.3/llms.txt +24 -0
  26. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/pyproject.toml +20 -3
  27. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  28. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  29. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/.github/dependabot.yml +0 -0
  30. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/.gitignore +0 -0
  31. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/.pre-commit-config.yaml +0 -0
  32. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/AGENTS.md +0 -0
  33. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/CLAUDE.md +0 -0
  34. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/CODE_OF_CONDUCT.md +0 -0
  35. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/LICENSE.txt +0 -0
  36. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/ROADMAP.md +0 -0
  37. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/codecov.yml +0 -0
  38. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/_supports.py +0 -0
  39. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/bulk.py +0 -0
  40. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/capabilities.py +0 -0
  41. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/config.py +0 -0
  42. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/conftest.py +0 -0
  43. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/datatypes.py +0 -0
  44. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/motherduck.py +0 -0
  45. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/olap.py +0 -0
  46. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/py.typed +0 -0
  47. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/requirements.py +0 -0
  48. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/tests/__init__.py +0 -0
  49. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/tests/conftest.py +0 -0
  50. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/tests/snapshots/test_datatypes/test_interval/schema.sql +0 -0
  51. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/tests/sqlalchemy_suite/conftest.py +0 -0
  52. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/tests/sqlalchemy_suite/test_suite.py +0 -0
  53. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/tests/test_basic.py +0 -0
  54. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/tests/test_datatypes.py +0 -0
  55. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/tests/test_execution_options.py +0 -0
  56. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/tests/test_helpers.py +0 -0
  57. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/tests/test_integration.py +0 -0
  58. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/tests/test_pandas.py +0 -0
  59. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/tests/test_pyarrow.py +0 -0
  60. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/tests/util.py +0 -0
  61. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/duckdb_sqlalchemy/url.py +0 -0
  62. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/examples/motherduck_arrow_reads.py +0 -0
  63. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/examples/motherduck_attach_modes.py +0 -0
  64. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/examples/motherduck_multi_instance_pool.py +0 -0
  65. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/examples/motherduck_queuepool_high_concurrency.py +0 -0
  66. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/examples/motherduck_read_scaling_per_user.py +0 -0
  67. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/examples/sqlalchemy_example.py +0 -0
  68. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/noxfile.py +0 -0
  69. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/renovate.json +0 -0
  70. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/test.cfg +0 -0
  71. {duckdb_sqlalchemy-0.19.2 → duckdb_sqlalchemy-0.19.3}/uv.lock +0 -0
@@ -2,6 +2,13 @@ name: Lint
2
2
 
3
3
  on:
4
4
  pull_request:
5
+ paths:
6
+ - "duckdb_sqlalchemy/**"
7
+ - "examples/**"
8
+ - "pyproject.toml"
9
+ - "noxfile.py"
10
+ - "test.cfg"
11
+ - ".github/workflows/lint.yml"
5
12
 
6
13
  jobs:
7
14
  pre-commit:
@@ -0,0 +1,42 @@
1
+ name: Docs (GitHub Pages)
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths:
7
+ - "docs/**"
8
+ - ".github/workflows/pages.yml"
9
+ workflow_dispatch:
10
+
11
+ permissions:
12
+ contents: read
13
+ pages: write
14
+ id-token: write
15
+
16
+ concurrency:
17
+ group: pages
18
+ cancel-in-progress: true
19
+
20
+ jobs:
21
+ build:
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - uses: actions/checkout@v5
25
+ - uses: actions/configure-pages@v5
26
+ - uses: actions/jekyll-build-pages@v1
27
+ with:
28
+ source: docs
29
+ destination: _site
30
+ - uses: actions/upload-pages-artifact@v3
31
+ with:
32
+ path: _site
33
+
34
+ deploy:
35
+ needs: build
36
+ runs-on: ubuntu-latest
37
+ environment:
38
+ name: github-pages
39
+ url: ${{ steps.deployment.outputs.page_url }}
40
+ steps:
41
+ - id: deployment
42
+ uses: actions/deploy-pages@v4
@@ -1,13 +1,5 @@
1
1
  name: Publish Python package
2
2
  on:
3
- workflow_dispatch:
4
- inputs:
5
- target:
6
- description: "Where to publish"
7
- required: true
8
- type: choice
9
- options:
10
- - testpypi
11
3
  release:
12
4
  types: [published]
13
5
 
@@ -58,28 +50,3 @@ jobs:
58
50
  path: dist/
59
51
  - name: Publish to PyPI
60
52
  uses: pypa/gh-action-pypi-publish@release/v1
61
-
62
- publish-to-testpypi:
63
- name: Publish to TestPyPI
64
- if: github.event_name == 'workflow_dispatch' && inputs.target == 'testpypi'
65
- needs: build
66
- runs-on: ubuntu-latest
67
-
68
- environment:
69
- name: testpypi
70
- url: https://test.pypi.org/p/duckdb-sqlalchemy
71
-
72
- permissions:
73
- contents: read
74
- id-token: write
75
-
76
- steps:
77
- - name: Download all the dists
78
- uses: actions/download-artifact@v4
79
- with:
80
- name: python-package-distributions
81
- path: dist/
82
- - name: Publish to TestPyPI
83
- uses: pypa/gh-action-pypi-publish@release/v1
84
- with:
85
- repository-url: https://test.pypi.org/legacy/
@@ -1,6 +1,15 @@
1
1
  name: Python application
2
2
 
3
- on: [pull_request, workflow_dispatch]
3
+ on:
4
+ pull_request:
5
+ paths:
6
+ - "duckdb_sqlalchemy/**"
7
+ - "examples/**"
8
+ - "pyproject.toml"
9
+ - "noxfile.py"
10
+ - "test.cfg"
11
+ - ".github/workflows/pythonapp.yaml"
12
+ workflow_dispatch:
4
13
  permissions:
5
14
  checks: write
6
15
 
@@ -6,6 +6,18 @@ preserved from the upstream project for historical context.
6
6
 
7
7
  ## Maintained in this fork
8
8
 
9
+ ## [0.19.3](https://github.com/leonardovida/duckdb-sqlalchemy/compare/v0.19.2...v0.19.3) (2025-12-28)
10
+
11
+ ### Documentation
12
+
13
+ * publish GitHub Pages docs site with Jekyll config and navigation
14
+ * add overview, getting started, migration guide, and SEO checklist
15
+ * add llms.txt and strengthen README/docs discoverability links
16
+
17
+ ### Metadata
18
+
19
+ * expand PyPI metadata (keywords, classifiers, documentation URL)
20
+
9
21
  ## [0.19.2](https://github.com/leonardovida/duckdb-sqlalchemy/compare/v0.19.0...v0.19.2) (2025-12-28)
10
22
 
11
23
  ### Documentation
@@ -1,14 +1,29 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: duckdb-sqlalchemy
3
- Version: 0.19.2
4
- Summary: SQLAlchemy driver for duckdb
3
+ Version: 0.19.3
4
+ Summary: DuckDB SQLAlchemy dialect for DuckDB and MotherDuck
5
5
  Project-URL: Bug Tracker, https://github.com/leonardovida/duckdb-sqlalchemy/issues
6
6
  Project-URL: Changelog, https://github.com/leonardovida/duckdb-sqlalchemy/releases
7
+ Project-URL: Documentation, https://leonardovida.github.io/duckdb-sqlalchemy/
7
8
  Project-URL: repository, https://github.com/leonardovida/duckdb-sqlalchemy
8
9
  Project-URL: Upstream, https://github.com/Mause/duckdb_engine
9
- Author-email: Leonardo Vida <leonardo@motherduck.com>
10
+ Author-email: Leonardo Vida <lleonardovida@gmail.com>
10
11
  License-Expression: MIT
11
12
  License-File: LICENSE.txt
13
+ Keywords: analytics,database,dialect,duckdb,motherduck,olap,sqlalchemy
14
+ Classifier: Development Status :: 5 - Production/Stable
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Programming Language :: Python :: 3.14
25
+ Classifier: Topic :: Database
26
+ Classifier: Topic :: Database :: Front-Ends
12
27
  Requires-Python: <4,>=3.9
13
28
  Requires-Dist: duckdb>=0.5.0
14
29
  Requires-Dist: packaging>=21
@@ -41,7 +56,7 @@ Description-Content-Type: text/markdown
41
56
  [![PyPI Downloads](https://img.shields.io/pypi/dm/duckdb-sqlalchemy.svg)](https://pypi.org/project/duckdb-sqlalchemy/)
42
57
  [![codecov](https://codecov.io/gh/leonardovida/duckdb-sqlalchemy/graph/badge.svg)](https://codecov.io/gh/leonardovida/duckdb-sqlalchemy)
43
58
 
44
- A production-ready SQLAlchemy dialect for DuckDB and MotherDuck. It supports SQLAlchemy Core and ORM APIs against DuckDB locally or in MotherDuck.
59
+ duckdb-sqlalchemy is a DuckDB SQLAlchemy dialect for DuckDB and MotherDuck. It supports SQLAlchemy Core and ORM APIs for local DuckDB and MotherDuck connections.
45
60
 
46
61
  The dialect handles pooling defaults, bulk inserts, type mappings, and cloud-specific configuration.
47
62
 
@@ -127,7 +142,7 @@ Use the URL helpers to build connection strings safely:
127
142
  ```python
128
143
  from duckdb_sqlalchemy import URL, MotherDuckURL
129
144
 
130
- local_url = URL(database=":memory:", read_only=False)
145
+ local_url = URL(database=":memory:", memory_limit="1GB")
131
146
  md_url = MotherDuckURL(database="md:my_db", attach_mode="single")
132
147
  ```
133
148
 
@@ -139,7 +154,11 @@ See `docs/configuration.md` and `docs/motherduck.md` for detailed guidance.
139
154
 
140
155
  ## Documentation
141
156
 
157
+ - `docs/index.md` - GitHub Pages entrypoint
142
158
  - `docs/README.md` - Docs index
159
+ - `docs/overview.md` - Overview and quick start
160
+ - `docs/getting-started.md` - Minimal install + setup walkthrough
161
+ - `docs/migration-from-duckdb-engine.md` - Migration guide from older dialects
143
162
  - `docs/connection-urls.md` - URL formats and helpers
144
163
  - `docs/motherduck.md` - MotherDuck setup and options
145
164
  - `docs/configuration.md` - Connection configuration, extensions, filesystems
@@ -148,6 +167,12 @@ See `docs/configuration.md` and `docs/motherduck.md` for detailed guidance.
148
167
  - `docs/types-and-caveats.md` - Type support and known caveats
149
168
  - `docs/alembic.md` - Alembic integration
150
169
 
170
+ Docs site (GitHub Pages):
171
+
172
+ ```
173
+ https://leonardovida.github.io/duckdb-sqlalchemy/
174
+ ```
175
+
151
176
  ## Examples
152
177
 
153
178
  - `examples/sqlalchemy_example.py` - end-to-end example
@@ -4,7 +4,7 @@
4
4
  [![PyPI Downloads](https://img.shields.io/pypi/dm/duckdb-sqlalchemy.svg)](https://pypi.org/project/duckdb-sqlalchemy/)
5
5
  [![codecov](https://codecov.io/gh/leonardovida/duckdb-sqlalchemy/graph/badge.svg)](https://codecov.io/gh/leonardovida/duckdb-sqlalchemy)
6
6
 
7
- A production-ready SQLAlchemy dialect for DuckDB and MotherDuck. It supports SQLAlchemy Core and ORM APIs against DuckDB locally or in MotherDuck.
7
+ duckdb-sqlalchemy is a DuckDB SQLAlchemy dialect for DuckDB and MotherDuck. It supports SQLAlchemy Core and ORM APIs for local DuckDB and MotherDuck connections.
8
8
 
9
9
  The dialect handles pooling defaults, bulk inserts, type mappings, and cloud-specific configuration.
10
10
 
@@ -90,7 +90,7 @@ Use the URL helpers to build connection strings safely:
90
90
  ```python
91
91
  from duckdb_sqlalchemy import URL, MotherDuckURL
92
92
 
93
- local_url = URL(database=":memory:", read_only=False)
93
+ local_url = URL(database=":memory:", memory_limit="1GB")
94
94
  md_url = MotherDuckURL(database="md:my_db", attach_mode="single")
95
95
  ```
96
96
 
@@ -102,7 +102,11 @@ See `docs/configuration.md` and `docs/motherduck.md` for detailed guidance.
102
102
 
103
103
  ## Documentation
104
104
 
105
+ - `docs/index.md` - GitHub Pages entrypoint
105
106
  - `docs/README.md` - Docs index
107
+ - `docs/overview.md` - Overview and quick start
108
+ - `docs/getting-started.md` - Minimal install + setup walkthrough
109
+ - `docs/migration-from-duckdb-engine.md` - Migration guide from older dialects
106
110
  - `docs/connection-urls.md` - URL formats and helpers
107
111
  - `docs/motherduck.md` - MotherDuck setup and options
108
112
  - `docs/configuration.md` - Connection configuration, extensions, filesystems
@@ -111,6 +115,12 @@ See `docs/configuration.md` and `docs/motherduck.md` for detailed guidance.
111
115
  - `docs/types-and-caveats.md` - Type support and known caveats
112
116
  - `docs/alembic.md` - Alembic integration
113
117
 
118
+ Docs site (GitHub Pages):
119
+
120
+ ```
121
+ https://leonardovida.github.io/duckdb-sqlalchemy/
122
+ ```
123
+
114
124
  ## Examples
115
125
 
116
126
  - `examples/sqlalchemy_example.py` - end-to-end example
@@ -4,6 +4,9 @@ This folder contains focused, task-oriented guides that keep the main README sho
4
4
 
5
5
  ## Guides
6
6
 
7
+ - `overview.md` - High-level overview and quick start
8
+ - `getting-started.md` - Minimal install + setup walkthrough
9
+ - `migration-from-duckdb-engine.md` - Migration guide from older dialects
7
10
  - `connection-urls.md` - URL formats, helpers, and manual escaping
8
11
  - `motherduck.md` - Connection patterns and MotherDuck-specific options
9
12
  - `configuration.md` - `connect_args`, extension preloads, and filesystem registration
@@ -11,6 +14,7 @@ This folder contains focused, task-oriented guides that keep the main README sho
11
14
  - `pandas-jupyter.md` - DataFrame registration and notebook usage
12
15
  - `types-and-caveats.md` - Supported types, parameter binding, and gotchas
13
16
  - `alembic.md` - Alembic integration notes
17
+ - `seo-checklist.md` - Docs indexability checklist
14
18
 
15
19
  ## Project references
16
20
 
@@ -0,0 +1,6 @@
1
+ title: duckdb-sqlalchemy
2
+ description: DuckDB SQLAlchemy dialect for DuckDB and MotherDuck
3
+ theme: jekyll-theme-cayman
4
+ plugins:
5
+ - jekyll-seo-tag
6
+ - jekyll-sitemap
@@ -1,3 +1,8 @@
1
+ ---
2
+ layout: default
3
+ title: Alembic integration
4
+ ---
5
+
1
6
  # Alembic integration
2
7
 
3
8
  SQLAlchemy's migration tool, Alembic, can be used with DuckDB by providing a dialect implementation class.
@@ -1,3 +1,8 @@
1
+ ---
2
+ layout: default
3
+ title: Configuration
4
+ ---
5
+
1
6
  # Configuration
2
7
 
3
8
  DuckDB configuration can be supplied via `connect_args` or URL query params.
@@ -1,3 +1,8 @@
1
+ ---
2
+ layout: default
3
+ title: Connection URLs
4
+ ---
5
+
1
6
  # Connection URLs
2
7
 
3
8
  DuckDB URLs follow the standard SQLAlchemy shape:
@@ -0,0 +1,81 @@
1
+ ---
2
+ layout: default
3
+ title: Getting Started
4
+ ---
5
+
6
+ # Getting Started
7
+
8
+ This guide is a compact walkthrough for the DuckDB SQLAlchemy dialect. It focuses on the most common local and MotherDuck setups and points you to deeper docs when you need them.
9
+
10
+ ## Install
11
+
12
+ ```sh
13
+ pip install duckdb-sqlalchemy
14
+ ```
15
+
16
+ ## Local DuckDB
17
+
18
+ ```python
19
+ from sqlalchemy import Column, Integer, String, create_engine
20
+ from sqlalchemy.orm import declarative_base, Session
21
+
22
+ Base = declarative_base()
23
+
24
+ class User(Base):
25
+ __tablename__ = "users"
26
+ id = Column(Integer, primary_key=True)
27
+ name = Column(String)
28
+
29
+ engine = create_engine("duckdb:///local.duckdb")
30
+ Base.metadata.create_all(engine)
31
+
32
+ with Session(engine) as session:
33
+ session.add(User(name="Ada"))
34
+ session.commit()
35
+ ```
36
+
37
+ ## In-memory DuckDB
38
+
39
+ ```python
40
+ from sqlalchemy import create_engine
41
+
42
+ engine = create_engine("duckdb:///:memory:")
43
+ ```
44
+
45
+ ## MotherDuck
46
+
47
+ ```bash
48
+ export MOTHERDUCK_TOKEN="..."
49
+ ```
50
+
51
+ ```python
52
+ from sqlalchemy import create_engine
53
+
54
+ engine = create_engine("duckdb:///md:my_db")
55
+ ```
56
+
57
+ If your token includes special characters, URL-escape it or pass it via `connect_args`.
58
+
59
+ ## Connection URLs
60
+
61
+ DuckDB URLs follow the SQLAlchemy pattern:
62
+
63
+ ```
64
+ duckdb:///<database>?<config>
65
+ ```
66
+
67
+ Examples:
68
+
69
+ ```
70
+ duckdb:///:memory:
71
+ duckdb:///analytics.db
72
+ duckdb:////absolute/path/to/analytics.db
73
+ duckdb:///md:my_db?attach_mode=single&access_mode=read_only&session_hint=team-a
74
+ ```
75
+
76
+ ## Next steps
77
+
78
+ - Connection strings: `docs/connection-urls.md`
79
+ - MotherDuck options: `docs/motherduck.md`
80
+ - Configuration and pooling: `docs/configuration.md`
81
+ - OLAP helpers: `docs/olap.md`
@@ -0,0 +1,26 @@
1
+ ---
2
+ layout: default
3
+ title: duckdb-sqlalchemy documentation
4
+ ---
5
+
6
+ # duckdb-sqlalchemy documentation
7
+
8
+ Production-ready DuckDB SQLAlchemy dialect for DuckDB and MotherDuck.
9
+
10
+ ## Start here
11
+
12
+ - [Overview](overview)
13
+ - [Getting started](getting-started)
14
+ - [Migration from duckdb_engine](migration-from-duckdb-engine)
15
+ - [Connection URLs](connection-urls)
16
+ - [MotherDuck](motherduck)
17
+ - [Configuration](configuration)
18
+ - [OLAP workflows](olap)
19
+ - [Pandas and Jupyter](pandas-jupyter)
20
+ - [Types and caveats](types-and-caveats)
21
+ - [Alembic integration](alembic)
22
+ - [SEO checklist](seo-checklist)
23
+
24
+ ## Examples
25
+
26
+ See `examples/` in the repository for runnable scripts.
@@ -0,0 +1,30 @@
1
+ ---
2
+ layout: default
3
+ title: Migration from duckdb_engine
4
+ ---
5
+
6
+ # Migration from duckdb_engine
7
+
8
+ This project is the actively maintained DuckDB SQLAlchemy dialect. If you are coming from the older `duckdb_engine` package, migrate as follows:
9
+
10
+ ## Package and import rename
11
+
12
+ Install the new package:
13
+
14
+ ```sh
15
+ pip install duckdb-sqlalchemy
16
+ ```
17
+
18
+ Update imports:
19
+
20
+ ```python
21
+ from duckdb_sqlalchemy import Dialect, URL, MotherDuckURL
22
+ ```
23
+
24
+ SQLAlchemy URLs use the `duckdb://` driver name in both packages. Existing URLs will continue to work.
25
+
26
+ ## Notes
27
+
28
+ - The package name is now `duckdb-sqlalchemy` and the module is `duckdb_sqlalchemy`.
29
+ - The dialect remains registered as `duckdb` for SQLAlchemy.
30
+ - See `docs/motherduck.md` for MotherDuck-specific behavior.
@@ -1,3 +1,8 @@
1
+ ---
2
+ layout: default
3
+ title: MotherDuck
4
+ ---
5
+
1
6
  # MotherDuck
2
7
 
3
8
  MotherDuck connections use the `md:` database prefix.
@@ -1,3 +1,8 @@
1
+ ---
2
+ layout: default
3
+ title: OLAP workflows
4
+ ---
5
+
1
6
  # OLAP workflows
2
7
 
3
8
  DuckDB exposes analytics-friendly table functions like `read_parquet` and `read_csv_auto`. The helpers in `duckdb_sqlalchemy.olap` make these easy to use with SQLAlchemy.
@@ -0,0 +1,43 @@
1
+ ---
2
+ layout: default
3
+ title: DuckDB SQLAlchemy dialect
4
+ ---
5
+
6
+ # DuckDB SQLAlchemy dialect
7
+
8
+ This project provides a production-ready SQLAlchemy dialect for DuckDB and MotherDuck. Use SQLAlchemy Core and ORM APIs with DuckDB locally or in MotherDuck without manual driver workarounds.
9
+
10
+ ## What you get
11
+
12
+ - SQLAlchemy Core, ORM, Alembic, and reflection support.
13
+ - MotherDuck helpers for attach modes, session hints, and read scaling.
14
+ - Sensible pooling defaults and optional performance tuning.
15
+ - Bulk insert helpers via Arrow or DataFrame registration.
16
+
17
+ ## Quick start
18
+
19
+ ```python
20
+ from sqlalchemy import Column, Integer, String, create_engine
21
+ from sqlalchemy.orm import declarative_base, Session
22
+
23
+ Base = declarative_base()
24
+
25
+ class User(Base):
26
+ __tablename__ = "users"
27
+ id = Column(Integer, primary_key=True)
28
+ name = Column(String)
29
+
30
+ engine = create_engine("duckdb:///:memory:")
31
+ Base.metadata.create_all(engine)
32
+
33
+ with Session(engine) as session:
34
+ session.add(User(name="Ada"))
35
+ session.commit()
36
+ ```
37
+
38
+ ## Next steps
39
+
40
+ - Connection strings: `docs/connection-urls.md`
41
+ - MotherDuck usage: `docs/motherduck.md`
42
+ - Configuration and pooling: `docs/configuration.md`
43
+ - OLAP helpers: `docs/olap.md`
@@ -1,3 +1,8 @@
1
+ ---
2
+ layout: default
3
+ title: Pandas and Jupyter
4
+ ---
5
+
1
6
  # Pandas and Jupyter
2
7
 
3
8
  ## Register a DataFrame
@@ -0,0 +1,3 @@
1
+ User-agent: *
2
+ Allow: /
3
+ Sitemap: https://leonardovida.github.io/duckdb-sqlalchemy/sitemap.xml
@@ -0,0 +1,24 @@
1
+ ---
2
+ layout: default
3
+ title: SEO checklist
4
+ ---
5
+
6
+ # SEO checklist
7
+
8
+ Use this list to validate indexability after each docs update or release.
9
+
10
+ ## Pages build
11
+
12
+ - GitHub Pages workflow completed successfully.
13
+ - Site URL responds with HTTP 200.
14
+
15
+ ## Indexability
16
+
17
+ - `robots.txt` is reachable and allows indexing.
18
+ - `sitemap.xml` is reachable and lists key docs pages.
19
+ - The docs homepage includes links to primary guides.
20
+
21
+ ## Consistency
22
+
23
+ - Project name and description are consistent in README, docs, and PyPI metadata.
24
+ - URLs in `pyproject.toml` match the docs site.
@@ -1,3 +1,8 @@
1
+ ---
2
+ layout: default
3
+ title: Types and Caveats
4
+ ---
5
+
1
6
  # Types and Caveats
2
7
 
3
8
  ## Type support
@@ -60,7 +60,7 @@ try:
60
60
  except ImportError: # pragma: no cover - fallback for older SQLAlchemy
61
61
  PGExecutionContext = DefaultExecutionContext
62
62
 
63
- __version__ = "0.19.2"
63
+ __version__ = "0.19.3"
64
64
  sqlalchemy_version = sqlalchemy.__version__
65
65
  SQLALCHEMY_VERSION = Version(sqlalchemy_version)
66
66
  SQLALCHEMY_2 = SQLALCHEMY_VERSION >= Version("2.0.0")
@@ -5,6 +5,7 @@ import duckdb
5
5
  import pytest
6
6
  from sqlalchemy import Integer, String, pool
7
7
  from sqlalchemy import exc as sa_exc
8
+ from sqlalchemy.engine import URL as SAURL
8
9
 
9
10
  from duckdb_sqlalchemy import (
10
11
  URL,
@@ -13,14 +14,20 @@ from duckdb_sqlalchemy import (
13
14
  Dialect,
14
15
  MotherDuckURL,
15
16
  _apply_motherduck_defaults,
17
+ _is_idempotent_statement,
18
+ _is_transient_error,
16
19
  _looks_like_motherduck,
20
+ _normalize_execution_options,
17
21
  _normalize_motherduck_config,
22
+ _parse_register_params,
23
+ _pool_override_from_url,
18
24
  _supports,
19
25
  create_engine_from_paths,
20
26
  olap,
21
27
  stable_session_hint,
22
28
  )
23
29
  from duckdb_sqlalchemy import datatypes as dt
30
+ from duckdb_sqlalchemy import motherduck as md
24
31
  from duckdb_sqlalchemy.config import TYPES, apply_config, get_core_config
25
32
 
26
33
 
@@ -472,3 +479,141 @@ def test_struct_or_union_requires_fields() -> None:
472
479
  assert rendered.startswith("(")
473
480
  assert rendered.endswith(")")
474
481
  assert '"first name"' in rendered
482
+
483
+
484
+ def test_parse_register_params_dict_and_tuple() -> None:
485
+ view_name, df = _parse_register_params({"view_name": "v", "df": "data"})
486
+ assert view_name == "v"
487
+ assert df == "data"
488
+
489
+ view_name, df = _parse_register_params(("v2", "data2"))
490
+ assert view_name == "v2"
491
+ assert df == "data2"
492
+
493
+
494
+ def test_parse_register_params_errors() -> None:
495
+ with pytest.raises(ValueError):
496
+ _parse_register_params(None)
497
+
498
+ with pytest.raises(ValueError):
499
+ _parse_register_params({"name": "v"})
500
+
501
+ with pytest.raises(ValueError):
502
+ _parse_register_params(("only-one",))
503
+
504
+
505
+ def test_normalize_execution_options_insertmanyvalues() -> None:
506
+ original = {"duckdb_insertmanyvalues_page_size": 123}
507
+ normalized = _normalize_execution_options(original)
508
+ assert normalized["insertmanyvalues_page_size"] == 123
509
+ assert "insertmanyvalues_page_size" not in original
510
+
511
+ already = {
512
+ "duckdb_insertmanyvalues_page_size": 5,
513
+ "insertmanyvalues_page_size": 10,
514
+ }
515
+ normalized = _normalize_execution_options(already)
516
+ assert normalized["insertmanyvalues_page_size"] == 10
517
+
518
+
519
+ def test_idempotent_statement_detection() -> None:
520
+ assert _is_idempotent_statement("SELECT 1")
521
+ assert _is_idempotent_statement(" show tables")
522
+ assert _is_idempotent_statement("pragma version")
523
+ assert not _is_idempotent_statement("insert into t values (1)")
524
+
525
+
526
+ def test_transient_error_detection() -> None:
527
+ assert _is_transient_error(RuntimeError("HTTP Error: 503 Service Unavailable"))
528
+ assert not _is_transient_error(RuntimeError("connection reset by peer"))
529
+ assert not _is_transient_error(RuntimeError("HTTP Error: 503 connection reset"))
530
+
531
+
532
+ def test_pool_override_from_url_and_env(monkeypatch: pytest.MonkeyPatch) -> None:
533
+ url = URL(database=":memory:", query={"duckdb_sqlalchemy_pool": ["Queue"]})
534
+ assert _pool_override_from_url(url) == "queue"
535
+
536
+ monkeypatch.setenv("DUCKDB_SQLALCHEMY_POOL", "Null")
537
+ url = URL(database=":memory:")
538
+ assert _pool_override_from_url(url) == "null"
539
+
540
+
541
+ def test_pool_class_for_empty_database() -> None:
542
+ url = SAURL.create("duckdb")
543
+ assert Dialect.get_pool_class(url) is pool.SingletonThreadPool
544
+
545
+
546
+ def test_apply_config_handles_none_path_decimal() -> None:
547
+ import decimal
548
+ from pathlib import Path
549
+
550
+ dialect = Dialect()
551
+
552
+ class DummyConn:
553
+ def __init__(self) -> None:
554
+ self.executed = []
555
+
556
+ def execute(self, statement: str) -> None:
557
+ self.executed.append(statement)
558
+
559
+ conn = DummyConn()
560
+ ext = {
561
+ "memory_limit": None,
562
+ "data_path": Path("/tmp/data"),
563
+ "ratio": decimal.Decimal("1.5"),
564
+ }
565
+
566
+ apply_config(
567
+ dialect,
568
+ conn,
569
+ cast(dict[str, str | int | bool | float | None], ext),
570
+ )
571
+
572
+ string_processor = String().literal_processor(dialect=dialect)
573
+ expected = [
574
+ "SET memory_limit = NULL",
575
+ f"SET data_path = {string_processor(str(Path('/tmp/data')))}",
576
+ f"SET ratio = {string_processor(str(decimal.Decimal('1.5')))}",
577
+ ]
578
+ assert conn.executed == expected
579
+
580
+
581
+ def test_motherduck_helpers() -> None:
582
+ url = md.MotherDuckURL(
583
+ database="md:db",
584
+ query={"memory_limit": "1GB"},
585
+ path_query={"user": "alice", "session_hint": "team"},
586
+ )
587
+ assert url.database.startswith("md:db?")
588
+ assert url.query == {"memory_limit": "1GB"}
589
+
590
+ appended = md.append_query_to_database("md:db?user=alice", {"session_hint": "s"})
591
+ assert appended == "md:db?user=alice&session_hint=s"
592
+
593
+ normalized = md._normalize_path_item("duckdb:///tmp.db")
594
+ assert normalized.drivername == "duckdb"
595
+
596
+ normalized = md._normalize_path_item("md:db")
597
+ assert normalized.database == "md:db"
598
+
599
+
600
+ def test_merge_and_copy_connect_args() -> None:
601
+ base = {"config": {"threads": 2}, "url_config": {"memory_limit": "1GB"}}
602
+ extra = {"config": {"threads": 4}, "url_config": {"s3_region": "us-east-1"}}
603
+ merged = md._merge_connect_args(base, extra)
604
+
605
+ assert merged["config"] == {"threads": 4}
606
+ assert merged["url_config"] == {"memory_limit": "1GB", "s3_region": "us-east-1"}
607
+
608
+ copied = md._copy_connect_params(merged)
609
+ copied["config"]["threads"] = 1
610
+ copied["url_config"]["memory_limit"] = "2GB"
611
+ assert merged["config"]["threads"] == 4
612
+ assert merged["url_config"]["memory_limit"] == "1GB"
613
+
614
+
615
+ def test_create_engine_from_paths_driver_mismatch() -> None:
616
+ url1 = SAURL.create("duckdb", database=":memory:")
617
+ url2 = SAURL.create("sqlite", database=":memory:")
618
+ with pytest.raises(ValueError):
619
+ create_engine_from_paths([url1, url2])
@@ -0,0 +1,24 @@
1
+ Project: duckdb-sqlalchemy
2
+ Summary: DuckDB SQLAlchemy dialect for DuckDB and MotherDuck. Supports SQLAlchemy Core and ORM APIs with pooling defaults, type mappings, and bulk insert helpers.
3
+
4
+ Key entry points:
5
+ - sqlalchemy.create_engine("duckdb://...")
6
+ - duckdb_sqlalchemy.URL and duckdb_sqlalchemy.MotherDuckURL
7
+ - duckdb_sqlalchemy.create_motherduck_engine
8
+ - duckdb_sqlalchemy.olap helpers (read_parquet, read_csv_auto, table_function)
9
+
10
+ Docs:
11
+ - docs/README.md (index)
12
+ - docs/connection-urls.md
13
+ - docs/motherduck.md
14
+ - docs/configuration.md
15
+ - docs/olap.md
16
+ - docs/pandas-jupyter.md
17
+ - docs/types-and-caveats.md
18
+ - docs/alembic.md
19
+ - docs/migration-from-duckdb-engine.md
20
+
21
+ Compatibility:
22
+ - Python 3.9+
23
+ - SQLAlchemy 1.3.22+ (2.x recommended)
24
+ - DuckDB 1.3.0+ (1.4.3 recommended)
@@ -1,14 +1,30 @@
1
1
  [project]
2
2
  name = "duckdb-sqlalchemy"
3
- version = "0.19.2"
4
- description = "SQLAlchemy driver for duckdb"
3
+ version = "0.19.3"
4
+ description = "DuckDB SQLAlchemy dialect for DuckDB and MotherDuck"
5
5
  authors = [
6
- {name = "Leonardo Vida", email = "leonardo@motherduck.com"},
6
+ {name = "Leonardo Vida", email = "lleonardovida@gmail.com"},
7
7
  ]
8
8
  license = "MIT"
9
9
  license-files = ["LICENSE.txt"]
10
10
  requires-python = ">=3.9,<4"
11
11
  readme = "README.md"
12
+ keywords = ["duckdb", "sqlalchemy", "motherduck", "database", "analytics", "olap", "dialect"]
13
+ classifiers = [
14
+ "Development Status :: 5 - Production/Stable",
15
+ "Intended Audience :: Developers",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3 :: Only",
19
+ "Programming Language :: Python :: 3.9",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Programming Language :: Python :: 3.14",
25
+ "Topic :: Database",
26
+ "Topic :: Database :: Front-Ends",
27
+ ]
12
28
  dependencies = [
13
29
  "duckdb>=0.5.0",
14
30
  "sqlalchemy>=1.3.22",
@@ -18,6 +34,7 @@ dependencies = [
18
34
  [project.urls]
19
35
  "Bug Tracker" = "https://github.com/leonardovida/duckdb-sqlalchemy/issues"
20
36
  Changelog = "https://github.com/leonardovida/duckdb-sqlalchemy/releases"
37
+ Documentation = "https://leonardovida.github.io/duckdb-sqlalchemy/"
21
38
  repository = "https://github.com/leonardovida/duckdb-sqlalchemy"
22
39
  Upstream = "https://github.com/Mause/duckdb_engine"
23
40