excel-dbapi 0.1.4__tar.gz → 0.2.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.
- excel_dbapi-0.2.0/.github/ISSUE_TEMPLATE/bug_report.md +32 -0
- excel_dbapi-0.2.0/.github/ISSUE_TEMPLATE/feature_request.md +16 -0
- excel_dbapi-0.2.0/.github/ISSUE_TEMPLATE/release_checklist.md +23 -0
- excel_dbapi-0.2.0/.github/pull_request_template.md +13 -0
- excel_dbapi-0.2.0/.github/workflows/ci.yml +36 -0
- excel_dbapi-0.2.0/.github/workflows/publish-pypi.yml +28 -0
- excel_dbapi-0.2.0/.gitignore +34 -0
- excel_dbapi-0.2.0/CHANGELOG.md +18 -0
- excel_dbapi-0.2.0/PKG-INFO +280 -0
- excel_dbapi-0.2.0/README.md +240 -0
- excel_dbapi-0.2.0/docs/DEVELOPMENT.md +80 -0
- excel_dbapi-0.2.0/docs/OPERATIONS.md +25 -0
- excel_dbapi-0.2.0/docs/PUBLIC_ROADMAP.md +19 -0
- excel_dbapi-0.2.0/docs/QUICKSTART_10_MIN.md +36 -0
- excel_dbapi-0.2.0/docs/ROADMAP.md +106 -0
- excel_dbapi-0.2.0/docs/USAGE.md +118 -0
- excel_dbapi-0.2.0/examples/advanced_query.py +17 -0
- excel_dbapi-0.2.0/examples/basic_usage.py +15 -0
- excel_dbapi-0.2.0/examples/education/lesson_01_first_query.py +8 -0
- excel_dbapi-0.2.0/examples/education/lesson_02_parameter_binding.py +7 -0
- excel_dbapi-0.2.0/examples/pandas_engine.py +14 -0
- excel_dbapi-0.2.0/examples/transactions.py +14 -0
- excel_dbapi-0.2.0/examples/write_operations.py +20 -0
- excel_dbapi-0.2.0/pyproject.toml +70 -0
- excel_dbapi-0.2.0/src/excel_dbapi/__init__.py +78 -0
- excel_dbapi-0.2.0/src/excel_dbapi/connection.py +188 -0
- excel_dbapi-0.2.0/src/excel_dbapi/cursor.py +149 -0
- excel_dbapi-0.2.0/src/excel_dbapi/engines/__init__.py +12 -0
- excel_dbapi-0.2.0/src/excel_dbapi/engines/base.py +80 -0
- excel_dbapi-0.2.0/src/excel_dbapi/engines/graph/__init__.py +5 -0
- excel_dbapi-0.2.0/src/excel_dbapi/engines/graph/auth.py +132 -0
- excel_dbapi-0.2.0/src/excel_dbapi/engines/graph/backend.py +380 -0
- excel_dbapi-0.2.0/src/excel_dbapi/engines/graph/client.py +146 -0
- excel_dbapi-0.2.0/src/excel_dbapi/engines/graph/locator.py +42 -0
- excel_dbapi-0.2.0/src/excel_dbapi/engines/graph/session.py +71 -0
- excel_dbapi-0.2.0/src/excel_dbapi/engines/openpyxl/__init__.py +3 -0
- excel_dbapi-0.2.0/src/excel_dbapi/engines/openpyxl/backend.py +138 -0
- excel_dbapi-0.2.0/src/excel_dbapi/engines/pandas/__init__.py +3 -0
- excel_dbapi-0.2.0/src/excel_dbapi/engines/pandas/backend.py +127 -0
- excel_dbapi-0.2.0/src/excel_dbapi/engines/registry.py +61 -0
- excel_dbapi-0.2.0/src/excel_dbapi/engines/result.py +24 -0
- excel_dbapi-0.2.0/src/excel_dbapi/exceptions.py +52 -0
- excel_dbapi-0.2.0/src/excel_dbapi/executor.py +363 -0
- excel_dbapi-0.2.0/src/excel_dbapi/openpyxl/__init__.py +22 -0
- excel_dbapi-0.2.0/src/excel_dbapi/parser.py +521 -0
- excel_dbapi-0.2.0/src/excel_dbapi/reflection.py +181 -0
- excel_dbapi-0.2.0/src/excel_dbapi/sanitize.py +52 -0
- excel_dbapi-0.2.0/tests/data/sample.xlsx +0 -0
- excel_dbapi-0.2.0/tests/graph/__init__.py +0 -0
- excel_dbapi-0.2.0/tests/graph/test_auth.py +106 -0
- excel_dbapi-0.2.0/tests/graph/test_backend.py +764 -0
- excel_dbapi-0.2.0/tests/graph/test_client.py +207 -0
- excel_dbapi-0.2.0/tests/graph/test_locator.py +46 -0
- excel_dbapi-0.2.0/tests/test_additional_coverage.py +70 -0
- excel_dbapi-0.2.0/tests/test_api_extensions.py +226 -0
- excel_dbapi-0.2.0/tests/test_atomic_rollback_integration.py +52 -0
- excel_dbapi-0.2.0/tests/test_base_engine.py +55 -0
- excel_dbapi-0.2.0/tests/test_connection.py +26 -0
- excel_dbapi-0.2.0/tests/test_connection_graph.py +399 -0
- excel_dbapi-0.2.0/tests/test_cursor.py +41 -0
- excel_dbapi-0.2.0/tests/test_engine.py +14 -0
- excel_dbapi-0.2.0/tests/test_engine_state.py +50 -0
- excel_dbapi-0.2.0/tests/test_error_paths.py +94 -0
- excel_dbapi-0.2.0/tests/test_exceptions.py +12 -0
- excel_dbapi-0.2.0/tests/test_executor.py +21 -0
- excel_dbapi-0.2.0/tests/test_formula_injection.py +203 -0
- excel_dbapi-0.2.0/tests/test_integration.py +11 -0
- excel_dbapi-0.2.0/tests/test_openpyxl_edge_cases.py +18 -0
- excel_dbapi-0.2.0/tests/test_openpyxl_facade.py +134 -0
- excel_dbapi-0.2.0/tests/test_parser.py +74 -0
- excel_dbapi-0.2.0/tests/test_parser_errors.py +58 -0
- excel_dbapi-0.2.0/tests/test_pep249_compliance.py +217 -0
- excel_dbapi-0.2.0/tests/test_sql_boundaries.py +18 -0
- excel_dbapi-0.2.0/tests/test_sql_extensions.py +183 -0
- excel_dbapi-0.2.0/tests/test_sql_features.py +133 -0
- excel_dbapi-0.2.0/tests/test_stage1_fixes.py +356 -0
- excel_dbapi-0.2.0/tests/test_where_operators.py +44 -0
- excel_dbapi-0.2.0/tests/test_write_operations.py +175 -0
- excel_dbapi-0.1.4/.gitignore +0 -91
- excel_dbapi-0.1.4/PKG-INFO +0 -21
- excel_dbapi-0.1.4/excel_dbapi/__init__.py +0 -3
- excel_dbapi-0.1.4/excel_dbapi/api.py +0 -9
- excel_dbapi-0.1.4/excel_dbapi/connection.py +0 -75
- excel_dbapi-0.1.4/excel_dbapi/cursor.py +0 -75
- excel_dbapi-0.1.4/excel_dbapi/engines/openpyxl_engine.py +0 -46
- excel_dbapi-0.1.4/excel_dbapi/exceptions.py +0 -34
- excel_dbapi-0.1.4/excel_dbapi/query.py +0 -54
- excel_dbapi-0.1.4/excel_dbapi/remote.py +0 -17
- excel_dbapi-0.1.4/excel_dbapi/table.py +0 -53
- excel_dbapi-0.1.4/pyproject.toml +0 -26
- {excel_dbapi-0.1.4 → excel_dbapi-0.2.0}/LICENSE +0 -0
- {excel_dbapi-0.1.4/excel_dbapi/engines → excel_dbapi-0.2.0/tests}/__init__.py +0 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Report a reproducible problem in excel-dbapi
|
|
4
|
+
labels: bug
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Summary
|
|
8
|
+
|
|
9
|
+
<!-- concise description -->
|
|
10
|
+
|
|
11
|
+
## Reproduction
|
|
12
|
+
|
|
13
|
+
1.
|
|
14
|
+
2.
|
|
15
|
+
3.
|
|
16
|
+
|
|
17
|
+
## Expected behavior
|
|
18
|
+
|
|
19
|
+
## Actual behavior
|
|
20
|
+
|
|
21
|
+
## Environment
|
|
22
|
+
|
|
23
|
+
- excel-dbapi version:
|
|
24
|
+
- Python version:
|
|
25
|
+
- OS:
|
|
26
|
+
- Engine: openpyxl / pandas
|
|
27
|
+
|
|
28
|
+
## Sample code / logs
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
paste traceback or snippet
|
|
32
|
+
```
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request
|
|
3
|
+
about: Suggest an enhancement aligned with project boundaries
|
|
4
|
+
labels: enhancement
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Problem statement
|
|
8
|
+
|
|
9
|
+
## Proposed solution
|
|
10
|
+
|
|
11
|
+
## Alternatives considered
|
|
12
|
+
|
|
13
|
+
## Scope check
|
|
14
|
+
|
|
15
|
+
- [ ] This does not require full SQL-engine behavior (JOIN/GROUP BY/subquery)
|
|
16
|
+
- [ ] This fits DB-API style Excel workflows
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Release checklist
|
|
3
|
+
about: Track release prep
|
|
4
|
+
labels: release
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Version
|
|
8
|
+
|
|
9
|
+
- [ ] VERSION updated
|
|
10
|
+
- [ ] pyproject.toml version updated
|
|
11
|
+
- [ ] CHANGELOG updated
|
|
12
|
+
- [ ] Tag planned (`vX.Y.Z`)
|
|
13
|
+
|
|
14
|
+
## Validation
|
|
15
|
+
|
|
16
|
+
- [ ] CI green
|
|
17
|
+
- [ ] Coverage artifact generated (`coverage.xml`)
|
|
18
|
+
- [ ] `python -m build` passes
|
|
19
|
+
|
|
20
|
+
## Publish
|
|
21
|
+
|
|
22
|
+
- [ ] Trusted Publishing environment configured
|
|
23
|
+
- [ ] Release notes drafted
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
## Related issue
|
|
4
|
+
|
|
5
|
+
Fixes #
|
|
6
|
+
|
|
7
|
+
## Checklist
|
|
8
|
+
|
|
9
|
+
- [ ] Focused change (no unrelated refactor)
|
|
10
|
+
- [ ] Tests added/updated
|
|
11
|
+
- [ ] Docs updated if behavior changed
|
|
12
|
+
- [ ] `pytest` passes locally
|
|
13
|
+
- [ ] Boundary maintained (not expanding to full SQL engine)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
strategy:
|
|
11
|
+
matrix:
|
|
12
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- name: Set up Python
|
|
16
|
+
uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: ${{ matrix.python-version }}
|
|
19
|
+
- name: Install dependencies
|
|
20
|
+
run: |
|
|
21
|
+
python -m pip install --upgrade pip
|
|
22
|
+
pip install -e ".[dev,pandas]"
|
|
23
|
+
- name: Run tests with coverage
|
|
24
|
+
run: pytest tests/ -v --cov=excel_dbapi --cov-report=xml --cov-report=term-missing
|
|
25
|
+
- name: Upload coverage to Codecov
|
|
26
|
+
if: matrix.python-version == '3.12'
|
|
27
|
+
uses: codecov/codecov-action@v5
|
|
28
|
+
with:
|
|
29
|
+
files: coverage.xml
|
|
30
|
+
fail_ci_if_error: false
|
|
31
|
+
- name: Run ruff
|
|
32
|
+
run: ruff check src/
|
|
33
|
+
- name: Run ruff format check
|
|
34
|
+
run: ruff format --check src/
|
|
35
|
+
- name: Run mypy strict
|
|
36
|
+
run: mypy --strict src/
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
environment: pypi
|
|
11
|
+
permissions:
|
|
12
|
+
id-token: write
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- name: Set up Python
|
|
17
|
+
uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.12"
|
|
20
|
+
|
|
21
|
+
- name: Install build tools
|
|
22
|
+
run: pip install build
|
|
23
|
+
|
|
24
|
+
- name: Build package
|
|
25
|
+
run: python -m build
|
|
26
|
+
|
|
27
|
+
- name: Publish to PyPI
|
|
28
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
*.py[cod]
|
|
5
|
+
*.so
|
|
6
|
+
|
|
7
|
+
# Virtual environments
|
|
8
|
+
.venv/
|
|
9
|
+
venv/
|
|
10
|
+
env/
|
|
11
|
+
|
|
12
|
+
# Tool caches
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
.mypy_cache/
|
|
15
|
+
.ruff_cache/
|
|
16
|
+
.coverage
|
|
17
|
+
coverage.xml
|
|
18
|
+
htmlcov/
|
|
19
|
+
|
|
20
|
+
# Build artifacts
|
|
21
|
+
build/
|
|
22
|
+
dist/
|
|
23
|
+
*.egg-info/
|
|
24
|
+
|
|
25
|
+
# Data files
|
|
26
|
+
*.xlsx
|
|
27
|
+
!tests/data/*.xlsx
|
|
28
|
+
|
|
29
|
+
# IDE
|
|
30
|
+
.vscode/
|
|
31
|
+
.idea/
|
|
32
|
+
|
|
33
|
+
# OS
|
|
34
|
+
.DS_Store
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [0.1.0] - 2026-04-12
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- PEP 249 (DB-API 2.0) compliant driver for Excel files
|
|
9
|
+
- SQL support: SELECT, INSERT, UPDATE, DELETE, CREATE TABLE, DROP TABLE
|
|
10
|
+
- WHERE clauses with AND/OR, comparison operators, LIKE, IN, IS NULL/IS NOT NULL
|
|
11
|
+
- ORDER BY and LIMIT for SELECT queries
|
|
12
|
+
- Openpyxl engine (default) for local .xlsx files
|
|
13
|
+
- Pandas engine (optional) for DataFrame-based operations
|
|
14
|
+
- Microsoft Graph API engine (optional) for remote Excel files
|
|
15
|
+
- Formula injection defense (enabled by default)
|
|
16
|
+
- Transaction simulation (commit/rollback)
|
|
17
|
+
- Reflection helpers for dialect integration
|
|
18
|
+
- Metadata sheet support for schema persistence
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: excel-dbapi
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: PEP 249 compliant DB-API driver for Excel files
|
|
5
|
+
Project-URL: Homepage, https://github.com/yeongseon/excel-dbapi
|
|
6
|
+
Project-URL: Repository, https://github.com/yeongseon/excel-dbapi
|
|
7
|
+
Project-URL: Issues, https://github.com/yeongseon/excel-dbapi/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/yeongseon/excel-dbapi/blob/main/CHANGELOG.md
|
|
9
|
+
Author-email: Yeongseon Choe <yeongseon.choe@gmail.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: db-api,excel,openpyxl,pandas,sql
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Education
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Database
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Requires-Dist: openpyxl<4.0.0,>=3.1.0
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: httpx>=0.27; extra == 'dev'
|
|
28
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
32
|
+
Provides-Extra: graph
|
|
33
|
+
Requires-Dist: httpx>=0.27; extra == 'graph'
|
|
34
|
+
Provides-Extra: graph-azure
|
|
35
|
+
Requires-Dist: azure-identity>=1.15; extra == 'graph-azure'
|
|
36
|
+
Requires-Dist: httpx>=0.27; extra == 'graph-azure'
|
|
37
|
+
Provides-Extra: pandas
|
|
38
|
+
Requires-Dist: pandas<3.0.0,>=2.0.0; extra == 'pandas'
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# excel-dbapi
|
|
43
|
+
|
|
44
|
+

|
|
45
|
+
[](https://codecov.io/gh/yeongseon/excel-dbapi)
|
|
46
|
+
[](https://www.python.org/downloads/)
|
|
47
|
+
[](https://opensource.org/licenses/MIT)
|
|
48
|
+
|
|
49
|
+
A lightweight, Python DB-API 2.0 compliant connector for Excel files.
|
|
50
|
+
Use SQL to query, insert, update, and delete rows in `.xlsx` workbooks — no database server required.
|
|
51
|
+
|
|
52
|
+
## Who is this for?
|
|
53
|
+
|
|
54
|
+
- **Data analysts** who want to query Excel files with SQL instead of manual filtering
|
|
55
|
+
- **Citizen developers** automating small workflows with familiar SQL syntax
|
|
56
|
+
- **Educators** teaching SQL concepts without setting up a database
|
|
57
|
+
- **Prototypers** building quick data pipelines before moving to a real database
|
|
58
|
+
|
|
59
|
+
### Who is this NOT for?
|
|
60
|
+
|
|
61
|
+
- If you need JOINs, GROUP BY, subqueries, or advanced SQL → use SQLite or PostgreSQL
|
|
62
|
+
- If you need concurrent writes from multiple processes → use a real database
|
|
63
|
+
- If your Excel file has 100k+ rows → use pandas directly or a database
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Features
|
|
68
|
+
|
|
69
|
+
- Python DB-API 2.0 compliant interface (PEP 249)
|
|
70
|
+
- Query Excel files using SQL syntax
|
|
71
|
+
- Supports SELECT, INSERT, UPDATE, DELETE
|
|
72
|
+
- Basic DDL support (CREATE TABLE, DROP TABLE)
|
|
73
|
+
- WHERE conditions with AND/OR and comparison operators
|
|
74
|
+
- ORDER BY and LIMIT for SELECT
|
|
75
|
+
- Sheet-to-Table mapping
|
|
76
|
+
- Pandas & Openpyxl engine selector
|
|
77
|
+
- Formula injection defense (enabled by default)
|
|
78
|
+
- Transaction simulation (commit/rollback)
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Installation
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pip install excel-dbapi
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
See [CHANGELOG](CHANGELOG.md) for release history.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Quick Start
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from excel_dbapi.connection import ExcelConnection
|
|
96
|
+
|
|
97
|
+
# Open an Excel file and query it
|
|
98
|
+
with ExcelConnection("sample.xlsx") as conn:
|
|
99
|
+
cursor = conn.cursor()
|
|
100
|
+
cursor.execute("SELECT * FROM Sheet1")
|
|
101
|
+
print(cursor.fetchall())
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Insert, Update, Delete
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
with ExcelConnection("sample.xlsx") as conn:
|
|
108
|
+
cursor = conn.cursor()
|
|
109
|
+
|
|
110
|
+
# Insert with parameter binding (recommended)
|
|
111
|
+
cursor.execute("INSERT INTO Sheet1 (id, name) VALUES (?, ?)", (1, "Alice"))
|
|
112
|
+
|
|
113
|
+
# Update
|
|
114
|
+
cursor.execute("UPDATE Sheet1 SET name = 'Ann' WHERE id = 1")
|
|
115
|
+
|
|
116
|
+
# Delete
|
|
117
|
+
cursor.execute("DELETE FROM Sheet1 WHERE id = 2")
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Create and Drop Sheets
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
with ExcelConnection("sample.xlsx") as conn:
|
|
124
|
+
cursor = conn.cursor()
|
|
125
|
+
cursor.execute("CREATE TABLE NewSheet (id, name)")
|
|
126
|
+
cursor.execute("DROP TABLE NewSheet")
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Engine Options
|
|
130
|
+
|
|
131
|
+
| Engine | Description | Dependency |
|
|
132
|
+
|--------|-------------|------------|
|
|
133
|
+
| openpyxl (default) | Fast sheet access | openpyxl |
|
|
134
|
+
| pandas | DataFrame-based operations | pandas, openpyxl |
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
conn = ExcelConnection("sample.xlsx", engine="openpyxl") # default
|
|
138
|
+
conn = ExcelConnection("sample.xlsx", engine="pandas")
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Safety Defaults
|
|
144
|
+
|
|
145
|
+
### Formula Injection Defense
|
|
146
|
+
|
|
147
|
+
By default, `excel-dbapi` sanitizes cell values on write (INSERT/UPDATE) to prevent
|
|
148
|
+
[formula injection attacks](https://owasp.org/www-community/attacks/CSV_Injection).
|
|
149
|
+
Strings starting with `=`, `+`, `-`, `@`, `\t`, or `\r` are automatically prefixed
|
|
150
|
+
with a single quote (`'`) so they are stored as plain text, not executed as formulas.
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
# Default: sanitization ON (recommended)
|
|
154
|
+
with ExcelConnection("sample.xlsx") as conn:
|
|
155
|
+
cursor = conn.cursor()
|
|
156
|
+
cursor.execute("INSERT INTO Sheet1 (id, name) VALUES (?, ?)",
|
|
157
|
+
(1, "=SUM(A1:A10)"))
|
|
158
|
+
# Stored as: '=SUM(A1:A10) (safe, not executed as formula)
|
|
159
|
+
|
|
160
|
+
# Opt out if you intentionally write formulas
|
|
161
|
+
with ExcelConnection("sample.xlsx", sanitize_formulas=False) as conn:
|
|
162
|
+
cursor = conn.cursor()
|
|
163
|
+
cursor.execute("INSERT INTO Sheet1 (id, formula) VALUES (?, ?)",
|
|
164
|
+
(1, "=SUM(A1:A10)"))
|
|
165
|
+
# Stored as: =SUM(A1:A10) (executed as formula in Excel)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Transaction Example
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
with ExcelConnection("sample.xlsx", autocommit=False) as conn:
|
|
174
|
+
cursor = conn.cursor()
|
|
175
|
+
cursor.execute("UPDATE Sheet1 SET name = 'Ann' WHERE id = 1")
|
|
176
|
+
conn.rollback()
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
When autocommit is enabled, `rollback()` is not supported.
|
|
180
|
+
|
|
181
|
+
## Cursor Metadata
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
with ExcelConnection("sample.xlsx") as conn:
|
|
185
|
+
cursor = conn.cursor()
|
|
186
|
+
cursor.execute("SELECT id, name FROM Sheet1")
|
|
187
|
+
print(cursor.description)
|
|
188
|
+
print(cursor.rowcount)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Troubleshooting
|
|
194
|
+
|
|
195
|
+
### "Column 'xyz' not found"
|
|
196
|
+
|
|
197
|
+
The column name in your SQL doesn't match any header in the sheet.
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
ProgrammingError: Column 'nmae' not found in Sheet1. Available columns: ['id', 'name', 'email']
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Fix:** Check the spelling. Column names must match the first row (header) of the sheet exactly.
|
|
204
|
+
|
|
205
|
+
### "Table 'SheetX' not found"
|
|
206
|
+
|
|
207
|
+
The sheet name in your SQL doesn't match any sheet in the workbook.
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
ProgrammingError: Table 'Shee1' not found. Available sheets: ['Sheet1', 'Sheet2']
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**Fix:** Check the sheet name spelling. Use the exact sheet name (case-sensitive) shown in your Excel file.
|
|
214
|
+
|
|
215
|
+
### PandasEngine drops formatting
|
|
216
|
+
|
|
217
|
+
`PandasEngine` reads data into a DataFrame and writes it back. This process drops
|
|
218
|
+
Excel formatting, charts, images, and formulas.
|
|
219
|
+
|
|
220
|
+
**Fix:** Use the default `openpyxl` engine if you need to preserve formatting.
|
|
221
|
+
|
|
222
|
+
### Integer vs. string comparison (Pandas)
|
|
223
|
+
|
|
224
|
+
The Pandas engine preserves Python types. If a column contains integers,
|
|
225
|
+
`WHERE id = '2'` (string) won't match — use `WHERE id = 2` (no quotes).
|
|
226
|
+
|
|
227
|
+
**Fix:** Omit quotes around numeric values in WHERE clauses when using the Pandas engine.
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Limitations and Operational Guidance
|
|
232
|
+
|
|
233
|
+
- `PandasEngine` rewrites workbooks and may drop formatting, charts, and formulas.
|
|
234
|
+
- `OpenpyxlEngine` loads with `data_only=True`, so formulas are evaluated to values when reading.
|
|
235
|
+
- Use a **single-writer model** for writes. Avoid writing to the same file from multiple processes.
|
|
236
|
+
- Save is implemented with a temporary file + atomic replace (`os.replace`) for safer persistence.
|
|
237
|
+
- No support for JOIN, GROUP BY, HAVING, or subqueries.
|
|
238
|
+
|
|
239
|
+
## Roadmap
|
|
240
|
+
|
|
241
|
+
- Remote file connection improvements
|
|
242
|
+
|
|
243
|
+
See [Project Roadmap](docs/ROADMAP.md) for details.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
## Related Projects
|
|
249
|
+
|
|
250
|
+
### sqlalchemy-excel
|
|
251
|
+
|
|
252
|
+
[sqlalchemy-excel](https://github.com/yeongseon/sqlalchemy-excel) is a higher-level toolkit that uses excel-dbapi as its core Excel I/O layer. It provides SQLAlchemy model-driven template generation, server-side validation, database import, and export.
|
|
253
|
+
|
|
254
|
+
- **Which package should I use?** See the [decision guide](https://github.com/yeongseon/sqlalchemy-excel/blob/main/docs/which-package.md)
|
|
255
|
+
- **Interface contract**: See the [compatibility documentation](https://github.com/yeongseon/sqlalchemy-excel/blob/main/docs/compatibility.md)
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Documentation
|
|
260
|
+
|
|
261
|
+
- [Usage Guide](docs/USAGE.md)
|
|
262
|
+
- [Development Guide](docs/DEVELOPMENT.md)
|
|
263
|
+
- [Project Roadmap](docs/ROADMAP.md)
|
|
264
|
+
- [10-Minute Quickstart](docs/QUICKSTART_10_MIN.md)
|
|
265
|
+
- [Operations Notes](docs/OPERATIONS.md)
|
|
266
|
+
- [Public Roadmap](docs/PUBLIC_ROADMAP.md)
|
|
267
|
+
|
|
268
|
+
## Examples
|
|
269
|
+
|
|
270
|
+
- `examples/basic_usage.py`
|
|
271
|
+
- `examples/write_operations.py`
|
|
272
|
+
- `examples/transactions.py`
|
|
273
|
+
- `examples/advanced_query.py`
|
|
274
|
+
- `examples/pandas_engine.py`
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## License
|
|
279
|
+
|
|
280
|
+
MIT License
|