--- /dev/null
+.. 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.
+
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
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
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"
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"
_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")