sqlalchemy-deprecated-column
Safely remove SQLAlchemy ORM columns through a gradual deprecation process. Inspired by django-deprecate-fields.
Installation
pip install sqlalchemy-deprecated-column
While the project is pre-1.0, breaking changes may land in minor releases (e.g. 0.1.x → 0.2.0), following the SemVer convention for 0.y.z versions. Patch releases (0.1.3 → 0.1.4) remain backwards-compatible. To avoid surprise breakage, pin to a specific minor version:
sqlalchemy-deprecated-column~=0.1.0
How it works
Removing a column from a live database requires coordination between code and schema changes. Dropping the column in a single step would break any running application instances that still reference it. deprecated_column() lets you do this safely in three steps:
- Deprecate: replace
mapped_column()withdeprecated_column()and run an Alembic migration. The column stays in the database but becomes nullable if it wasn't already. - Deploy: the column is hidden from the ORM — it no longer appears in any generated SQL. Any remaining code that reads or writes the column gets a
DeprecationWarningat runtime (or raisesColumnDeprecatedErrorifraise_on_access=True), making stale references easy to find and remove. - Remove: once all references are gone, delete the
deprecated_column()definition from the model and run a final migration to drop the column from the database.
Usage
deprecated_column() is a drop-in replacement for mapped_column() and accepts the same arguments. For columns declared with only a bare Mapped[T] annotation, add deprecated_column() with no arguments.
Before:
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
email: Mapped[str] = mapped_column(String)
old_username: Mapped[str] = mapped_column(String(200), index=True)
old_email: Mapped[str]
After:
from sqlalchemy_deprecated_column import deprecated_column
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
email: Mapped[str] = mapped_column(String)
old_username: Mapped[str] = deprecated_column(String(200), index=True)
old_email: Mapped[str] = deprecated_column()
While the column is deprecated the library:
- Hides it from the ORM: the column is excluded from all generated SQL queries — existing application code stays compatible even after the column is eventually dropped from the database.
- Warns on instance read:
instance.old_usernamereturnsNoneand emits aDeprecationWarningnaming the model and column, so the call site is easy to locate. - Warns on class-level reference:
User.old_username(e.g. in filter expressions) emits aDeprecationWarningand evaluates to SQLNULL. - Warns on write and discards the value:
instance.old_username = "x"emits aDeprecationWarningand silently drops the value, so no stale data is written to the database.
Pass raise_on_access=True to raise a ColumnDeprecatedError on any access instead of emitting a warning. This is useful when you want to enforce that all stale references are removed — for example, by letting the exception surface in tests or CI:
from sqlalchemy_deprecated_column import ColumnDeprecatedError, deprecated_column
old_username: Mapped[str] = deprecated_column(String(200), raise_on_access=True)
Alembic integration
Add the following at the top of alembic/env.py, before any model imports:
import sqlalchemy_deprecated_column
sqlalchemy_deprecated_column.configure(alembic_mode=True)
# model imports must come after configure()
from myapp import mymodel
target_metadata = mymodel.Base.metadata
In Alembic mode, deprecated_column() acts as mapped_column(nullable=True). Alembic will:
- Not generate
DROP COLUMNfor deprecated columns. - Generate
ALTER TABLE … DROP NOT NULLif the column was originally non-nullable. This is needed because once the column is deprecated the ORM stops including it inINSERTstatements — aNOT NULLcolumn without a value would cause those inserts to fail.
Requirements
- Python 3.10+
- SQLAlchemy 2.0+
License
The code in this project is licensed under MIT license. See LICENSE for more information.
Metadata
Release files for sqlalchemy-deprecated-column 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sqlalchemy_deprecated_column-0.3.0.tar.gz | 5.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sqlalchemy_deprecated_column-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 11.8 kB
Release files / sqlalchemy_deprecated_column-0.3.0.tar.gz
| Download URL | sqlalchemy_deprecated_column-0.3.0.tar.gz |
|---|---|
| Size | 5.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
656a779c5f954c53a9403ab0292a3a3e9311e5cbee765e9c2f5ae5ec3587a12c
|
|
BLAKE2b-256 checksum How to use checksums |
cfcc679d3cfa7abf022f7407f6eecd8f66fa2122703496d7d6f36142fe07d9f5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.13 {"installer":{"name":"uv","version":"0.11.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / sqlalchemy_deprecated_column-0.3.0-py3-none-any.whl
| Download URL | sqlalchemy_deprecated_column-0.3.0-py3-none-any.whl |
|---|---|
| Size | 6.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3d38db400904a43e1493f62e9ee0eeb323a1f70305d92f53219c3b1d82e8eecf
|
|
BLAKE2b-256 checksum How to use checksums |
28a1a7ee836630a10edc64569a3a9d0bba95e5bfd601028d1df69beba2059d78
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.13 {"installer":{"name":"uv","version":"0.11.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|