Skip to content

Support SQLAlchemy 2.0 alongside 1.4 - #284

Open
xravitycapital wants to merge 1 commit into
dynotx:mainfrom
xravitycapital:sqlalchemy-2-compat
Open

xravitycapital wants to merge 1 commit into
dynotx:mainfrom
xravitycapital:sqlalchemy-2-compat

Conversation

@xravitycapital

Copy link
Copy Markdown

Closes #205

Thanks @steve-dyno for the update on the issue. Since Dyno is looking at SQLAlchemy 2 again, I thought a concrete PR might be easier to evaluate than a description. No pressure on timing: if it's not the right moment, or you'd rather take a different approach, I'm happy to adjust it or close it.

Why

Projects that depend on SQLAlchemy 2.x (for example through fastapi-users-db-sqlalchemy) can't install liminal-orm because it pins sqlalchemy<2. This keeps 1.4 fully supported, so anyone still on 1.x isn't affected, and also allows 2.0.x. Teams can then upgrade SQLAlchemy whenever they're ready.

Changes

  • pyproject.toml: sqlalchemy>=1.4.53,<2.1. The dev group still pins 1.4.53, so the locked environment is unchanged.
  • liminal/orm/base.py:
    • Import declarative_base from sqlalchemy.orm. It's available since 1.4, and the ext.declarative import is deprecated in 2.0.
    • Set __allow_unmapped__ = True on Base. With it, 2.0 accepts existing col: SqlColumn = Column(...) annotations, including those in generated model files. 1.4 ignores this attribute.
  • liminal/orm/base_model.py and liminal/orm/base_results_model.py: annotate creator_id as Mapped[str | None] and creator as Mapped[Any]. 2.0 requires Mapped[] return annotations on @declared_attr, and __allow_unmapped__ doesn't cover them.
  • .github/workflows/cicd.yml: add a step that also runs the tests on SQLAlchemy 2.0, via uv run --with "sqlalchemy>=2.0,<2.1".

Testing

Python SQLAlchemy 1.4.53 SQLAlchemy 2.0.57 (SQLAlchemy deprecation warnings as errors)
3.10 19 passed 19 passed
3.12 19 passed 19 passed
3.13 19 passed 19 passed

pre-commit (ruff, ruff-format, mypy) passes on the changed files.

Notes for reviewers

  • The test suite doesn't hit a real Benchling warehouse, so queries against Postgres on 2.0 aren't exercised here. Liminal's own query code uses session.query(...) and connection().execute(query.statement), and 2.0 still supports both.
  • Users' own query code may still use APIs that only exist in 1.x, such as engine.execute. That's outside this PR, but it might be worth a line in the release notes.

About me

To be upfront: I used an AI coding assistant for this, and I reviewed and tested every change myself. I'm also trying to build a small paid service around this kind of work, partly to earn some extra money for my family. This PR is completely free, though, with nothing expected in return. I just hope it's useful. Sorry if this is an unwelcome interruption.

🤖 Generated with Claude Code

Widen the pin to sqlalchemy>=1.4.53,<2.1, import declarative_base from
sqlalchemy.orm, set __allow_unmapped__ on Base so existing Column
annotations keep working on 2.0, annotate the creator_id/creator
declared_attrs with Mapped[...], and run the tests on 2.0 in CI.

Closes dynotx#205

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Upgrade to support SQLAlchemy 2.x

1 participant