From 1e05901bbe88f86060db13ceffc415e098e653f4 Mon Sep 17 00:00:00 2001 From: Federico Caselli Date: Wed, 14 Dec 2022 22:18:58 +0100 Subject: [PATCH] Improved error message in orm annotated declarative Fixes: #8980 Change-Id: I32c4cf8715ee43fa8415f0102394ddd43b1fee0a --- lib/sqlalchemy/orm/properties.py | 25 +++++++++++++++---- .../test_tm_future_annotations_sync.py | 18 ++++++++++++- test/orm/declarative/test_typed_mapping.py | 18 ++++++++++++- 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index 21df672eca..04b011f091 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -50,6 +50,7 @@ from ..sql.base import _NoArg from ..sql.roles import DDLConstraintColumnRole from ..sql.schema import Column from ..sql.schema import SchemaConst +from ..sql.type_api import TypeEngine from ..util.typing import de_optionalize_union_types from ..util.typing import de_stringify_annotation from ..util.typing import de_stringify_union_elements @@ -678,7 +679,10 @@ class MappedColumn( return self._init_column_for_annotation( - cls, registry, extracted_mapped_annotation, originating_module + cls, + registry, + extracted_mapped_annotation, + originating_module, ) @util.preload_module("sqlalchemy.orm.decl_base") @@ -760,9 +764,20 @@ class MappedColumn( if new_sqltype is not None: break else: - raise sa_exc.ArgumentError( - f"Could not locate SQLAlchemy Core " - f"type for Python type: {our_type}" - ) + if isinstance(our_type, TypeEngine) or ( + isinstance(our_type, type) + and issubclass(our_type, TypeEngine) + ): + raise sa_exc.ArgumentError( + f"The type provided inside the {self.column.key!r} " + "attribute Mapped annotation is the SQLAlchemy type " + f"{our_type}. Expected a Python type instead" + ) + else: + raise sa_exc.ArgumentError( + "Could not locate SQLAlchemy Core type for Python " + f"type {our_type} inside the {self.column.key!r} " + "attribute Mapped annotation" + ) self.column._set_type(new_sqltype) diff --git a/test/orm/declarative/test_tm_future_annotations_sync.py b/test/orm/declarative/test_tm_future_annotations_sync.py index 5d1b6b199e..787e09aac9 100644 --- a/test/orm/declarative/test_tm_future_annotations_sync.py +++ b/test/orm/declarative/test_tm_future_annotations_sync.py @@ -402,7 +402,8 @@ class MappedColumnTest(fixtures.TestBase, testing.AssertsCompiledSQL): with expect_raises_message( sa_exc.ArgumentError, - "Could not locate SQLAlchemy Core type for Python type: .*MyClass", + "Could not locate SQLAlchemy Core type for Python type " + ".*MyClass.* inside the 'data' attribute Mapped annotation", ): class User(decl_base): @@ -411,6 +412,21 @@ class MappedColumnTest(fixtures.TestBase, testing.AssertsCompiledSQL): id: Mapped[int] = mapped_column(primary_key=True) data: Mapped[MyClass] = mapped_column() + def test_construct_lhs_sqlalchemy_type(self, decl_base): + + with expect_raises_message( + sa_exc.ArgumentError, + "The type provided inside the 'data' attribute Mapped " + "annotation is the SQLAlchemy type .*BigInteger.*. Expected " + "a Python type instead", + ): + + class User(decl_base): + __tablename__ = "users" + + id: Mapped[int] = mapped_column(primary_key=True) + data: Mapped[BigInteger] = mapped_column() + def test_construct_rhs_type_override_lhs(self, decl_base): class Element(decl_base): __tablename__ = "element" diff --git a/test/orm/declarative/test_typed_mapping.py b/test/orm/declarative/test_typed_mapping.py index ffa640d4cd..da73104e26 100644 --- a/test/orm/declarative/test_typed_mapping.py +++ b/test/orm/declarative/test_typed_mapping.py @@ -393,7 +393,8 @@ class MappedColumnTest(fixtures.TestBase, testing.AssertsCompiledSQL): with expect_raises_message( sa_exc.ArgumentError, - "Could not locate SQLAlchemy Core type for Python type: .*MyClass", + "Could not locate SQLAlchemy Core type for Python type " + ".*MyClass.* inside the 'data' attribute Mapped annotation", ): class User(decl_base): @@ -402,6 +403,21 @@ class MappedColumnTest(fixtures.TestBase, testing.AssertsCompiledSQL): id: Mapped[int] = mapped_column(primary_key=True) data: Mapped[MyClass] = mapped_column() + def test_construct_lhs_sqlalchemy_type(self, decl_base): + + with expect_raises_message( + sa_exc.ArgumentError, + "The type provided inside the 'data' attribute Mapped " + "annotation is the SQLAlchemy type .*BigInteger.*. Expected " + "a Python type instead", + ): + + class User(decl_base): + __tablename__ = "users" + + id: Mapped[int] = mapped_column(primary_key=True) + data: Mapped[BigInteger] = mapped_column() + def test_construct_rhs_type_override_lhs(self, decl_base): class Element(decl_base): __tablename__ = "element" -- 2.47.2