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_1_4_33~24 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7a93686ae47aca374a6ed29fdf1ae6cb5451cc63;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 (cherry picked from commit 764e36e5e7b7faf1a97b4b06be1ca307ac4fce46) --- 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 9a73bb5c2c..fbf377afd4 100644 --- a/lib/sqlalchemy/ext/associationproxy.py +++ b/lib/sqlalchemy/ext/associationproxy.py @@ -383,6 +383,22 @@ class AssociationProxyInstance(object): return AmbiguousAssociationProxyInstance( parent, owning_class, target_class, value_attr ) + except Exception as err: + util.raise_( + exc.InvalidRequestError( + "Association proxy received an unexpected error when " + "trying to retreive attribute " + '"%s.%s" from ' + 'class "%s": %s' + % ( + target_class.__name__, + parent.value_attr, + 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 0b05fe0387..44f3890de8 100644 --- a/test/ext/test_associationproxy.py +++ b/test/ext/test_associationproxy.py @@ -34,6 +34,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.mock import call from sqlalchemy.testing.mock import Mock @@ -3343,6 +3344,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" @@ -3386,6 +3391,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" @@ -3394,6 +3403,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")