hawkapi-sqlalchemy 0.1.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.
Files changed (27) hide show
  1. hawkapi_sqlalchemy-0.1.0/.github/workflows/ci.yml +52 -0
  2. hawkapi_sqlalchemy-0.1.0/.github/workflows/release.yml +25 -0
  3. hawkapi_sqlalchemy-0.1.0/.gitignore +35 -0
  4. hawkapi_sqlalchemy-0.1.0/CHANGELOG.md +15 -0
  5. hawkapi_sqlalchemy-0.1.0/LICENSE +21 -0
  6. hawkapi_sqlalchemy-0.1.0/PKG-INFO +217 -0
  7. hawkapi_sqlalchemy-0.1.0/README.md +160 -0
  8. hawkapi_sqlalchemy-0.1.0/pyproject.toml +75 -0
  9. hawkapi_sqlalchemy-0.1.0/src/hawkapi_sqlalchemy/__init__.py +41 -0
  10. hawkapi_sqlalchemy-0.1.0/src/hawkapi_sqlalchemy/_alembic.py +99 -0
  11. hawkapi_sqlalchemy-0.1.0/src/hawkapi_sqlalchemy/_database.py +133 -0
  12. hawkapi_sqlalchemy-0.1.0/src/hawkapi_sqlalchemy/_engine.py +67 -0
  13. hawkapi_sqlalchemy-0.1.0/src/hawkapi_sqlalchemy/_health.py +35 -0
  14. hawkapi_sqlalchemy-0.1.0/src/hawkapi_sqlalchemy/_models.py +52 -0
  15. hawkapi_sqlalchemy-0.1.0/src/hawkapi_sqlalchemy/_session.py +64 -0
  16. hawkapi_sqlalchemy-0.1.0/src/hawkapi_sqlalchemy/_testing.py +51 -0
  17. hawkapi_sqlalchemy-0.1.0/src/hawkapi_sqlalchemy/alembic.py +8 -0
  18. hawkapi_sqlalchemy-0.1.0/src/hawkapi_sqlalchemy/py.typed +0 -0
  19. hawkapi_sqlalchemy-0.1.0/tests/__init__.py +0 -0
  20. hawkapi_sqlalchemy-0.1.0/tests/conftest.py +41 -0
  21. hawkapi_sqlalchemy-0.1.0/tests/test_database.py +68 -0
  22. hawkapi_sqlalchemy-0.1.0/tests/test_engine.py +30 -0
  23. hawkapi_sqlalchemy-0.1.0/tests/test_health.py +26 -0
  24. hawkapi_sqlalchemy-0.1.0/tests/test_models.py +39 -0
  25. hawkapi_sqlalchemy-0.1.0/tests/test_plugin.py +117 -0
  26. hawkapi_sqlalchemy-0.1.0/tests/test_testing.py +26 -0
  27. hawkapi_sqlalchemy-0.1.0/uv.lock +482 -0
@@ -0,0 +1,52 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ lint:
10
+ name: Lint
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - uses: astral-sh/setup-uv@v4
15
+ with:
16
+ enable-cache: true
17
+ - name: Install dependencies
18
+ run: uv sync --extra dev
19
+ - name: ruff check
20
+ run: uv run ruff check .
21
+ - name: ruff format check
22
+ run: uv run ruff format --check .
23
+
24
+ typecheck:
25
+ name: Typecheck
26
+ runs-on: ubuntu-latest
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+ - uses: astral-sh/setup-uv@v4
30
+ with:
31
+ enable-cache: true
32
+ - name: Install dependencies
33
+ run: uv sync --extra dev
34
+ - name: pyright
35
+ run: uv run pyright src/
36
+
37
+ test:
38
+ name: Test (Python ${{ matrix.python-version }})
39
+ runs-on: ubuntu-latest
40
+ strategy:
41
+ matrix:
42
+ python-version: ["3.12", "3.13"]
43
+ steps:
44
+ - uses: actions/checkout@v4
45
+ - uses: astral-sh/setup-uv@v4
46
+ with:
47
+ enable-cache: true
48
+ python-version: ${{ matrix.python-version }}
49
+ - name: Install dependencies
50
+ run: uv sync --extra dev
51
+ - name: Run tests
52
+ run: uv run pytest tests/ -q
@@ -0,0 +1,25 @@
1
+ name: Release
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ build-and-publish:
9
+ name: Build and publish to PyPI
10
+ runs-on: ubuntu-latest
11
+ environment: release
12
+ permissions:
13
+ id-token: write # required for trusted publishing
14
+
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: astral-sh/setup-uv@v4
18
+ with:
19
+ enable-cache: true
20
+ - name: Build package
21
+ run: uv build
22
+ - name: Publish to PyPI
23
+ uses: pypa/gh-action-pypi-publish@release/v1
24
+ with:
25
+ packages-dir: dist/
@@ -0,0 +1,35 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.so
5
+ dist/
6
+ build/
7
+ *.egg-info/
8
+ *.egg
9
+ .eggs/
10
+ .venv/
11
+ venv/
12
+ env/
13
+ .env
14
+ *.log
15
+ .mypy_cache/
16
+ .pyright/
17
+ .ruff_cache/
18
+ .pytest_cache/
19
+ htmlcov/
20
+ .coverage
21
+ .coverage.*
22
+ coverage.xml
23
+ *.cover
24
+ .hypothesis/
25
+ .tox/
26
+ .nox/
27
+ *.swp
28
+ *.swo
29
+ *~
30
+ .DS_Store
31
+ .idea/
32
+ .vscode/
33
+ .history/
34
+ site/
35
+ .remember/
@@ -0,0 +1,15 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 — 2026-05-16
4
+
5
+ Initial release.
6
+
7
+ - Async engine + sessionmaker factory; SQLite-aware pool kwargs.
8
+ - `init_database(app, ...)` with three shapes: `url=`, `config=`, or `databases={...}`.
9
+ - Multi-database registry — register any number of named engines (`primary`, `replica`, shards). Replica falls back to primary when absent.
10
+ - DI: `Depends(get_session)`, `Depends(get_replica_session)`, `session_for(name)`. Auto-commit on success, rollback on exception.
11
+ - `Base`, `DataclassBase`, `TimestampMixin`, `UUIDMixin`.
12
+ - Healthchecks: `session_healthy`, `database_healthy`, `all_healthy`.
13
+ - Alembic helper `hawkapi_sqlalchemy.alembic.run_migrations` — handles both online and offline modes.
14
+ - Pytest helpers `temporary_database` / `temporary_session` (in-memory SQLite, schema lifecycle).
15
+ - Extras: `[postgres]` (asyncpg), `[mysql]` (aiomysql).
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 HawkAPI Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,217 @@
1
+ Metadata-Version: 2.4
2
+ Name: hawkapi-sqlalchemy
3
+ Version: 0.1.0
4
+ Summary: SQLAlchemy integration for HawkAPI — async sessions, multi-database routing, Alembic helpers, pytest fixtures
5
+ Project-URL: Homepage, https://pypi.org/project/hawkapi-sqlalchemy/
6
+ Project-URL: Repository, https://github.com/ashimov/hawkapi-sqlalchemy
7
+ Project-URL: Issues, https://github.com/ashimov/hawkapi-sqlalchemy/issues
8
+ Author-email: HawkAPI Contributors <hawkapi@users.noreply.github.com>
9
+ License: MIT License
10
+
11
+ Copyright (c) 2026 HawkAPI Contributors
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
30
+ License-File: LICENSE
31
+ Keywords: alembic,async,database,hawkapi,mysql,postgres,sqlalchemy
32
+ Classifier: Development Status :: 5 - Production/Stable
33
+ Classifier: Framework :: AsyncIO
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Programming Language :: Python :: 3
37
+ Classifier: Programming Language :: Python :: 3.12
38
+ Classifier: Programming Language :: Python :: 3.13
39
+ Classifier: Topic :: Database
40
+ Classifier: Topic :: Database :: Front-Ends
41
+ Classifier: Typing :: Typed
42
+ Requires-Python: >=3.12
43
+ Requires-Dist: aiosqlite>=0.20
44
+ Requires-Dist: alembic>=1.13
45
+ Requires-Dist: hawkapi>=0.1.7
46
+ Requires-Dist: sqlalchemy[asyncio]>=2.0
47
+ Provides-Extra: dev
48
+ Requires-Dist: pyright>=1.1; extra == 'dev'
49
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
50
+ Requires-Dist: pytest>=8.0; extra == 'dev'
51
+ Requires-Dist: ruff>=0.8; extra == 'dev'
52
+ Provides-Extra: mysql
53
+ Requires-Dist: aiomysql>=0.2; extra == 'mysql'
54
+ Provides-Extra: postgres
55
+ Requires-Dist: asyncpg>=0.29; extra == 'postgres'
56
+ Description-Content-Type: text/markdown
57
+
58
+ # hawkapi-sqlalchemy
59
+
60
+ SQLAlchemy integration for [HawkAPI](https://github.com/ashimov/HawkAPI). Async sessions, multi-database routing (primary/replica/shards), Alembic helpers, and pytest fixtures.
61
+
62
+ ## Install
63
+
64
+ ```bash
65
+ pip install hawkapi-sqlalchemy # SQLite included
66
+ pip install 'hawkapi-sqlalchemy[postgres]' # + asyncpg
67
+ pip install 'hawkapi-sqlalchemy[mysql]' # + aiomysql
68
+ ```
69
+
70
+ ## Quickstart
71
+
72
+ ```python
73
+ from hawkapi import Depends, HawkAPI
74
+ from sqlalchemy.ext.asyncio import AsyncSession
75
+ from sqlalchemy.orm import Mapped, mapped_column
76
+
77
+ from hawkapi_sqlalchemy import Base, TimestampMixin, get_session, init_database
78
+
79
+
80
+ class User(Base, TimestampMixin):
81
+ __tablename__ = "users"
82
+ id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
83
+ email: Mapped[str] = mapped_column(unique=True)
84
+
85
+
86
+ app = HawkAPI()
87
+ init_database(app, url="postgresql+asyncpg://user:pw@localhost/app")
88
+
89
+
90
+ @app.post("/users")
91
+ async def create(email: str, sess: AsyncSession = Depends(get_session)):
92
+ sess.add(User(email=email))
93
+ await sess.flush()
94
+ return {"ok": True}
95
+ ```
96
+
97
+ The `get_session` dependency opens a fresh session per request, **commits on success**, and **rolls back on exception** — no boilerplate.
98
+
99
+ ## Multiple databases
100
+
101
+ ```python
102
+ from hawkapi_sqlalchemy import DatabaseConfig, init_database, session_for
103
+
104
+ init_database(
105
+ app,
106
+ databases={
107
+ "primary": DatabaseConfig(url="postgresql+asyncpg://…/primary"),
108
+ "replica": DatabaseConfig(url="postgresql+asyncpg://…/replica"),
109
+ "analytics": DatabaseConfig(url="postgresql+asyncpg://…/analytics"),
110
+ },
111
+ )
112
+
113
+ # DI helpers:
114
+ from hawkapi_sqlalchemy import get_session, get_replica_session
115
+
116
+ get_analytics = session_for("analytics", commit=False)
117
+
118
+
119
+ @app.get("/report")
120
+ async def report(sess: AsyncSession = Depends(get_analytics)):
121
+ ...
122
+ ```
123
+
124
+ `get_replica_session` falls back to `primary` if no replica is registered, so you can switch on without changing handlers.
125
+
126
+ ## Mixins
127
+
128
+ ```python
129
+ from hawkapi_sqlalchemy import Base, TimestampMixin, UUIDMixin
130
+
131
+
132
+ class Doc(Base, UUIDMixin, TimestampMixin):
133
+ __tablename__ = "docs"
134
+ title: Mapped[str] = mapped_column()
135
+ ```
136
+
137
+ - `TimestampMixin` — `created_at` / `updated_at` with DB-side defaults + Python `onupdate`.
138
+ - `UUIDMixin` — string `id` column with a `uuid4()` default.
139
+ - Prefer `DataclassBase` over `Base` to get SQLAlchemy 2.0's dataclass-style declarative.
140
+
141
+ ## Alembic
142
+
143
+ In your `alembic/env.py`:
144
+
145
+ ```python
146
+ from hawkapi_sqlalchemy.alembic import run_migrations
147
+ from myapp.db import Base, settings # your Base + URL
148
+
149
+ run_migrations(target_metadata=Base.metadata, url=settings.database_url)
150
+ ```
151
+
152
+ That's it — handles both online (live connection) and offline (`--sql`) modes; uses `NullPool` for migrations; enables `render_as_batch=True` automatically for SQLite.
153
+
154
+ ## Healthchecks
155
+
156
+ ```python
157
+ from hawkapi_sqlalchemy import all_healthy
158
+
159
+
160
+ @app.get("/healthz")
161
+ async def healthz():
162
+ return await all_healthy(app.state.db)
163
+ ```
164
+
165
+ Returns `{"primary": True, "replica": True, ...}`.
166
+
167
+ ## Testing
168
+
169
+ ```python
170
+ import pytest
171
+ from hawkapi_sqlalchemy import Base, temporary_database
172
+
173
+
174
+ @pytest.fixture
175
+ async def db():
176
+ async with temporary_database(Base.metadata) as database:
177
+ yield database
178
+
179
+
180
+ async def test_something(db):
181
+ async with db.session() as sess:
182
+ ...
183
+ ```
184
+
185
+ `temporary_database` creates an in-memory SQLite engine, calls `Base.metadata.create_all`, yields, then drops the schema and disposes.
186
+
187
+ ## DatabaseConfig
188
+
189
+ ```python
190
+ DatabaseConfig(
191
+ url="postgresql+asyncpg://…",
192
+ echo=False,
193
+ pool_size=5,
194
+ max_overflow=10,
195
+ pool_timeout=30.0,
196
+ pool_recycle=3600,
197
+ pool_pre_ping=True,
198
+ connect_args={"server_settings": {"jit": "off"}},
199
+ engine_kwargs={...}, # forwarded to create_async_engine
200
+ session_kwargs={...}, # forwarded to async_sessionmaker
201
+ )
202
+ ```
203
+
204
+ ## Development
205
+
206
+ ```bash
207
+ git clone https://github.com/ashimov/hawkapi-sqlalchemy.git
208
+ cd hawkapi-sqlalchemy
209
+ uv sync --extra dev
210
+ uv run pytest -q
211
+ uv run ruff check . && uv run ruff format --check .
212
+ uv run pyright src/
213
+ ```
214
+
215
+ ## License
216
+
217
+ MIT.
@@ -0,0 +1,160 @@
1
+ # hawkapi-sqlalchemy
2
+
3
+ SQLAlchemy integration for [HawkAPI](https://github.com/ashimov/HawkAPI). Async sessions, multi-database routing (primary/replica/shards), Alembic helpers, and pytest fixtures.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install hawkapi-sqlalchemy # SQLite included
9
+ pip install 'hawkapi-sqlalchemy[postgres]' # + asyncpg
10
+ pip install 'hawkapi-sqlalchemy[mysql]' # + aiomysql
11
+ ```
12
+
13
+ ## Quickstart
14
+
15
+ ```python
16
+ from hawkapi import Depends, HawkAPI
17
+ from sqlalchemy.ext.asyncio import AsyncSession
18
+ from sqlalchemy.orm import Mapped, mapped_column
19
+
20
+ from hawkapi_sqlalchemy import Base, TimestampMixin, get_session, init_database
21
+
22
+
23
+ class User(Base, TimestampMixin):
24
+ __tablename__ = "users"
25
+ id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
26
+ email: Mapped[str] = mapped_column(unique=True)
27
+
28
+
29
+ app = HawkAPI()
30
+ init_database(app, url="postgresql+asyncpg://user:pw@localhost/app")
31
+
32
+
33
+ @app.post("/users")
34
+ async def create(email: str, sess: AsyncSession = Depends(get_session)):
35
+ sess.add(User(email=email))
36
+ await sess.flush()
37
+ return {"ok": True}
38
+ ```
39
+
40
+ The `get_session` dependency opens a fresh session per request, **commits on success**, and **rolls back on exception** — no boilerplate.
41
+
42
+ ## Multiple databases
43
+
44
+ ```python
45
+ from hawkapi_sqlalchemy import DatabaseConfig, init_database, session_for
46
+
47
+ init_database(
48
+ app,
49
+ databases={
50
+ "primary": DatabaseConfig(url="postgresql+asyncpg://…/primary"),
51
+ "replica": DatabaseConfig(url="postgresql+asyncpg://…/replica"),
52
+ "analytics": DatabaseConfig(url="postgresql+asyncpg://…/analytics"),
53
+ },
54
+ )
55
+
56
+ # DI helpers:
57
+ from hawkapi_sqlalchemy import get_session, get_replica_session
58
+
59
+ get_analytics = session_for("analytics", commit=False)
60
+
61
+
62
+ @app.get("/report")
63
+ async def report(sess: AsyncSession = Depends(get_analytics)):
64
+ ...
65
+ ```
66
+
67
+ `get_replica_session` falls back to `primary` if no replica is registered, so you can switch on without changing handlers.
68
+
69
+ ## Mixins
70
+
71
+ ```python
72
+ from hawkapi_sqlalchemy import Base, TimestampMixin, UUIDMixin
73
+
74
+
75
+ class Doc(Base, UUIDMixin, TimestampMixin):
76
+ __tablename__ = "docs"
77
+ title: Mapped[str] = mapped_column()
78
+ ```
79
+
80
+ - `TimestampMixin` — `created_at` / `updated_at` with DB-side defaults + Python `onupdate`.
81
+ - `UUIDMixin` — string `id` column with a `uuid4()` default.
82
+ - Prefer `DataclassBase` over `Base` to get SQLAlchemy 2.0's dataclass-style declarative.
83
+
84
+ ## Alembic
85
+
86
+ In your `alembic/env.py`:
87
+
88
+ ```python
89
+ from hawkapi_sqlalchemy.alembic import run_migrations
90
+ from myapp.db import Base, settings # your Base + URL
91
+
92
+ run_migrations(target_metadata=Base.metadata, url=settings.database_url)
93
+ ```
94
+
95
+ That's it — handles both online (live connection) and offline (`--sql`) modes; uses `NullPool` for migrations; enables `render_as_batch=True` automatically for SQLite.
96
+
97
+ ## Healthchecks
98
+
99
+ ```python
100
+ from hawkapi_sqlalchemy import all_healthy
101
+
102
+
103
+ @app.get("/healthz")
104
+ async def healthz():
105
+ return await all_healthy(app.state.db)
106
+ ```
107
+
108
+ Returns `{"primary": True, "replica": True, ...}`.
109
+
110
+ ## Testing
111
+
112
+ ```python
113
+ import pytest
114
+ from hawkapi_sqlalchemy import Base, temporary_database
115
+
116
+
117
+ @pytest.fixture
118
+ async def db():
119
+ async with temporary_database(Base.metadata) as database:
120
+ yield database
121
+
122
+
123
+ async def test_something(db):
124
+ async with db.session() as sess:
125
+ ...
126
+ ```
127
+
128
+ `temporary_database` creates an in-memory SQLite engine, calls `Base.metadata.create_all`, yields, then drops the schema and disposes.
129
+
130
+ ## DatabaseConfig
131
+
132
+ ```python
133
+ DatabaseConfig(
134
+ url="postgresql+asyncpg://…",
135
+ echo=False,
136
+ pool_size=5,
137
+ max_overflow=10,
138
+ pool_timeout=30.0,
139
+ pool_recycle=3600,
140
+ pool_pre_ping=True,
141
+ connect_args={"server_settings": {"jit": "off"}},
142
+ engine_kwargs={...}, # forwarded to create_async_engine
143
+ session_kwargs={...}, # forwarded to async_sessionmaker
144
+ )
145
+ ```
146
+
147
+ ## Development
148
+
149
+ ```bash
150
+ git clone https://github.com/ashimov/hawkapi-sqlalchemy.git
151
+ cd hawkapi-sqlalchemy
152
+ uv sync --extra dev
153
+ uv run pytest -q
154
+ uv run ruff check . && uv run ruff format --check .
155
+ uv run pyright src/
156
+ ```
157
+
158
+ ## License
159
+
160
+ MIT.
@@ -0,0 +1,75 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "hawkapi-sqlalchemy"
7
+ version = "0.1.0"
8
+ description = "SQLAlchemy integration for HawkAPI — async sessions, multi-database routing, Alembic helpers, pytest fixtures"
9
+ readme = "README.md"
10
+ license = { file = "LICENSE" }
11
+ requires-python = ">=3.12"
12
+ authors = [
13
+ { name = "HawkAPI Contributors", email = "hawkapi@users.noreply.github.com" },
14
+ ]
15
+ keywords = ["hawkapi", "sqlalchemy", "async", "database", "alembic", "postgres", "mysql"]
16
+ classifiers = [
17
+ "Development Status :: 5 - Production/Stable",
18
+ "Framework :: AsyncIO",
19
+ "Intended Audience :: Developers",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Topic :: Database",
25
+ "Topic :: Database :: Front-Ends",
26
+ "Typing :: Typed",
27
+ ]
28
+ dependencies = [
29
+ "hawkapi>=0.1.7",
30
+ "sqlalchemy[asyncio]>=2.0",
31
+ "alembic>=1.13",
32
+ "aiosqlite>=0.20",
33
+ ]
34
+
35
+ [project.optional-dependencies]
36
+ postgres = ["asyncpg>=0.29"]
37
+ mysql = ["aiomysql>=0.2"]
38
+ dev = [
39
+ "pytest>=8.0",
40
+ "pytest-asyncio>=0.24",
41
+ "ruff>=0.8",
42
+ "pyright>=1.1",
43
+ ]
44
+
45
+ [project.urls]
46
+ Homepage = "https://pypi.org/project/hawkapi-sqlalchemy/"
47
+ Repository = "https://github.com/ashimov/hawkapi-sqlalchemy"
48
+ Issues = "https://github.com/ashimov/hawkapi-sqlalchemy/issues"
49
+
50
+ [tool.hatch.build.targets.wheel]
51
+ packages = ["src/hawkapi_sqlalchemy"]
52
+
53
+ [tool.pytest.ini_options]
54
+ testpaths = ["tests"]
55
+ asyncio_mode = "auto"
56
+ filterwarnings = ["ignore::DeprecationWarning"]
57
+
58
+ [tool.ruff]
59
+ target-version = "py312"
60
+ line-length = 100
61
+
62
+ [tool.ruff.lint]
63
+ select = ["E", "F", "I", "UP", "B", "SIM", "S"]
64
+ ignore = ["S101", "B008"]
65
+
66
+ [tool.ruff.lint.per-file-ignores]
67
+ "tests/**" = ["S"]
68
+
69
+ [tool.pyright]
70
+ pythonVersion = "3.12"
71
+ typeCheckingMode = "strict"
72
+ reportUnknownVariableType = false
73
+ reportUnknownMemberType = false
74
+ reportUnknownArgumentType = false
75
+ reportMissingTypeStubs = false
@@ -0,0 +1,41 @@
1
+ """hawkapi-sqlalchemy — SQLAlchemy integration for HawkAPI.
2
+
3
+ Async engines, multi-database routing (primary / replica / shards), per-request
4
+ sessions with auto-commit/rollback, Alembic helpers, and pytest fixtures.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from ._alembic import run_migrations
10
+ from ._database import Database, init_database, resolve_database
11
+ from ._engine import DatabaseConfig, Engine, create_engine
12
+ from ._health import all_healthy, database_healthy, session_healthy
13
+ from ._models import Base, DataclassBase, TimestampMixin, UUIDMixin
14
+ from ._session import get_replica_session, get_session, open_session, session_for
15
+ from ._testing import temporary_database, temporary_session
16
+
17
+ __version__ = "0.1.0"
18
+
19
+ __all__ = [
20
+ "Base",
21
+ "DataclassBase",
22
+ "Database",
23
+ "DatabaseConfig",
24
+ "Engine",
25
+ "TimestampMixin",
26
+ "UUIDMixin",
27
+ "__version__",
28
+ "all_healthy",
29
+ "create_engine",
30
+ "database_healthy",
31
+ "get_replica_session",
32
+ "get_session",
33
+ "init_database",
34
+ "open_session",
35
+ "resolve_database",
36
+ "run_migrations",
37
+ "session_for",
38
+ "session_healthy",
39
+ "temporary_database",
40
+ "temporary_session",
41
+ ]