Skip to content

Commit

Permalink
Merge "More descriptive error for non-mapped string prop name"
Browse files Browse the repository at this point in the history
  • Loading branch information
zzzeek authored and Gerrit Code Review committed Aug 26, 2020
2 parents 1d18c46 + aff9d06 commit 014879f
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 2 deletions.
10 changes: 10 additions & 0 deletions doc/build/changelog/unreleased_13/4589.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.. change::
:tags: bug, orm
:tickets: 4589

Fixed issue where using a loader option against a string attribute name
that is not actually a mapped attribute, such as a plain Python descriptor,
would raise an uninformative AttributeError; a descriptive error is now
raised.


18 changes: 17 additions & 1 deletion lib/sqlalchemy/orm/strategy_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from .base import _is_mapped_class
from .base import InspectionAttr
from .interfaces import LoaderOption
from .interfaces import MapperProperty
from .interfaces import PropComparator
from .path_registry import _DEFAULT_TOKEN
from .path_registry import _WILDCARD_TOKEN
Expand Down Expand Up @@ -170,6 +171,7 @@ def _generate_path(

if isinstance(attr, util.string_types):
default_token = attr.endswith(_DEFAULT_TOKEN)
attr_str_name = attr
if attr.endswith(_WILDCARD_TOKEN) or default_token:
if default_token:
self.propagate_to_loaders = False
Expand Down Expand Up @@ -207,7 +209,21 @@ def _generate_path(
else:
return None
else:
attr = found_property = attr.property
try:
attr = found_property = attr.property
except AttributeError as ae:
if not isinstance(attr, MapperProperty):
util.raise_(
sa_exc.ArgumentError(
'Expected attribute "%s" on %s to be a '
"mapped attribute; "
"instead got %s object."
% (attr_str_name, ent, type(attr))
),
replace_context=ae,
)
else:
raise

path = path[attr]
elif _is_mapped_class(attr):
Expand Down
39 changes: 38 additions & 1 deletion test/orm/test_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ class SubItem(cls.classes.Item):
},
)

class OrderWProp(cls.classes.Order):
@property
def some_attr(self):
return "hi"

mapper(OrderWProp, None, inherits=cls.classes.Order)


class PathTest(object):
def _make_path(self, path):
Expand Down Expand Up @@ -193,6 +200,20 @@ def test_gen_path_attr_entity_invalid_raiseerr(self):
"relationship",
)

def test_gen_path_attr_str_not_mapped(self):
OrderWProp = self.classes.OrderWProp

sess = Session()
q = sess.query(OrderWProp).options(defer("some_attr"))

assert_raises_message(
sa.exc.ArgumentError,
r"Expected attribute \"some_attr\" on mapped class "
"OrderWProp->orders to be a mapped attribute; instead "
"got .*property.* object.",
q._compile_state,
)

def test_gen_path_attr_entity_invalid_noraiseerr(self):
User = self.classes.User
Order = self.classes.Order
Expand Down Expand Up @@ -1141,7 +1162,7 @@ def test_option_against_wrong_multi_entity_type_attr_three(self):
'column property "Keyword.keywords"',
)

def test_wrong_type_in_option(self):
def test_wrong_type_in_option_cls(self):
Item = self.classes.Item
Keyword = self.classes.Keyword
self._assert_eager_with_entity_exception(
Expand All @@ -1150,6 +1171,15 @@ def test_wrong_type_in_option(self):
r"mapper option expects string key or list of attributes",
)

def test_wrong_type_in_option_descriptor(self):
OrderWProp = self.classes.OrderWProp

self._assert_eager_with_entity_exception(
[OrderWProp],
(joinedload(OrderWProp.some_attr),),
r"mapper option expects string key or list of attributes",
)

def test_non_contiguous_all_option(self):
User = self.classes.User
self._assert_eager_with_entity_exception(
Expand Down Expand Up @@ -1215,6 +1245,13 @@ def setup_mappers(cls):
),
)

class OrderWProp(cls.classes.Order):
@property
def some_attr(self):
return "hi"

mapper(OrderWProp, None, inherits=cls.classes.Order)

def _assert_option(self, entity_list, option):
Item = self.classes.Item

Expand Down

0 comments on commit 014879f

Please sign in to comment.