Allow hybrid_property, hybrid_method and association_proxy on SQLModel classes#1990
Open
alvinttang wants to merge 1 commit into
Open
Conversation
… v2 crash Defining a `sqlalchemy.ext.hybrid.hybrid_property` (or `hybrid_method`, `association_proxy`) directly on a `SQLModel` class body raises `pydantic.errors.PydanticUserError: A non-annotated attribute was detected` under Pydantic v2 because those SQLAlchemy descriptors carry no Pydantic annotation. Add them to `SQLModel.model_config["ignored_types"]` so Pydantic skips them during model construction, while SQLAlchemy continues to expose them as descriptors at runtime. Python-side hybrid evaluation now works on table models; emitting them as SQL expressions/columns is intentionally still left to user code (the proposed broader feature in PR fastapi#801). Refs fastapi#299 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Author
|
Friendly bump: this PR has a required |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Defining a SQLModel class with a SQLAlchemy descriptor (
hybrid_property,hybrid_method, orassociation_proxy) crashes at class-construction time with:This is the long-standing #299 (20 reactions / 13 comments). The issue was mass-closed on 2026-05-18 alongside many other un-triaged bugs, but the bug is still present on
mainand community workarounds (subclass SQLModel and setmodel_config['ignored_types']yourself) remain the only path. Reopening for review.Root cause
Pydantic v2's
inspect_namespacerejects every non-dunder, non-annotated attribute.hybrid_property/hybrid_method/association_proxyare SQLAlchemy descriptors users add without Python type annotations — that's the whole point of these descriptors. SQLModel never told Pydantic to treat them as ignored types viamodel_config['ignored_types'], so class construction crashes before SQLModel's metaclass even sees the column logic.Fix
sqlmodel/main.py(+11 / -1):AssociationProxyfromsqlalchemy.ext.associationproxyandhybrid_method/hybrid_propertyfromsqlalchemy.ext.hybrid.SQLModel.model_config = SQLModelConfig(from_attributes=True, ignored_types=(hybrid_property, hybrid_method, AssociationProxy)).Production diff is 10 net LOC.
This is intentionally disjoint and minimal: it stops the crash so users can define these descriptors on SQLModel classes. It does NOT implement DDL/expression generation for hybrid properties (a separate concern that PR #801 attempts in a much larger ~4400-line patch). Most users hitting #299 just want the descriptor to work at the Python level, which this PR enables.
Tests
tests/test_hybrid_property.py(new, 110 LOC, 4 tests):test_table_model_allows_hybrid_property— table model +@hybrid_property; instance returns the computed value.test_table_model_allows_hybrid_method— table model +@hybrid_method.test_table_model_allows_association_proxy— table model +association_proxy(...).test_non_table_model_allows_hybrid_property— non-table model.RED proof on main (4/4 fail):
GREEN after patch: 4/4 pass; broader sweep
pytest tests/→ 88 passed.ruff check/ruff format --checkclean.Risk notes
hybrid_propertyas an unannotated raw attribute hoping Pydantic would treat it as a field: vanishingly unlikely, sincehybrid_propertyis meaningless outside an ORM context.Refs #299