summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2018-07-08 19:10:36 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2018-07-08 19:10:36 -0400
commitaec57258b3b33fe070ebb54f31f1627db07f072b (patch)
tree93dfb251684d782b310416dcb6a823e97791beb8
parent284009683d9e48e19cc09e740e7b928c2c02997c (diff)
downloadsqlalchemy-aec57258b3b33fe070ebb54f31f1627db07f072b.tar.gz
Check tokens in chop path for inspectionattr before calling is_mapper
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. Change-Id: I2997ead0b8b9fa0edd009aa6f3161f4618fab97b Fixes: #4298
-rw-r--r--doc/build/changelog/unreleased_12/4298.rst7
-rw-r--r--lib/sqlalchemy/orm/strategy_options.py6
-rw-r--r--test/orm/test_options.py52
3 files changed, 62 insertions, 3 deletions
diff --git a/doc/build/changelog/unreleased_12/4298.rst b/doc/build/changelog/unreleased_12/4298.rst
new file mode 100644
index 000000000..8066ccdd0
--- /dev/null
+++ b/doc/build/changelog/unreleased_12/4298.rst
@@ -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.
diff --git a/lib/sqlalchemy/orm/strategy_options.py b/lib/sqlalchemy/orm/strategy_options.py
index 90d14075c..af9bd71b6 100644
--- a/lib/sqlalchemy/orm/strategy_options.py
+++ b/lib/sqlalchemy/orm/strategy_options.py
@@ -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:
diff --git a/test/orm/test_options.py b/test/orm/test_options.py
index 3c1f6527d..e94b9e6b6 100644
--- a/test/orm/test_options.py
+++ b/test/orm/test_options.py
@@ -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")