From: Mike Bayer Date: Wed, 9 Jan 2019 07:01:16 +0000 (-0500) Subject: Improve error messages in the area of loader options X-Git-Tag: rel_1_3_0b2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2eb3f211dae1188a6c1b3664f612f4628fd7b9a9;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Improve error messages in the area of loader options Improved error messages emitted by the ORM in the area of loader option traversal. This includes early detection of mis-matched loader strategies along with a clearer explanation why these strategies don't match. Fixes: #4433 Change-Id: I3351b64241f7f62ca141a0be95085e6ef8ca6d32 --- diff --git a/doc/build/changelog/unreleased_13/4433.rst b/doc/build/changelog/unreleased_13/4433.rst new file mode 100644 index 0000000000..a77354f3ea --- /dev/null +++ b/doc/build/changelog/unreleased_13/4433.rst @@ -0,0 +1,8 @@ +.. change:: + :tags: bug, orm + :tickets: 4433 + + Improved error messages emitted by the ORM in the area of loader option + traversal. This includes early detection of mis-matched loader strategies + along with a clearer explanation why these strategies don't match. + diff --git a/lib/sqlalchemy/orm/exc.py b/lib/sqlalchemy/orm/exc.py index e983844f6c..f061a6a56d 100644 --- a/lib/sqlalchemy/orm/exc.py +++ b/lib/sqlalchemy/orm/exc.py @@ -150,6 +150,38 @@ class MultipleResultsFound(sa_exc.InvalidRequestError): """A single database result was required but more than one were found.""" +class LoaderStrategyException(sa_exc.InvalidRequestError): + """A loader strategy for an attribute does not exist.""" + + def __init__( + self, + applied_to_property_type, + requesting_property, + applies_to, + actual_strategy_type, + strategy_key, + ): + if actual_strategy_type is None: + sa_exc.InvalidRequestError.__init__( + self, + "Can't find strategy %s for %s" + % (strategy_key, requesting_property), + ) + else: + sa_exc.InvalidRequestError.__init__( + self, + 'Can\'t apply "%s" strategy to property "%s", ' + 'which is a "%s"; this loader strategy is intended ' + 'to be used with a "%s".' + % ( + util.clsname_as_plain_name(actual_strategy_type), + requesting_property, + util.clsname_as_plain_name(applied_to_property_type), + util.clsname_as_plain_name(applies_to), + ), + ) + + def _safe_cls_name(cls): try: cls_name = ".".join((cls.__module__, cls.__name__)) diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py index 87b4cfcde8..d2b08a9087 100644 --- a/lib/sqlalchemy/orm/interfaces.py +++ b/lib/sqlalchemy/orm/interfaces.py @@ -22,6 +22,7 @@ from __future__ import absolute_import import collections +from . import exc as orm_exc from . import path_registry from .base import _MappedAttribute # noqa from .base import EXT_CONTINUE @@ -536,7 +537,7 @@ class StrategizedProperty(MapperProperty): try: return self._strategies[key] except KeyError: - cls = self._strategy_lookup(*key) + cls = self._strategy_lookup(self, *key) self._strategies[key] = self._strategies[cls] = strategy = cls( self, key ) @@ -592,7 +593,7 @@ class StrategizedProperty(MapperProperty): return decorate @classmethod - def _strategy_lookup(cls, *key): + def _strategy_lookup(cls, requesting_property, *key): for prop_cls in cls.__mro__: if prop_cls in cls._all_strategies: strategies = cls._all_strategies[prop_cls] @@ -600,7 +601,23 @@ class StrategizedProperty(MapperProperty): return strategies[key] except KeyError: pass - raise Exception("can't locate strategy for %s %s" % (cls, key)) + + for property_type, strats in cls._all_strategies.items(): + if key in strats: + intended_property_type = property_type + actual_strategy = strats[key] + break + else: + intended_property_type = None + actual_strategy = None + + raise orm_exc.LoaderStrategyException( + cls, + requesting_property, + intended_property_type, + actual_strategy, + key, + ) class MapperOption(object): diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 12b8b42689..9909724d3c 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -2001,12 +2001,12 @@ class Mapper(InspectionAttr): return "" % (id(self), self.class_.__name__) def __str__(self): - return "Mapper|%s|%s%s" % ( + return "mapped class %s%s->%s" % ( self.class_.__name__, - self.local_table is not None - and self.local_table.description - or None, - self.non_primary and "|non-primary" or "", + self.non_primary and " (non-primary)" or "", + self.local_table.description + if self.local_table is not None + else self.persist_selectable.description, ) def _is_orphan(self, state): diff --git a/lib/sqlalchemy/orm/strategy_options.py b/lib/sqlalchemy/orm/strategy_options.py index cac23f6be0..19c81860e8 100644 --- a/lib/sqlalchemy/orm/strategy_options.py +++ b/lib/sqlalchemy/orm/strategy_options.py @@ -180,10 +180,11 @@ class Load(Generative, MapperOption): else: query._attributes.update(self.context) - def _generate_path(self, path, attr, wildcard_key, raiseerr=True): + def _generate_path( + self, path, attr, for_strategy, wildcard_key, raiseerr=True + ): existing_of_type = self._of_type self._of_type = None - if raiseerr and not path.has_entity: if isinstance(path, TokenRegistry): raise sa_exc.ArgumentError( @@ -191,9 +192,8 @@ class Load(Generative, MapperOption): ) else: raise sa_exc.ArgumentError( - "Attribute '%s' of entity '%s' does not " - "refer to a mapped entity" - % (path.prop.key, path.parent.entity) + "Mapped attribute '%s' does not " + "refer to a mapped entity" % (path.prop,) ) if isinstance(attr, util.string_types): @@ -219,13 +219,13 @@ class Load(Generative, MapperOption): except AttributeError: if raiseerr: raise sa_exc.ArgumentError( - "Can't find property named '%s' on the " - "mapped entity %s in this Query. " % (attr, ent) + 'Can\'t find property named "%s" on ' + "%s in this Query. " % (attr, ent) ) else: return None else: - attr = attr.property + attr = found_property = attr.property path = path[attr] elif _is_mapped_class(attr): @@ -238,7 +238,7 @@ class Load(Generative, MapperOption): else: return None else: - prop = attr.property + prop = found_property = attr.property if not prop.parent.common_parent(path.mapper): if raiseerr: @@ -298,6 +298,8 @@ class Load(Generative, MapperOption): else: path = path[prop] + if for_strategy is not None: + found_property._get_strategy(for_strategy) if path.has_entity: path = path.entity_path self.path = path @@ -320,7 +322,7 @@ class Load(Generative, MapperOption): self.is_class_strategy = False self.propagate_to_loaders = propagate_to_loaders # if the path is a wildcard, this will set propagate_to_loaders=False - self._generate_path(self.path, attr, "relationship") + self._generate_path(self.path, attr, strategy, "relationship") self.strategy = strategy if strategy is not None: self._set_path_strategy() @@ -333,7 +335,7 @@ class Load(Generative, MapperOption): for attr in attrs: cloned = self._generate() cloned.strategy = strategy - cloned._generate_path(self.path, attr, "column") + cloned._generate_path(self.path, attr, strategy, "column") cloned.propagate_to_loaders = True if opts: cloned.local_opts.update(opts) @@ -347,7 +349,7 @@ class Load(Generative, MapperOption): strategy = self._coerce_strat(strategy) for attr in attrs: - path = self._generate_path(self.path, attr, None) + path = self._generate_path(self.path, attr, strategy, None) cloned = self._generate() cloned.strategy = strategy cloned.path = path @@ -359,7 +361,7 @@ class Load(Generative, MapperOption): strategy = self._coerce_strat(strategy) cloned = self._generate() cloned.is_class_strategy = True - path = cloned._generate_path(self.path, None, None) + path = cloned._generate_path(self.path, None, strategy, None) cloned.strategy = strategy cloned.path = path cloned.propagate_to_loaders = True @@ -482,7 +484,7 @@ class _UnboundLoad(Load): def _set_path_strategy(self): self._to_bind.append(self) - def _generate_path(self, path, attr, wildcard_key): + def _generate_path(self, path, attr, for_strategy, wildcard_key): if ( wildcard_key and isinstance(attr, util.string_types) @@ -670,7 +672,7 @@ class _UnboundLoad(Load): elif isinstance(token, PropComparator): prop = token.property entity = self._find_entity_prop_comparator( - entities, prop.key, token._parententity, raiseerr + entities, prop, token._parententity, raiseerr ) elif self.is_class_strategy and _is_mapped_class(token): entity = inspect(token) @@ -703,9 +705,14 @@ class _UnboundLoad(Load): path = loader.path if not loader.is_class_strategy: - for token in start_path: + for idx, token in enumerate(start_path): + if not loader._generate_path( - loader.path, token, None, raiseerr + loader.path, + token, + self.strategy if idx == len(start_path) - 1 else None, + None, + raiseerr, ): return @@ -738,7 +745,7 @@ class _UnboundLoad(Load): return loader - def _find_entity_prop_comparator(self, entities, token, mapper, raiseerr): + def _find_entity_prop_comparator(self, entities, prop, mapper, raiseerr): if _is_aliased_class(mapper): searchfor = mapper else: @@ -750,15 +757,18 @@ class _UnboundLoad(Load): if raiseerr: if not list(entities): raise sa_exc.ArgumentError( - "Query has only expression-based entities - " - "can't find property named '%s'." % (token,) + "Query has only expression-based entities, " + 'which do not apply to %s "%s"' + % (util.clsname_as_plain_name(type(prop)), prop) ) else: raise sa_exc.ArgumentError( - "Can't find property '%s' on any entity " - "specified in this Query. Note the full path " - "from root (%s) to target entity must be specified." - % (token, ",".join(str(x) for x in entities)) + 'Mapped attribute "%s" does not apply to any of the ' + "root entities in this query, e.g. %s. Please " + "specify the full path " + "from one of the root entities to the target " + "attribute. " + % (prop, ", ".join(str(x) for x in entities)) ) else: return None @@ -768,9 +778,17 @@ class _UnboundLoad(Load): if len(list(entities)) != 1: if raiseerr: raise sa_exc.ArgumentError( - "Wildcard loader can only be used with exactly " - "one entity. Use Load(ent) to specify " - "specific entities." + "Can't apply wildcard ('*') or load_only() " + "loader option to multiple entities %s. Specify " + "loader options for each entity individually, such " + "as %s." + % ( + ", ".join(str(ent) for ent in entities), + ", ".join( + "Load(%s).some_option('*')" % ent + for ent in entities + ), + ) ) elif token.endswith(_DEFAULT_TOKEN): raiseerr = False @@ -784,7 +802,7 @@ class _UnboundLoad(Load): if raiseerr: raise sa_exc.ArgumentError( "Query has only expression-based entities - " - "can't find property named '%s'." % (token,) + 'can\'t find property named "%s".' % (token,) ) else: return None diff --git a/lib/sqlalchemy/orm/util.py b/lib/sqlalchemy/orm/util.py index 8873a6a72a..92dd4c4ecd 100644 --- a/lib/sqlalchemy/orm/util.py +++ b/lib/sqlalchemy/orm/util.py @@ -530,6 +530,9 @@ class AliasedClass(object): self._aliased_insp._target.__name__, ) + def __str__(self): + return str(self._aliased_insp) + class AliasedInsp(InspectionAttr): """Provide an inspection interface for an @@ -714,6 +717,9 @@ class AliasedInsp(InspectionAttr): with_poly, ) + def __str__(self): + return "aliased(%s)" % (self._target.__name__,) + inspection._inspects(AliasedClass)(lambda target: target._aliased_insp) inspection._inspects(AliasedInsp)(lambda target: target) diff --git a/lib/sqlalchemy/util/__init__.py b/lib/sqlalchemy/util/__init__.py index 383c143c4c..1e54ef80bf 100644 --- a/lib/sqlalchemy/util/__init__.py +++ b/lib/sqlalchemy/util/__init__.py @@ -102,6 +102,7 @@ from .langhelpers import bool_or_str # noqa from .langhelpers import chop_traceback # noqa from .langhelpers import class_hierarchy # noqa from .langhelpers import classproperty # noqa +from .langhelpers import clsname_as_plain_name # noqa from .langhelpers import coerce_kw_type # noqa from .langhelpers import constructor_copy # noqa from .langhelpers import counter # noqa diff --git a/lib/sqlalchemy/util/langhelpers.py b/lib/sqlalchemy/util/langhelpers.py index 1bc3c00de2..bfe3fd275c 100644 --- a/lib/sqlalchemy/util/langhelpers.py +++ b/lib/sqlalchemy/util/langhelpers.py @@ -78,6 +78,12 @@ class safe_reraise(object): compat.reraise(type_, value, traceback) +def clsname_as_plain_name(cls): + return " ".join( + n.lower() for n in re.findall(r"([A-Z][a-z]+)", cls.__name__) + ) + + def decode_slice(slc): """decode a slice object as sent to __getitem__. diff --git a/test/ext/declarative/test_basic.py b/test/ext/declarative/test_basic.py index 4406925ffa..8b60a11763 100644 --- a/test/ext/declarative/test_basic.py +++ b/test/ext/declarative/test_basic.py @@ -982,7 +982,7 @@ class DeclarativeTest(DeclarativeTestBase): sa.exc.InvalidRequestError, "^One or more mappers failed to initialize" " - can't proceed with initialization of other mappers. " - r"Triggering mapper: 'Mapper\|User\|users'. " + r"Triggering mapper: 'mapped class User->users'. " "Original exception was: When initializing.*", configure_mappers, ) diff --git a/test/orm/inheritance/test_basic.py b/test/orm/inheritance/test_basic.py index 6c9da92d20..59ecc7c986 100644 --- a/test/orm/inheritance/test_basic.py +++ b/test/orm/inheritance/test_basic.py @@ -2010,7 +2010,7 @@ class DistinctPKTest(fixtures.MappedTest): ) assert_raises_message( sa_exc.SAWarning, - r"On mapper Mapper\|Employee\|employees, " + r"On mapper mapped class Employee->employees, " "primary key column 'persons.id' is being " "combined with distinct primary key column 'employees.eid' " "in attribute 'id'. Use explicit properties to give " diff --git a/test/orm/test_deprecations.py b/test/orm/test_deprecations.py index 7ce05345bb..679b3ec5bd 100644 --- a/test/orm/test_deprecations.py +++ b/test/orm/test_deprecations.py @@ -1839,8 +1839,8 @@ class DeprecatedOptionAllTest(OptionsPathTest, _fixtures.FixtureTest): self._assert_eager_with_entity_exception( [Item], (joinedload_all("keywords.foo"),), - r"Can't find property named 'foo' on the mapped entity " - r"Mapper\|Keyword\|keywords in this Query.", + 'Can\'t find property named \\"foo\\" on mapped class ' + "Keyword->keywords in this Query.", ) def test_all_path_vs_chained(self): diff --git a/test/orm/test_mapper.py b/test/orm/test_mapper.py index 06929c6bc3..93cf19faea 100644 --- a/test/orm/test_mapper.py +++ b/test/orm/test_mapper.py @@ -187,13 +187,11 @@ class MapperTest(_fixtures.FixtureTest, AssertsCompiledSQL): for i in range(3): assert_raises_message( sa.exc.InvalidRequestError, - "^One or more " - "mappers failed to initialize - can't " - "proceed with initialization of other " - r"mappers. Triggering mapper\: " - r"'Mapper\|Address\|addresses'." - " Original exception was: Class " - "'test.orm._fixtures.User' is not mapped$", + "One or more mappers failed to initialize - can't " + "proceed with initialization of other mappers. " + "Triggering mapper: 'mapped class Address->addresses'. " + "Original exception was: Class 'test.orm._fixtures.User' " + "is not mapped", configure_mappers, ) @@ -2540,8 +2538,10 @@ class DeepOptionsTest(_fixtures.FixtureTest): assert_raises_message( sa.exc.ArgumentError, - "Can't find property 'items' on any entity " - "specified in this Query.", + 'Mapped attribute "Order.items" does not apply to any of the ' + "root entities in this query, e.g. mapped class User->users. " + "Please specify the full path from one of the root entities " + "to the target attribute.", sess.query(User).options, sa.orm.joinedload(Order.items), ) diff --git a/test/orm/test_options.py b/test/orm/test_options.py index 4d205e593f..b4953cd3bc 100644 --- a/test/orm/test_options.py +++ b/test/orm/test_options.py @@ -10,9 +10,11 @@ from sqlalchemy.orm import class_mapper from sqlalchemy.orm import column_property from sqlalchemy.orm import create_session from sqlalchemy.orm import defaultload +from sqlalchemy.orm import exc as orm_exc from sqlalchemy.orm import joinedload from sqlalchemy.orm import lazyload from sqlalchemy.orm import Load +from sqlalchemy.orm import load_only from sqlalchemy.orm import mapper from sqlalchemy.orm import relationship from sqlalchemy.orm import Session @@ -107,7 +109,10 @@ class LoadTest(PathTest, QueryTest): result = Load(User) eq_( result._generate_path( - inspect(User)._path_registry, User.addresses, "relationship" + inspect(User)._path_registry, + User.addresses, + None, + "relationship", ), self._make_path_registry([User, "addresses", Address]), ) @@ -118,7 +123,7 @@ class LoadTest(PathTest, QueryTest): result = Load(User) eq_( result._generate_path( - inspect(User)._path_registry, User.name, "column" + inspect(User)._path_registry, User.name, None, "column" ), self._make_path_registry([User, "name"]), ) @@ -130,7 +135,7 @@ class LoadTest(PathTest, QueryTest): result = Load(User) eq_( result._generate_path( - inspect(User)._path_registry, "addresses", "relationship" + inspect(User)._path_registry, "addresses", None, "relationship" ), self._make_path_registry([User, "addresses", Address]), ) @@ -141,7 +146,7 @@ class LoadTest(PathTest, QueryTest): result = Load(User) eq_( result._generate_path( - inspect(User)._path_registry, "name", "column" + inspect(User)._path_registry, "name", None, "column" ), self._make_path_registry([User, "name"]), ) @@ -158,6 +163,7 @@ class LoadTest(PathTest, QueryTest): result._generate_path, result.path, User.addresses, + None, "relationship", ) @@ -174,6 +180,7 @@ class LoadTest(PathTest, QueryTest): result._generate_path, inspect(User)._path_registry, Order.items, + None, "relationship", ) @@ -187,6 +194,7 @@ class LoadTest(PathTest, QueryTest): result._generate_path( inspect(User)._path_registry, Order.items, + None, "relationship", False, ), @@ -930,8 +938,8 @@ class OptionsNoPropTest(_fixtures.FixtureTest): Item = self.classes.Item message = ( - "Query has only expression-based entities - " - "can't find property named 'keywords'." + "Query has only expression-based entities - can't " + 'find property named "keywords".' ) self._assert_eager_with_just_column_exception( Item.id, "keywords", message @@ -943,8 +951,8 @@ class OptionsNoPropTest(_fixtures.FixtureTest): self._assert_eager_with_just_column_exception( Item.id, Item.keywords, - "Query has only expression-based entities " - "- can't find property named 'keywords'.", + "Query has only expression-based entities, which do not apply " + 'to relationship property "Item.keywords"', ) def test_option_against_nonexistent_PropComparator(self): @@ -953,10 +961,10 @@ class OptionsNoPropTest(_fixtures.FixtureTest): self._assert_eager_with_entity_exception( [Keyword], (joinedload(Item.keywords),), - r"Can't find property 'keywords' on any entity specified " - r"in this Query. Note the full path from root " - r"\(Mapper\|Keyword\|keywords\) to target entity must be " - r"specified.", + 'Mapped attribute "Item.keywords" does not apply to any of the ' + "root entities in this query, e.g. mapped class " + "Keyword->keywords. Please specify the full path from one of " + "the root entities to the target attribute. ", ) def test_option_against_nonexistent_basestring(self): @@ -964,8 +972,8 @@ class OptionsNoPropTest(_fixtures.FixtureTest): self._assert_eager_with_entity_exception( [Item], (joinedload("foo"),), - r"Can't find property named 'foo' on the mapped " - r"entity Mapper\|Item\|items in this Query.", + 'Can\'t find property named "foo" on mapped class ' + "Item->items in this Query.", ) def test_option_against_nonexistent_twolevel_basestring(self): @@ -973,8 +981,8 @@ class OptionsNoPropTest(_fixtures.FixtureTest): self._assert_eager_with_entity_exception( [Item], (joinedload("keywords.foo"),), - r"Can't find property named 'foo' on the mapped entity " - r"Mapper\|Keyword\|keywords in this Query.", + 'Can\'t find property named "foo" on mapped class ' + "Keyword->keywords in this Query.", ) def test_option_against_nonexistent_twolevel_chained(self): @@ -982,8 +990,8 @@ class OptionsNoPropTest(_fixtures.FixtureTest): self._assert_eager_with_entity_exception( [Item], (joinedload("keywords").joinedload("foo"),), - r"Can't find property named 'foo' on the mapped entity " - r"Mapper\|Keyword\|keywords in this Query.", + 'Can\'t find property named "foo" on mapped class ' + "Keyword->keywords in this Query.", ) @testing.fails_if( @@ -1016,21 +1024,57 @@ class OptionsNoPropTest(_fixtures.FixtureTest): def test_option_against_wrong_entity_type_basestring(self): Item = self.classes.Item - self._assert_eager_with_entity_exception( + self._assert_loader_strategy_exception( [Item], (joinedload("id").joinedload("keywords"),), - r"Attribute 'id' of entity 'Mapper\|Item\|items' does not " - r"refer to a mapped entity", + 'Can\'t apply "joined loader" strategy to property "Item.id", ' + 'which is a "column property"; this loader strategy is ' + 'intended to be used with a "relationship property".', + ) + + def test_col_option_against_relationship_basestring(self): + Item = self.classes.Item + self._assert_loader_strategy_exception( + [Item], + (load_only("keywords"),), + 'Can\'t apply "column loader" strategy to property ' + '"Item.keywords", which is a "relationship property"; this ' + 'loader strategy is intended to be used with a "column property".', + ) + + def test_load_only_against_multi_entity_attr(self): + User = self.classes.User + Item = self.classes.Item + self._assert_eager_with_entity_exception( + [User, Item], + (load_only(User.id, Item.id),), + r"Can't apply wildcard \('\*'\) or load_only\(\) loader option " + "to multiple entities mapped class User->users, mapped class " + "Item->items. Specify loader options for each entity " + "individually, such as " + r"Load\(mapped class User->users\).some_option\('\*'\), " + r"Load\(mapped class Item->items\).some_option\('\*'\).", + ) + + def test_col_option_against_relationship_attr(self): + Item = self.classes.Item + self._assert_loader_strategy_exception( + [Item], + (load_only(Item.keywords),), + 'Can\'t apply "column loader" strategy to property ' + '"Item.keywords", which is a "relationship property"; this ' + 'loader strategy is intended to be used with a "column property".', ) def test_option_against_multi_non_relation_twolevel_basestring(self): Item = self.classes.Item Keyword = self.classes.Keyword - self._assert_eager_with_entity_exception( + self._assert_loader_strategy_exception( [Keyword, Item], (joinedload("id").joinedload("keywords"),), - r"Attribute 'id' of entity 'Mapper\|Keyword\|keywords' " - "does not refer to a mapped entity", + 'Can\'t apply "joined loader" strategy to property "Keyword.id", ' + 'which is a "column property"; this loader strategy is intended ' + 'to be used with a "relationship property".', ) def test_option_against_multi_nonexistent_basestring(self): @@ -1039,8 +1083,8 @@ class OptionsNoPropTest(_fixtures.FixtureTest): self._assert_eager_with_entity_exception( [Keyword, Item], (joinedload("description"),), - r"Can't find property named 'description' on the mapped " - r"entity Mapper\|Keyword\|keywords in this Query.", + 'Can\'t find property named "description" on mapped class ' + "Keyword->keywords in this Query.", ) def test_option_against_multi_no_entities_basestring(self): @@ -1050,27 +1094,29 @@ class OptionsNoPropTest(_fixtures.FixtureTest): [Keyword.id, Item.id], (joinedload("keywords"),), r"Query has only expression-based entities - can't find property " - "named 'keywords'.", + 'named "keywords".', ) def test_option_against_wrong_multi_entity_type_attr_one(self): Item = self.classes.Item Keyword = self.classes.Keyword - self._assert_eager_with_entity_exception( + self._assert_loader_strategy_exception( [Keyword, Item], (joinedload(Keyword.id).joinedload(Item.keywords),), - r"Attribute 'id' of entity 'Mapper\|Keyword\|keywords' " - "does not refer to a mapped entity", + 'Can\'t apply "joined loader" strategy to property "Keyword.id", ' + 'which is a "column property"; this loader strategy is intended ' + 'to be used with a "relationship property".', ) def test_option_against_wrong_multi_entity_type_attr_two(self): Item = self.classes.Item Keyword = self.classes.Keyword - self._assert_eager_with_entity_exception( + self._assert_loader_strategy_exception( [Keyword, Item], (joinedload(Keyword.keywords).joinedload(Item.keywords),), - r"Attribute 'keywords' of entity 'Mapper\|Keyword\|keywords' " - "does not refer to a mapped entity", + 'Can\'t apply "joined loader" strategy to property ' + '"Keyword.keywords", which is a "column property"; this loader ' + 'strategy is intended to be used with a "relationship property".', ) def test_option_against_wrong_multi_entity_type_attr_three(self): @@ -1079,8 +1125,8 @@ class OptionsNoPropTest(_fixtures.FixtureTest): self._assert_eager_with_entity_exception( [Keyword.id, Item.id], (joinedload(Keyword.keywords).joinedload(Item.keywords),), - r"Query has only expression-based entities - " - "can't find property named 'keywords'.", + "Query has only expression-based entities, which do not apply to " + 'column property "Keyword.keywords"', ) def test_wrong_type_in_option(self): @@ -1164,6 +1210,14 @@ class OptionsNoPropTest(_fixtures.FixtureTest): key = ("loader", (inspect(Item), inspect(Item).attrs.keywords)) assert key in q._attributes + def _assert_loader_strategy_exception(self, entity_list, options, message): + assert_raises_message( + orm_exc.LoaderStrategyException, + message, + create_session().query(*entity_list).options, + *options + ) + def _assert_eager_with_entity_exception( self, entity_list, options, message ): diff --git a/test/orm/test_relationships.py b/test/orm/test_relationships.py index 6e1c699c41..652b8bacd6 100644 --- a/test/orm/test_relationships.py +++ b/test/orm/test_relationships.py @@ -2142,7 +2142,7 @@ class ManualBackrefTest(_fixtures.FixtureTest): r"User.addresses references " r"relationship Address.dingaling, " r"which does not " - r"reference mapper Mapper\|User\|users", + r"reference mapper mapped class User->users", configure_mappers, ) diff --git a/test/orm/test_sync.py b/test/orm/test_sync.py index 697a8097e5..880f0bd188 100644 --- a/test/orm/test_sync.py +++ b/test/orm/test_sync.py @@ -102,7 +102,7 @@ class SyncTest( assert_raises_message( orm_exc.UnmappedColumnError, "Can't execute sync rule for source column 't2.id'; " - r"mapper 'Mapper\|A\|t1' does not map this column.", + r"mapper 'mapped class A->t1' does not map this column.", sync.populate, a1, a_mapper, @@ -120,7 +120,7 @@ class SyncTest( orm_exc.UnmappedColumnError, r"Can't execute sync rule for destination " r"column 't1.id'; " - r"mapper 'Mapper\|B\|t2' does not map this column.", + r"mapper 'mapped class B->t2' does not map this column.", sync.populate, a1, a_mapper, @@ -160,7 +160,7 @@ class SyncTest( assert_raises_message( orm_exc.UnmappedColumnError, "Can't execute sync rule for destination " - r"column 't1.foo'; mapper 'Mapper\|B\|t2' does not " + r"column 't1.foo'; mapper 'mapped class B->t2' does not " "map this column.", sync.clear, b1, @@ -185,7 +185,7 @@ class SyncTest( assert_raises_message( orm_exc.UnmappedColumnError, "Can't execute sync rule for source column 't2.id'; " - r"mapper 'Mapper\|A\|t1' does not map this column.", + r"mapper 'mapped class A->t1' does not map this column.", sync.update, a1, a_mapper, @@ -210,7 +210,7 @@ class SyncTest( assert_raises_message( orm_exc.UnmappedColumnError, "Can't execute sync rule for source column 't2.id'; " - r"mapper 'Mapper\|A\|t1' does not map this column.", + r"mapper 'mapped class A->t1' does not map this column.", sync.populate_dict, a1, a_mapper, @@ -263,7 +263,7 @@ class SyncTest( assert_raises_message( orm_exc.UnmappedColumnError, "Can't execute sync rule for source column 't2.id'; " - r"mapper 'Mapper\|A\|t1' does not map this column.", + r"mapper 'mapped class A->t1' does not map this column.", sync.source_modified, uowcommit, a1, diff --git a/test/profiles.txt b/test/profiles.txt index 05bc5746ac..d2bcb7c9b9 100644 --- a/test/profiles.txt +++ b/test/profiles.txt @@ -359,127 +359,19 @@ test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove # TEST: test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 2.7_mssql_pyodbc_dbapiunicode_cextensions 104 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 2.7_mssql_pyodbc_dbapiunicode_nocextensions 104 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 2.7_mysql_mysqldb_dbapiunicode_cextensions 104 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 2.7_mysql_mysqldb_dbapiunicode_nocextensions 104 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 2.7_oracle_cx_oracle_dbapiunicode_cextensions 104 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 104 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 2.7_postgresql_psycopg2_dbapiunicode_cextensions 104 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 104 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 2.7_sqlite_pysqlite_dbapiunicode_cextensions 104 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 104 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 3.6_mssql_pyodbc_dbapiunicode_cextensions 81 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 3.6_mssql_pyodbc_dbapiunicode_nocextensions 81 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 3.6_mysql_mysqldb_dbapiunicode_cextensions 81 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 3.6_mysql_mysqldb_dbapiunicode_nocextensions 81 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 3.6_oracle_cx_oracle_dbapiunicode_cextensions 81 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 3.6_oracle_cx_oracle_dbapiunicode_nocextensions 81 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 3.6_postgresql_psycopg2_dbapiunicode_cextensions 81 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 3.6_postgresql_psycopg2_dbapiunicode_nocextensions 81 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 3.6_sqlite_pysqlite_dbapiunicode_cextensions 81 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 3.6_sqlite_pysqlite_dbapiunicode_nocextensions 81 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 3.7_mysql_mysqldb_dbapiunicode_cextensions 81 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 3.7_mysql_mysqldb_dbapiunicode_nocextensions 81 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 3.7_oracle_cx_oracle_dbapiunicode_cextensions 81 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 81 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 3.7_postgresql_psycopg2_dbapiunicode_cextensions 81 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 81 test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 3.7_sqlite_pysqlite_dbapiunicode_cextensions 81 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 81 # TEST: test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 2.7_mssql_pyodbc_dbapiunicode_cextensions 651 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 2.7_mssql_pyodbc_dbapiunicode_nocextensions 651 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 2.7_mysql_mysqldb_dbapiunicode_cextensions 651 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 2.7_mysql_mysqldb_dbapiunicode_nocextensions 651 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 2.7_oracle_cx_oracle_dbapiunicode_cextensions 651 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 651 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 2.7_postgresql_psycopg2_dbapiunicode_cextensions 651 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 651 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 2.7_sqlite_pysqlite_dbapiunicode_cextensions 651 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 651 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 3.6_mssql_pyodbc_dbapiunicode_cextensions 624 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 3.6_mssql_pyodbc_dbapiunicode_nocextensions 624 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 3.6_mysql_mysqldb_dbapiunicode_cextensions 624 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 3.6_mysql_mysqldb_dbapiunicode_nocextensions 624 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 3.6_oracle_cx_oracle_dbapiunicode_cextensions 624 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 3.6_oracle_cx_oracle_dbapiunicode_nocextensions 624 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 3.6_postgresql_psycopg2_dbapiunicode_cextensions 624 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 3.6_postgresql_psycopg2_dbapiunicode_nocextensions 624 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 3.6_sqlite_pysqlite_dbapiunicode_cextensions 624 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 3.6_sqlite_pysqlite_dbapiunicode_nocextensions 624 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 3.7_mysql_mysqldb_dbapiunicode_cextensions 628 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 3.7_mysql_mysqldb_dbapiunicode_nocextensions 628 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 3.7_oracle_cx_oracle_dbapiunicode_cextensions 628 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 628 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 3.7_postgresql_psycopg2_dbapiunicode_cextensions 628 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 628 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 3.7_sqlite_pysqlite_dbapiunicode_cextensions 628 -test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 628 +test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_unbound_branching 3.7_sqlite_pysqlite_dbapiunicode_cextensions 668 # TEST: test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 2.7_mssql_pyodbc_dbapiunicode_cextensions 45 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 2.7_mssql_pyodbc_dbapiunicode_nocextensions 45 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 2.7_mysql_mysqldb_dbapiunicode_cextensions 45 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 2.7_mysql_mysqldb_dbapiunicode_nocextensions 45 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 2.7_oracle_cx_oracle_dbapiunicode_cextensions 45 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 45 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 2.7_postgresql_psycopg2_dbapiunicode_cextensions 45 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 45 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 2.7_sqlite_pysqlite_dbapiunicode_cextensions 45 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 45 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 3.6_mssql_pyodbc_dbapiunicode_cextensions 46 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 3.6_mssql_pyodbc_dbapiunicode_nocextensions 46 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 3.6_mysql_mysqldb_dbapiunicode_cextensions 46 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 3.6_mysql_mysqldb_dbapiunicode_nocextensions 46 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 3.6_oracle_cx_oracle_dbapiunicode_cextensions 46 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 3.6_oracle_cx_oracle_dbapiunicode_nocextensions 46 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 3.6_postgresql_psycopg2_dbapiunicode_cextensions 46 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 3.6_postgresql_psycopg2_dbapiunicode_nocextensions 46 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 3.6_sqlite_pysqlite_dbapiunicode_cextensions 46 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 3.6_sqlite_pysqlite_dbapiunicode_nocextensions 46 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 3.7_mysql_mysqldb_dbapiunicode_cextensions 46 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 3.7_mysql_mysqldb_dbapiunicode_nocextensions 46 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 3.7_oracle_cx_oracle_dbapiunicode_cextensions 46 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 46 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 3.7_postgresql_psycopg2_dbapiunicode_cextensions 46 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 46 test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 3.7_sqlite_pysqlite_dbapiunicode_cextensions 46 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branching 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 46 # TEST: test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 2.7_mssql_pyodbc_dbapiunicode_cextensions 460 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 2.7_mssql_pyodbc_dbapiunicode_nocextensions 460 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 2.7_mysql_mysqldb_dbapiunicode_cextensions 460 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 2.7_mysql_mysqldb_dbapiunicode_nocextensions 460 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 2.7_oracle_cx_oracle_dbapiunicode_cextensions 460 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 460 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 2.7_postgresql_psycopg2_dbapiunicode_cextensions 460 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 460 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 2.7_sqlite_pysqlite_dbapiunicode_cextensions 460 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 460 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.6_mssql_pyodbc_dbapiunicode_cextensions 466 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.6_mssql_pyodbc_dbapiunicode_nocextensions 466 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.6_mysql_mysqldb_dbapiunicode_cextensions 466 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.6_mysql_mysqldb_dbapiunicode_nocextensions 466 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.6_oracle_cx_oracle_dbapiunicode_cextensions 466 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.6_oracle_cx_oracle_dbapiunicode_nocextensions 466 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.6_postgresql_psycopg2_dbapiunicode_cextensions 466 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.6_postgresql_psycopg2_dbapiunicode_nocextensions 466 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.6_sqlite_pysqlite_dbapiunicode_cextensions 466 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.6_sqlite_pysqlite_dbapiunicode_nocextensions 466 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.7_mysql_mysqldb_dbapiunicode_cextensions 470 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.7_mysql_mysqldb_dbapiunicode_nocextensions 470 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.7_oracle_cx_oracle_dbapiunicode_cextensions 470 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 470 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.7_postgresql_psycopg2_dbapiunicode_cextensions 470 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 470 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.7_sqlite_pysqlite_dbapiunicode_cextensions 470 -test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 470 +test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.7_sqlite_pysqlite_dbapiunicode_cextensions 504 # TEST: test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline