Skip to content

Commit c584481

Browse files
feat(alembic): auto-enable PostgreSQL enum migration detection
Alembic autogenerate cannot detect changes to PostgreSQL native ENUM types (e.g. adding a value to an existing StrEnum), silently skipping those migrations. The generated env.py templates now import alembic-postgresql-enum inside a guarded try/except, which registers the required autogenerate comparators as an import side effect. This is a no-op when the package is not installed. Adds a public `postgresql` extra so users can install the dependency with `pip install "advanced-alchemy[postgresql]"`, documents the behavior in the CLI usage guide, and covers the template rendering with a test. Closes #492
1 parent 7952494 commit c584481

6 files changed

Lines changed: 75 additions & 3 deletions

File tree

advanced_alchemy/alembic/templates/asyncio/env.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@
88
from advanced_alchemy.base import metadata_registry
99
from alembic import context
1010

11+
try:
12+
# Enables autogenerate support for PostgreSQL ``ENUM`` changes (e.g. added values).
13+
# Alembic cannot detect these on its own; importing this package registers the
14+
# required autogenerate comparators as a side effect. Install with the
15+
# ``advanced-alchemy[postgresql]`` extra to enable.
16+
import alembic_postgresql_enum # type: ignore[import-not-found,unused-ignore] # pyright: ignore[reportMissingImports] # noqa: F401
17+
except ImportError:
18+
pass
19+
1120
if TYPE_CHECKING:
1221
from sqlalchemy.engine import Connection
1322

advanced_alchemy/alembic/templates/sync/env.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@
66
from advanced_alchemy.base import metadata_registry
77
from alembic import context
88

9+
try:
10+
# Enables autogenerate support for PostgreSQL ``ENUM`` changes (e.g. added values).
11+
# Alembic cannot detect these on its own; importing this package registers the
12+
# required autogenerate comparators as a side effect. Install with the
13+
# ``advanced-alchemy[postgresql]`` extra to enable.
14+
import alembic_postgresql_enum # type: ignore[import-not-found,unused-ignore] # pyright: ignore[reportMissingImports] # noqa: F401
15+
except ImportError:
16+
pass
17+
918
if TYPE_CHECKING:
1019
from sqlalchemy.engine import Connection
1120

docs/usage/cli.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,24 @@ Create a new migration revision:
255255
* - ``--rev-id`` TEXT
256256
- Specific revision ID
257257

258+
.. note:: **PostgreSQL enum changes**
259+
260+
Alembic's autogenerate does not detect changes to PostgreSQL native ``ENUM``
261+
types on its own (for example, adding a value to an existing ``StrEnum``).
262+
Advanced Alchemy's migration templates automatically enable this detection
263+
when the optional `alembic-postgresql-enum
264+
<https://pypi.org/project/alembic-postgresql-enum/>`_ package is installed.
265+
Install it with the ``postgresql`` extra:
266+
267+
.. code-block:: bash
268+
269+
pip install "advanced-alchemy[postgresql]"
270+
271+
The generated ``env.py`` imports the package inside a ``try``/``except`` block,
272+
so no configuration is required — it activates only when the package is present.
273+
If you initialized your migrations with an older version of Advanced Alchemy,
274+
add ``import alembic_postgresql_enum`` near the top of your ``env.py`` to enable it.
275+
258276

259277
Inspection Commands
260278
~~~~~~~~~~~~~~~~~~~

pyproject.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ fsspec = ["fsspec"]
6666
nanoid = ["fastnanoid>=0.4.1"]
6767
obstore = ["obstore"]
6868
passlib = ["passlib[argon2]"]
69+
postgresql = ["alembic-postgresql-enum"]
6970
pwdlib = ["pwdlib[argon2]"]
7071
pyotp = ["pyotp"]
7172
uuid = ["uuid-utils>=0.6.1"]
@@ -145,7 +146,7 @@ litestar = ["litestar[cli]>=2.23.0"]
145146
mssql = ["aioodbc>=0.5.0", "pyodbc>=5.2.0"]
146147
mysql = ["asyncmy>=0.2.9"]
147148
oracle = ["oracledb>=2.4.1"]
148-
postgres = ["asyncpg>=0.29.0", "psycopg2-binary>=2.9.10", "psycopg[binary,pool]>=3.2.3"]
149+
postgres = ["alembic-postgresql-enum", "asyncpg>=0.29.0", "psycopg2-binary>=2.9.10", "psycopg[binary,pool]>=3.2.3"]
149150
sanic = ["sanic", "sanic-testing>=24.6.0", "sanic[ext]>=24.6.0"]
150151
spanner = ["sqlalchemy-spanner>=1.7.0"]
151152
sqlite = ["aiosqlite>=0.20.0"]
@@ -375,7 +376,7 @@ classmethod-decorators = [
375376
]
376377

377378
[tool.ruff.lint.per-file-ignores]
378-
"advanced_alchemy/alembic/templates/*/env.py" = ["INP001"]
379+
"advanced_alchemy/alembic/templates/*/env.py" = ["INP001", "SIM105"]
379380
"advanced_alchemy/repository/*.py" = ['C901', 'UP006', 'UP035']
380381
"advanced_alchemy/repository/memory/*.py" = ['UP006', 'UP035']
381382
"advanced_alchemy/service/*.py" = ["PLR0911", "UP006", "UP035"]

tests/integration/test_alembic_commands.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,21 @@ async def test_alembic_init(alembic_commands: commands.AlembicCommands, tmp_proj
234234
assert await async_(Path(file).is_file)()
235235

236236

237+
async def test_alembic_init_renders_postgres_enum_import(
238+
alembic_commands: commands.AlembicCommands, tmp_project_dir: Path
239+
) -> None:
240+
"""The generated ``env.py`` should opt into PostgreSQL enum autogenerate support.
241+
242+
See https://github.com/litestar-org/advanced-alchemy/issues/492.
243+
"""
244+
from advanced_alchemy.utils.sync_tools import async_
245+
246+
alembic_commands.init(directory=f"{tmp_project_dir}/migrations/")
247+
env_contents = await async_(Path(f"{tmp_project_dir}/migrations/env.py").read_text)()
248+
assert "import alembic_postgresql_enum" in env_contents
249+
assert "except ImportError:" in env_contents
250+
251+
237252
async def test_alembic_init_already(alembic_commands: commands.AlembicCommands, tmp_project_dir: Path) -> None:
238253
from advanced_alchemy.utils.sync_tools import async_
239254

uv.lock

Lines changed: 21 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)