From: Mike Bayer Date: Fri, 18 Mar 2022 14:33:40 +0000 (-0400) Subject: catch unexpected errors when accessing clslevel attribute X-Git-Tag: rel_2_0_0b1~419^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=764e36e5e7b7faf1a97b4b06be1ca307ac4fce46;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git catch unexpected errors when accessing clslevel attribute Improved the error message that's raised for the case where the :func:`.association_proxy` construct attempts to access a target attribute at the class level, and this access fails. The particular use case here is when proxying to a hybrid attribute that does not include a working class-level implementation. Fixes: #7827 Change-Id: Ic6ff9df010f49253e664a1e7c7e16d8546006965 --- diff --git a/doc/build/changelog/unreleased_14/7827.rst b/doc/build/changelog/unreleased_14/7827.rst new file mode 100644 index 0000000000..aedf25809d --- /dev/null +++ b/doc/build/changelog/unreleased_14/7827.rst @@ -0,0 +1,10 @@ +.. change:: + :tags: bug, ext + :tickets: 7827 + + Improved the error message that's raised for the case where the + :func:`.association_proxy` construct attempts to access a target attribute + at the class level, and this access fails. The particular use case here is + when proxying to a hybrid attribute that does not include a working + class-level implementation. + diff --git a/lib/sqlalchemy/ext/associationproxy.py b/lib/sqlalchemy/ext/associationproxy.py index 4d2b1d8b69..194eabb64e 100644 --- a/lib/sqlalchemy/ext/associationproxy.py +++ b/lib/sqlalchemy/ext/associationproxy.py @@ -583,6 +583,13 @@ class AssociationProxyInstance(SQLORMOperations[_T]): return AmbiguousAssociationProxyInstance( parent, owning_class, target_class, value_attr ) + except Exception as err: + raise exc.InvalidRequestError( + f"Association proxy received an unexpected error when " + f"trying to retreive attribute " + f'"{target_class.__name__}.{parent.value_attr}" from ' + f'class "{target_class.__name__}": {err}' + ) from err else: return cls._construct_for_assoc( target_assoc, parent, owning_class, target_class, value_attr diff --git a/test/ext/test_associationproxy.py b/test/ext/test_associationproxy.py index 484aed7953..a99b23338f 100644 --- a/test/ext/test_associationproxy.py +++ b/test/ext/test_associationproxy.py @@ -37,6 +37,7 @@ from sqlalchemy.testing import expect_warnings from sqlalchemy.testing import fixtures from sqlalchemy.testing import is_ from sqlalchemy.testing import is_false +from sqlalchemy.testing.assertions import expect_raises_message from sqlalchemy.testing.fixtures import fixture_session from sqlalchemy.testing.schema import Column from sqlalchemy.testing.schema import Table @@ -3365,6 +3366,10 @@ class ProxyHybridTest(fixtures.DeclarativeMappedTest, AssertsCompiledSQL): b_data = association_proxy("bs", "value") well_behaved_b_data = association_proxy("bs", "well_behaved_value") + fails_on_class_access = association_proxy( + "bs", "fails_on_class_access" + ) + class B(Base): __tablename__ = "b" @@ -3408,6 +3413,10 @@ class ProxyHybridTest(fixtures.DeclarativeMappedTest, AssertsCompiledSQL): def well_behaved_w_expr(cls): return cast(cls.data, Integer) + @hybrid_property + def fails_on_class_access(self): + return len(self.data) + class C(Base): __tablename__ = "c" @@ -3416,6 +3425,19 @@ class ProxyHybridTest(fixtures.DeclarativeMappedTest, AssertsCompiledSQL): _b = relationship("B") attr = association_proxy("_b", "well_behaved_w_expr") + def test_msg_fails_on_cls_access(self): + A, B = self.classes("A", "B") + + a1 = A(bs=[B(data="b1")]) + + with expect_raises_message( + exc.InvalidRequestError, + "Association proxy received an unexpected error when trying to " + 'retreive attribute "B.fails_on_class_access" from ' + r'class "B": .* no len\(\)', + ): + a1.fails_on_class_access + def test_get_ambiguous(self): A, B = self.classes("A", "B")