mgf-alembic 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.
- mgf_alembic-0.1.0/.gitignore +64 -0
- mgf_alembic-0.1.0/CHANGELOG.md +63 -0
- mgf_alembic-0.1.0/LICENSE +21 -0
- mgf_alembic-0.1.0/PKG-INFO +162 -0
- mgf_alembic-0.1.0/PUBLIC_API.md +78 -0
- mgf_alembic-0.1.0/README.md +122 -0
- mgf_alembic-0.1.0/docs/cutover/v0.1.0.md +249 -0
- mgf_alembic-0.1.0/docs/recipes/alembic.md +251 -0
- mgf_alembic-0.1.0/pyproject.toml +203 -0
- mgf_alembic-0.1.0/src/mgf/alembic/__init__.py +60 -0
- mgf_alembic-0.1.0/src/mgf/alembic/_env.py +275 -0
- mgf_alembic-0.1.0/src/mgf/alembic/py.typed +0 -0
- mgf_alembic-0.1.0/tests/unit/test_env.py +474 -0
- mgf_alembic-0.1.0/uv.lock +1161 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# IDE
|
|
2
|
+
.idea/
|
|
3
|
+
.vscode/
|
|
4
|
+
*.swp
|
|
5
|
+
*.swo
|
|
6
|
+
|
|
7
|
+
# Python
|
|
8
|
+
__pycache__/
|
|
9
|
+
*.py[cod]
|
|
10
|
+
*$py.class
|
|
11
|
+
*.so
|
|
12
|
+
.Python
|
|
13
|
+
build/
|
|
14
|
+
develop-eggs/
|
|
15
|
+
dist/
|
|
16
|
+
downloads/
|
|
17
|
+
eggs/
|
|
18
|
+
.eggs/
|
|
19
|
+
lib/
|
|
20
|
+
lib64/
|
|
21
|
+
parts/
|
|
22
|
+
sdist/
|
|
23
|
+
var/
|
|
24
|
+
wheels/
|
|
25
|
+
*.egg-info/
|
|
26
|
+
.installed.cfg
|
|
27
|
+
*.egg
|
|
28
|
+
|
|
29
|
+
# Virtual environments
|
|
30
|
+
.venv/
|
|
31
|
+
venv/
|
|
32
|
+
env/
|
|
33
|
+
ENV/
|
|
34
|
+
|
|
35
|
+
# Testing and coverage
|
|
36
|
+
.pytest_cache/
|
|
37
|
+
.hypothesis/
|
|
38
|
+
.coverage
|
|
39
|
+
.coverage.*
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
coverage.xml
|
|
44
|
+
*.cover
|
|
45
|
+
|
|
46
|
+
# Type checking
|
|
47
|
+
.mypy_cache/
|
|
48
|
+
.pyre/
|
|
49
|
+
.pytype/
|
|
50
|
+
|
|
51
|
+
# Ruff
|
|
52
|
+
.ruff_cache/
|
|
53
|
+
|
|
54
|
+
# Packaging
|
|
55
|
+
MANIFEST
|
|
56
|
+
|
|
57
|
+
# Claude Code — keep settings.json (committed for the team), ignore
|
|
58
|
+
# per-machine local overrides + runtime locks/state.
|
|
59
|
+
.claude/settings.local.json
|
|
60
|
+
.claude/*.lock
|
|
61
|
+
.claude/scheduled_tasks*
|
|
62
|
+
|
|
63
|
+
# Maintainer planning notes (per-machine; never commit)
|
|
64
|
+
my_stuff/
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `mgf-alembic` are documented here.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/);
|
|
6
|
+
the project follows [SemVer](https://semver.org/spec/v2.0.0.html). Per
|
|
7
|
+
the 0.x window ([SemVer 0.x](https://semver.org/#spec-item-4) and rule
|
|
8
|
+
**AP-03** from `mgf-common/docs/standards/API_DESIGN.md`), MINOR
|
|
9
|
+
releases MAY break the public API. Pin tightly:
|
|
10
|
+
|
|
11
|
+
```toml
|
|
12
|
+
mgf-alembic = ">=0.X.0,<0.Y" # one minor at a time
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The release-engineering discipline that produces this changelog is in
|
|
16
|
+
[`mgf-common/docs/standards/RELEASING.md`](https://codeberg.org/magogi-admin/mgf_common/src/branch/master/docs/standards/RELEASING.md).
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## [Unreleased]
|
|
21
|
+
|
|
22
|
+
Nothing yet.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## [0.1.0] — 2026-05-10
|
|
27
|
+
|
|
28
|
+
PyPI: <https://pypi.org/project/mgf-alembic/0.1.0/> · Tag: `v0.1.0`
|
|
29
|
+
|
|
30
|
+
> **Maiden voyage** — extracted from `mgf-common` v0.29.0 per the
|
|
31
|
+
> federation split plan ([mgf-common/docs/release/federation_roadmap.md](https://codeberg.org/magogi-admin/mgf_common/src/branch/master/docs/release/federation_roadmap.md)).
|
|
32
|
+
> Paired ship with mgf-sqlalchemy v0.1.0 (this sibling depends on it).
|
|
33
|
+
> Cutover guide: [`docs/cutover/v0.1.0.md`](docs/cutover/v0.1.0.md).
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- **`mgf.alembic.configure_env`** — one call replaces the ~40-line
|
|
38
|
+
`env.py` boilerplate every async-SQLAlchemy + alembic project
|
|
39
|
+
ships. Detects sync vs async drivers from the URL prefix
|
|
40
|
+
(`postgresql+asyncpg://`, `postgresql+psycopg://`,
|
|
41
|
+
`mysql+aiomysql://`, `mysql+asyncmy://`, `sqlite+aiosqlite://`)
|
|
42
|
+
and runs the migration via `asyncio.run` for async URLs;
|
|
43
|
+
falls through to the sync path otherwise. Plumbs
|
|
44
|
+
`compare_type`, `compare_server_default`, `naming_convention`,
|
|
45
|
+
`include_object`, `include_schemas` through to
|
|
46
|
+
`alembic.context.configure` (PAPER-22 — `include_object` /
|
|
47
|
+
`include_schemas` were added in mgf-common v0.19; carried over
|
|
48
|
+
byte-identical).
|
|
49
|
+
|
|
50
|
+
### Engineering
|
|
51
|
+
|
|
52
|
+
- 11 tests carried over from `mgf-common/tests/unit/alembic/test_env.py`
|
|
53
|
+
— every pre-extraction failure mode stays green at parity. Coverage
|
|
54
|
+
threshold ≥80% (matches mgf-common's standard).
|
|
55
|
+
- Imports rewrite from `mgf.common.alembic.*` to `mgf.alembic.*`.
|
|
56
|
+
No private-import leaks; the sibling reaches into mgf-common only
|
|
57
|
+
through public names.
|
|
58
|
+
- `mgf-common>=0.30,<0.31` + `mgf-sqlalchemy>=0.1,<0.2` runtime
|
|
59
|
+
dependencies. AP-03 0.x window pin discipline applies — bump in
|
|
60
|
+
lock-step with mgf-common's next minor.
|
|
61
|
+
- PEP 420 namespace package (no top-level `mgf/__init__.py`); the
|
|
62
|
+
wheel ships `src/mgf/` as-is so `mgf.alembic`, `mgf.sqlalchemy`,
|
|
63
|
+
`mgf.fastapi`, `mgf.http`, and `mgf.common` coexist as siblings.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Bassam Alsanie and mgf-common 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,162 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mgf-alembic
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Async-aware alembic env.py helper for mgf-common consumers — one-call configure_env replaces ~40 lines of boilerplate. Sibling of mgf-common under the mgf.* namespace; pairs with mgf-sqlalchemy.
|
|
5
|
+
Project-URL: Homepage, https://codeberg.org/magogi-admin/mgf-alembic
|
|
6
|
+
Project-URL: Issues, https://codeberg.org/magogi-admin/mgf-alembic/issues
|
|
7
|
+
Project-URL: Changelog, https://codeberg.org/magogi-admin/mgf-alembic/src/branch/master/CHANGELOG.md
|
|
8
|
+
Author: Bassam Alsanie, mgf-alembic contributors
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: alembic,async,asyncpg,configure-env,migrations,sqlalchemy
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: MacOS
|
|
16
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
17
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
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
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.11
|
|
26
|
+
Requires-Dist: alembic>=1.13
|
|
27
|
+
Requires-Dist: mgf-common<0.31,>=0.30
|
|
28
|
+
Requires-Dist: mgf-sqlalchemy<0.2,>=0.1
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: aiosqlite>=0.20; extra == 'dev'
|
|
31
|
+
Requires-Dist: import-linter>=2.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
37
|
+
Provides-Extra: test
|
|
38
|
+
Requires-Dist: aiosqlite>=0.20; extra == 'test'
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
|
|
41
|
+
# `mgf-alembic` — async-aware alembic env.py helper for mgf-common consumers
|
|
42
|
+
|
|
43
|
+
[](https://pypi.org/project/mgf-alembic/)
|
|
44
|
+
[](https://pypi.org/project/mgf-alembic/)
|
|
45
|
+
|
|
46
|
+
> **Sibling of [`mgf-common`](https://pypi.org/project/mgf-common/) +
|
|
47
|
+
> [`mgf-sqlalchemy`](https://pypi.org/project/mgf-sqlalchemy/) under
|
|
48
|
+
> the `mgf.*` namespace.** Houses the async-aware alembic `env.py`
|
|
49
|
+
> helper that previously lived under `mgf.common.alembic.*` —
|
|
50
|
+
> extracted at mgf-common v0.30 / mgf-alembic v0.1 (paired with
|
|
51
|
+
> mgf-sqlalchemy v0.1) per the
|
|
52
|
+
> [federation split plan](https://codeberg.org/magogi-admin/mgf_common/src/branch/master/docs/release/federation_roadmap.md).
|
|
53
|
+
|
|
54
|
+
## What this provides
|
|
55
|
+
|
|
56
|
+
| Submodule | What |
|
|
57
|
+
|---|---|
|
|
58
|
+
| `mgf.alembic` | `configure_env` — one call replaces the ~40-line `env.py` boilerplate. Auto-detects sync vs async drivers from the URL prefix (`postgresql+asyncpg://`, `sqlite+aiosqlite://`, etc.). Plumbs `compare_type`, `compare_server_default`, `naming_convention`, `include_object`, `include_schemas` through to `alembic.context.configure`. |
|
|
59
|
+
|
|
60
|
+
`include_object` / `include_schemas` were added per
|
|
61
|
+
[PAPER-22](https://codeberg.org/magogi-admin/mgf_common/src/branch/master/FEEDBACK.md)
|
|
62
|
+
in mgf-common v0.19; carried over to mgf-alembic v0.1 unchanged.
|
|
63
|
+
|
|
64
|
+
## Install
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pip install mgf-alembic
|
|
68
|
+
# Or with the test extra (aiosqlite for async-driver round-trip tests):
|
|
69
|
+
pip install 'mgf-alembic[test]'
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Pulls in `mgf-common`, `mgf-sqlalchemy`, and `alembic>=1.13`
|
|
73
|
+
automatically.
|
|
74
|
+
|
|
75
|
+
## Quick start — the entire env.py
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
# alembic/env.py
|
|
79
|
+
from mgf.alembic import configure_env
|
|
80
|
+
from myapp.config import MyAppSettings
|
|
81
|
+
from myapp.db.base import Base
|
|
82
|
+
|
|
83
|
+
settings = MyAppSettings()
|
|
84
|
+
configure_env(
|
|
85
|
+
database_url=settings.database_url,
|
|
86
|
+
target_metadata=Base.metadata,
|
|
87
|
+
)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
That's the entire file. The helper detects offline vs online mode,
|
|
91
|
+
runs the migration, disposes the engine cleanly. Async drivers
|
|
92
|
+
(asyncpg, aiomysql, aiosqlite, asyncmy, async psycopg) are
|
|
93
|
+
auto-detected; sync drivers fall through the synchronous path.
|
|
94
|
+
|
|
95
|
+
## PostGIS / TimescaleDB: filter extension tables
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
def _exclude_extensions(obj, name, type_, reflected, compare_to):
|
|
99
|
+
return not (type_ == "table" and name in {"spatial_ref_sys"})
|
|
100
|
+
|
|
101
|
+
configure_env(
|
|
102
|
+
database_url=settings.database_url,
|
|
103
|
+
target_metadata=Base.metadata,
|
|
104
|
+
include_object=_exclude_extensions,
|
|
105
|
+
)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`alembic revision --autogenerate` no longer proposes phantom drops
|
|
109
|
+
for extension-managed tables (PostGIS `spatial_ref_sys`,
|
|
110
|
+
TimescaleDB `_timescaledb_internal`, pgvector housekeeping).
|
|
111
|
+
|
|
112
|
+
## Naming-convention shape
|
|
113
|
+
|
|
114
|
+
Constraint names auto-generated by `op.create_*` are otherwise
|
|
115
|
+
anonymous and vary across DBs — pin them:
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
configure_env(
|
|
119
|
+
database_url=settings.database_url,
|
|
120
|
+
target_metadata=Base.metadata,
|
|
121
|
+
naming_convention={
|
|
122
|
+
"ix": "ix_%(column_0_label)s",
|
|
123
|
+
"uq": "uq_%(table_name)s_%(column_0_name)s",
|
|
124
|
+
"ck": "ck_%(table_name)s_%(constraint_name)s",
|
|
125
|
+
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
|
|
126
|
+
"pk": "pk_%(table_name)s",
|
|
127
|
+
},
|
|
128
|
+
)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Documentation
|
|
132
|
+
|
|
133
|
+
- [`docs/recipes/alembic.md`](docs/recipes/alembic.md) — full async-alembic walkthrough.
|
|
134
|
+
- [`docs/cutover/v0.1.0.md`](docs/cutover/v0.1.0.md) — maiden voyage migration story (the v0.30 split).
|
|
135
|
+
- [`PUBLIC_API.md`](PUBLIC_API.md) — full public surface contract.
|
|
136
|
+
- [`CHANGELOG.md`](CHANGELOG.md) — release history.
|
|
137
|
+
|
|
138
|
+
For the federation-wide engineering standards (DESIGN_PRINCIPLES,
|
|
139
|
+
ERROR_HANDLING, SECURITY, etc.) see
|
|
140
|
+
[`mgf-common/docs/standards/`](https://codeberg.org/magogi-admin/mgf_common/src/branch/master/docs/standards/).
|
|
141
|
+
This sibling inherits them by reference; the standards
|
|
142
|
+
source-of-truth lives in mgf-common.
|
|
143
|
+
|
|
144
|
+
## Status
|
|
145
|
+
|
|
146
|
+
🚧 **Experimental** — every public name is `experimental` per AP-09.
|
|
147
|
+
Promotion to `stable` happens release-by-release as consumer feedback
|
|
148
|
+
in [`mgf-common/FEEDBACK.md`](https://codeberg.org/magogi-admin/mgf_common/src/branch/master/FEEDBACK.md)
|
|
149
|
+
converges. The 0.x window applies. Pin tightly:
|
|
150
|
+
`mgf-alembic = ">=0.X.0,<0.Y"`.
|
|
151
|
+
|
|
152
|
+
## Cross-references
|
|
153
|
+
|
|
154
|
+
- **Filing process for sharp edges**: open an entry on
|
|
155
|
+
[`mgf-common/FEEDBACK.md`](https://codeberg.org/magogi-admin/mgf_common/src/branch/master/FEEDBACK.md)
|
|
156
|
+
with `[mgf-alembic]` prefix, OR file directly on this repo's Issues
|
|
157
|
+
→ maintainer mirrors into the canonical FEEDBACK.md.
|
|
158
|
+
- **Federation pattern**:
|
|
159
|
+
[`mgf-common/docs/design/federation.md`](https://codeberg.org/magogi-admin/mgf_common/src/branch/master/docs/design/federation.md).
|
|
160
|
+
- **The split that created this sibling**:
|
|
161
|
+
[`mgf-common/docs/release/federation_roadmap.md`](https://codeberg.org/magogi-admin/mgf_common/src/branch/master/docs/release/federation_roadmap.md).
|
|
162
|
+
- **Companion sibling**: [`mgf-sqlalchemy`](https://pypi.org/project/mgf-sqlalchemy/) — async SQLAlchemy engine + sessionmaker + tenant-scoping (paired ship at v0.30; this sibling depends on it).
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Public API — `mgf-alembic`
|
|
2
|
+
|
|
3
|
+
> ⚠️ **This file documents `master` HEAD.** Names listed here may
|
|
4
|
+
> be unreleased. To learn what your installed wheel actually
|
|
5
|
+
> ships, run `pip show mgf-alembic` and compare against the git tag
|
|
6
|
+
> matching the published version.
|
|
7
|
+
|
|
8
|
+
This document is the **contract list** for `mgf-alembic`. Every name
|
|
9
|
+
listed below is a public name that consumers MAY depend on.
|
|
10
|
+
|
|
11
|
+
The contract terms are defined in
|
|
12
|
+
[`mgf-common/docs/standards/API_DESIGN.md`](https://codeberg.org/magogi-admin/mgf_common/src/branch/master/docs/standards/API_DESIGN.md). In
|
|
13
|
+
short:
|
|
14
|
+
|
|
15
|
+
- **Stability tiers:**
|
|
16
|
+
- `experimental` — MAY change shape in any MINOR release
|
|
17
|
+
(the 0.x window keeps everything experimental in practice).
|
|
18
|
+
- `stable` — follows the deprecation cycle; removal only in MAJOR.
|
|
19
|
+
- `deprecated` — slated for removal; emits `DeprecationWarning`.
|
|
20
|
+
- **Names not listed below are private.** Anything starting with
|
|
21
|
+
`_` (underscore-prefixed module names like `_env.py`) is internal
|
|
22
|
+
and MAY change without notice.
|
|
23
|
+
- **The 0.x window applies.** Per [SemVer](https://semver.org/) 0.x
|
|
24
|
+
semantics, MINOR releases MAY break the public API. Pin tightly:
|
|
25
|
+
`mgf-alembic = ">=0.X.0,<0.Y"`.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## `mgf.alembic`
|
|
30
|
+
|
|
31
|
+
Top-level alembic env.py helper. Closed-box: depends on
|
|
32
|
+
`mgf-common` + `mgf-sqlalchemy` + `alembic` only.
|
|
33
|
+
|
|
34
|
+
| Name | Tier | Description |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| `configure_env` | experimental | One-call replacement for the ~40-line async-alembic env.py boilerplate. Keyword-only parameters: `database_url` (str), `target_metadata` (sqlalchemy `MetaData`), `compare_type` (default True), `compare_server_default` (default True), `naming_convention` (dict, default None), `include_object` (callable, default None), `include_schemas` (default False). Auto-detects sync vs async drivers from URL prefix; offline mode (`alembic upgrade --sql`) detected from `context.is_offline_mode()`. |
|
|
37
|
+
|
|
38
|
+
### Behaviours guaranteed at the public surface
|
|
39
|
+
|
|
40
|
+
- Async URL prefixes detected: `postgresql+asyncpg://`,
|
|
41
|
+
`postgresql+psycopg://` (psycopg 3 async), `mysql+aiomysql://`,
|
|
42
|
+
`mysql+asyncmy://`, `sqlite+aiosqlite://`. Other URLs take the
|
|
43
|
+
sync path.
|
|
44
|
+
- `include_object=None` and `include_schemas=False` (the defaults)
|
|
45
|
+
match alembic's own defaults — no behaviour change for consumers
|
|
46
|
+
that don't supply them.
|
|
47
|
+
- `naming_convention` is applied to `target_metadata.naming_convention`
|
|
48
|
+
before `context.configure` runs, so auto-generated constraints
|
|
49
|
+
pick up the convention.
|
|
50
|
+
- All keyword arguments are pass-through to `alembic.context.configure`
|
|
51
|
+
— adding/removing options requires a `mgf-alembic` minor bump per
|
|
52
|
+
AP-03.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## What stays in `mgf-common`, NOT here
|
|
57
|
+
|
|
58
|
+
- **`AppError`, `OperationError`** and the rest of the typed
|
|
59
|
+
exception hierarchy — `mgf.common.exceptions`.
|
|
60
|
+
- **`bootstrap`, `app_name`, `app_version`, `current_context`** —
|
|
61
|
+
`mgf.common`.
|
|
62
|
+
|
|
63
|
+
`mgf-alembic` reaches into none of mgf-common's private modules. The
|
|
64
|
+
runtime dep is `mgf-common>=0.30,<0.31`.
|
|
65
|
+
|
|
66
|
+
## Companion sibling: `mgf-sqlalchemy`
|
|
67
|
+
|
|
68
|
+
`mgf.sqlalchemy.create_engine`, `create_sessionmaker`,
|
|
69
|
+
`tenant_session` — the async-SQLAlchemy helpers paired with this
|
|
70
|
+
alembic helper. Install both for the full DB+migrations story:
|
|
71
|
+
|
|
72
|
+
```toml
|
|
73
|
+
dependencies = [
|
|
74
|
+
"mgf-common>=0.30,<0.31",
|
|
75
|
+
"mgf-sqlalchemy>=0.1,<0.2",
|
|
76
|
+
"mgf-alembic>=0.1,<0.2",
|
|
77
|
+
]
|
|
78
|
+
```
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# `mgf-alembic` — async-aware alembic env.py helper for mgf-common consumers
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/mgf-alembic/)
|
|
4
|
+
[](https://pypi.org/project/mgf-alembic/)
|
|
5
|
+
|
|
6
|
+
> **Sibling of [`mgf-common`](https://pypi.org/project/mgf-common/) +
|
|
7
|
+
> [`mgf-sqlalchemy`](https://pypi.org/project/mgf-sqlalchemy/) under
|
|
8
|
+
> the `mgf.*` namespace.** Houses the async-aware alembic `env.py`
|
|
9
|
+
> helper that previously lived under `mgf.common.alembic.*` —
|
|
10
|
+
> extracted at mgf-common v0.30 / mgf-alembic v0.1 (paired with
|
|
11
|
+
> mgf-sqlalchemy v0.1) per the
|
|
12
|
+
> [federation split plan](https://codeberg.org/magogi-admin/mgf_common/src/branch/master/docs/release/federation_roadmap.md).
|
|
13
|
+
|
|
14
|
+
## What this provides
|
|
15
|
+
|
|
16
|
+
| Submodule | What |
|
|
17
|
+
|---|---|
|
|
18
|
+
| `mgf.alembic` | `configure_env` — one call replaces the ~40-line `env.py` boilerplate. Auto-detects sync vs async drivers from the URL prefix (`postgresql+asyncpg://`, `sqlite+aiosqlite://`, etc.). Plumbs `compare_type`, `compare_server_default`, `naming_convention`, `include_object`, `include_schemas` through to `alembic.context.configure`. |
|
|
19
|
+
|
|
20
|
+
`include_object` / `include_schemas` were added per
|
|
21
|
+
[PAPER-22](https://codeberg.org/magogi-admin/mgf_common/src/branch/master/FEEDBACK.md)
|
|
22
|
+
in mgf-common v0.19; carried over to mgf-alembic v0.1 unchanged.
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install mgf-alembic
|
|
28
|
+
# Or with the test extra (aiosqlite for async-driver round-trip tests):
|
|
29
|
+
pip install 'mgf-alembic[test]'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Pulls in `mgf-common`, `mgf-sqlalchemy`, and `alembic>=1.13`
|
|
33
|
+
automatically.
|
|
34
|
+
|
|
35
|
+
## Quick start — the entire env.py
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
# alembic/env.py
|
|
39
|
+
from mgf.alembic import configure_env
|
|
40
|
+
from myapp.config import MyAppSettings
|
|
41
|
+
from myapp.db.base import Base
|
|
42
|
+
|
|
43
|
+
settings = MyAppSettings()
|
|
44
|
+
configure_env(
|
|
45
|
+
database_url=settings.database_url,
|
|
46
|
+
target_metadata=Base.metadata,
|
|
47
|
+
)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
That's the entire file. The helper detects offline vs online mode,
|
|
51
|
+
runs the migration, disposes the engine cleanly. Async drivers
|
|
52
|
+
(asyncpg, aiomysql, aiosqlite, asyncmy, async psycopg) are
|
|
53
|
+
auto-detected; sync drivers fall through the synchronous path.
|
|
54
|
+
|
|
55
|
+
## PostGIS / TimescaleDB: filter extension tables
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
def _exclude_extensions(obj, name, type_, reflected, compare_to):
|
|
59
|
+
return not (type_ == "table" and name in {"spatial_ref_sys"})
|
|
60
|
+
|
|
61
|
+
configure_env(
|
|
62
|
+
database_url=settings.database_url,
|
|
63
|
+
target_metadata=Base.metadata,
|
|
64
|
+
include_object=_exclude_extensions,
|
|
65
|
+
)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`alembic revision --autogenerate` no longer proposes phantom drops
|
|
69
|
+
for extension-managed tables (PostGIS `spatial_ref_sys`,
|
|
70
|
+
TimescaleDB `_timescaledb_internal`, pgvector housekeeping).
|
|
71
|
+
|
|
72
|
+
## Naming-convention shape
|
|
73
|
+
|
|
74
|
+
Constraint names auto-generated by `op.create_*` are otherwise
|
|
75
|
+
anonymous and vary across DBs — pin them:
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
configure_env(
|
|
79
|
+
database_url=settings.database_url,
|
|
80
|
+
target_metadata=Base.metadata,
|
|
81
|
+
naming_convention={
|
|
82
|
+
"ix": "ix_%(column_0_label)s",
|
|
83
|
+
"uq": "uq_%(table_name)s_%(column_0_name)s",
|
|
84
|
+
"ck": "ck_%(table_name)s_%(constraint_name)s",
|
|
85
|
+
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
|
|
86
|
+
"pk": "pk_%(table_name)s",
|
|
87
|
+
},
|
|
88
|
+
)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Documentation
|
|
92
|
+
|
|
93
|
+
- [`docs/recipes/alembic.md`](docs/recipes/alembic.md) — full async-alembic walkthrough.
|
|
94
|
+
- [`docs/cutover/v0.1.0.md`](docs/cutover/v0.1.0.md) — maiden voyage migration story (the v0.30 split).
|
|
95
|
+
- [`PUBLIC_API.md`](PUBLIC_API.md) — full public surface contract.
|
|
96
|
+
- [`CHANGELOG.md`](CHANGELOG.md) — release history.
|
|
97
|
+
|
|
98
|
+
For the federation-wide engineering standards (DESIGN_PRINCIPLES,
|
|
99
|
+
ERROR_HANDLING, SECURITY, etc.) see
|
|
100
|
+
[`mgf-common/docs/standards/`](https://codeberg.org/magogi-admin/mgf_common/src/branch/master/docs/standards/).
|
|
101
|
+
This sibling inherits them by reference; the standards
|
|
102
|
+
source-of-truth lives in mgf-common.
|
|
103
|
+
|
|
104
|
+
## Status
|
|
105
|
+
|
|
106
|
+
🚧 **Experimental** — every public name is `experimental` per AP-09.
|
|
107
|
+
Promotion to `stable` happens release-by-release as consumer feedback
|
|
108
|
+
in [`mgf-common/FEEDBACK.md`](https://codeberg.org/magogi-admin/mgf_common/src/branch/master/FEEDBACK.md)
|
|
109
|
+
converges. The 0.x window applies. Pin tightly:
|
|
110
|
+
`mgf-alembic = ">=0.X.0,<0.Y"`.
|
|
111
|
+
|
|
112
|
+
## Cross-references
|
|
113
|
+
|
|
114
|
+
- **Filing process for sharp edges**: open an entry on
|
|
115
|
+
[`mgf-common/FEEDBACK.md`](https://codeberg.org/magogi-admin/mgf_common/src/branch/master/FEEDBACK.md)
|
|
116
|
+
with `[mgf-alembic]` prefix, OR file directly on this repo's Issues
|
|
117
|
+
→ maintainer mirrors into the canonical FEEDBACK.md.
|
|
118
|
+
- **Federation pattern**:
|
|
119
|
+
[`mgf-common/docs/design/federation.md`](https://codeberg.org/magogi-admin/mgf_common/src/branch/master/docs/design/federation.md).
|
|
120
|
+
- **The split that created this sibling**:
|
|
121
|
+
[`mgf-common/docs/release/federation_roadmap.md`](https://codeberg.org/magogi-admin/mgf_common/src/branch/master/docs/release/federation_roadmap.md).
|
|
122
|
+
- **Companion sibling**: [`mgf-sqlalchemy`](https://pypi.org/project/mgf-sqlalchemy/) — async SQLAlchemy engine + sessionmaker + tenant-scoping (paired ship at v0.30; this sibling depends on it).
|