Check tokens in chop path for inspectionattr before calling is_mapper

Fixed regression in 1.2.9 due to 🎫`4287` where using a
:class::`.Load` option in conjunction with a string wildcard would result
in a TypeError.

Change-Id: I2997ead0b8b9fa0edd009aa6f3161f4618fab97b
Fixes: #4298
This commit is contained in:
Mike Bayer
2018-07-08 19:10:36 -04:00
parent 284009683d
commit aec57258b3
3 changed files with 62 additions and 3 deletions
+7
View File
@@ -0,0 +1,7 @@
.. change::
:tags: bug, orm
:tickets: 4298
Fixed regression in 1.2.9 due to :ticket:`4287` where using a
:class::`.Load` option in conjunction with a string wildcard would result
in a TypeError.
+4 -2
View File
@@ -13,7 +13,8 @@ from .attributes import QueryableAttribute
from .. import util
from ..sql.base import _generative, Generative
from .. import exc as sa_exc, inspect
from .base import _is_aliased_class, _class_to_mapper, _is_mapped_class
from .base import _is_aliased_class, _class_to_mapper, _is_mapped_class, \
InspectionAttr
from . import util as orm_util
from .path_registry import PathRegistry, TokenRegistry, \
_WILDCARD_TOKEN, _DEFAULT_TOKEN
@@ -385,7 +386,8 @@ class Load(Generative, MapperOption):
if c_token is p_token:
continue
elif c_token.is_mapper and p_token.is_mapper and \
elif isinstance(c_token, InspectionAttr) and \
c_token.is_mapper and p_token.is_mapper and \
c_token.isa(p_token):
continue
else:
+51 -1
View File
@@ -2,7 +2,7 @@ from sqlalchemy import inspect
from sqlalchemy.orm import attributes, mapper, relationship, backref, \
configure_mappers, create_session, synonym, Session, class_mapper, \
aliased, column_property, joinedload_all, joinedload, Query,\
util as orm_util, Load, defer, defaultload
util as orm_util, Load, defer, defaultload, lazyload
from sqlalchemy.orm.query import QueryContext
from sqlalchemy.orm import strategy_options
import sqlalchemy as sa
@@ -1228,6 +1228,56 @@ class CacheKeyTest(PathTest, QueryTest):
None
)
def test_bound_cache_key_wildcard_one(self):
# do not change this test, it is testing
# a specific condition in Load._chop_path().
User, Address = self.classes('User', 'Address')
query_path = self._make_path_registry([User, "addresses"])
opt = Load(User).lazyload("*")
eq_(
opt._generate_cache_key(query_path),
None
)
def test_unbound_cache_key_wildcard_one(self):
User, Address = self.classes('User', 'Address')
query_path = self._make_path_registry([User, "addresses"])
opt = lazyload("*")
eq_(
opt._generate_cache_key(query_path),
(('relationship:_sa_default', ('lazy', 'select')),)
)
def test_bound_cache_key_wildcard_two(self):
User, Address, Order, Item, SubItem, Keyword = self.classes(
'User', 'Address', 'Order', 'Item', 'SubItem', "Keyword")
query_path = self._make_path_registry([User])
opt = Load(User).lazyload("orders").lazyload("*")
eq_(
opt._generate_cache_key(query_path),
(('orders', Order, ('lazy', 'select')),
('orders', Order, 'relationship:*', ('lazy', 'select')))
)
def test_unbound_cache_key_wildcard_two(self):
User, Address, Order, Item, SubItem, Keyword = self.classes(
'User', 'Address', 'Order', 'Item', 'SubItem', "Keyword")
query_path = self._make_path_registry([User])
opt = lazyload("orders").lazyload("*")
eq_(
opt._generate_cache_key(query_path),
(('orders', Order, ('lazy', 'select')),
('orders', Order, 'relationship:*', ('lazy', 'select')))
)
def test_unbound_cache_key_of_type_subclass_relationship(self):
User, Address, Order, Item, SubItem, Keyword = self.classes(
'User', 'Address', 'Order', 'Item', 'SubItem', "Keyword")