Skip to main content

Utility to mark SQLAlchemy ORM columns as deprecated to allow removing them in a backwards compatible manner.

Project description

sqlalchemy-deprecated-column

PyPi PyVersions Coverage License

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.x0.2.0), following the SemVer convention for 0.y.z versions. Patch releases (0.1.30.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:

  1. Deprecate: replace mapped_column() with deprecated_column() and run an Alembic migration. The column stays in the database but becomes nullable if it wasn't already.
  2. 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 DeprecationWarning at runtime, making stale references easy to find and remove.
  3. 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_username returns None and emits a DeprecationWarning naming 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 a DeprecationWarning and evaluates to SQL NULL.
  • Warns on write and discards the value: instance.old_username = "x" emits a DeprecationWarning and silently drops the value, so no stale data is written to the database.

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 COLUMN for deprecated columns.
  • Generate ALTER TABLE … DROP NOT NULL if the column was originally non-nullable. This is needed because once the column is deprecated the ORM stops including it in INSERT statements — a NOT NULL column 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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sqlalchemy_deprecated_column-0.2.0.tar.gz (5.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sqlalchemy_deprecated_column-0.2.0-py3-none-any.whl (6.6 kB view details)

Uploaded Python 3

File details

Details for the file sqlalchemy_deprecated_column-0.2.0.tar.gz.

File metadata

  • Download URL: sqlalchemy_deprecated_column-0.2.0.tar.gz
  • Upload date:
  • Size: 5.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.11 {"installer":{"name":"uv","version":"0.11.11","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}

File hashes

Hashes for sqlalchemy_deprecated_column-0.2.0.tar.gz
Algorithm Hash digest
SHA256 8b6a112ca1b43cccde3d3c78ea26e983d30053674da4344de3c1c16da62aa0a6
MD5 3ecae96f913509aaae421431e76799ba
BLAKE2b-256 1e98e5b23a16e182ae3b1b09e2bc90aaf1c0e8ef6e9aac7d3b56b0dabb5f16f0

See more details on using hashes here.

File details

Details for the file sqlalchemy_deprecated_column-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: sqlalchemy_deprecated_column-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 6.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.11 {"installer":{"name":"uv","version":"0.11.11","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}

File hashes

Hashes for sqlalchemy_deprecated_column-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2cbc628ff67daf2c52895c0bfdcad200b2e0ed3de076a78393911b8aca0831af
MD5 ad756dd31eb7c2e93c6d21973cc900f4
BLAKE2b-256 5772656fb332adcb23a8c36bcae402d0cde907258ba1e7a16e9ebb53ccdda29c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page