summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2020-04-27 12:58:12 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2020-05-25 13:56:37 -0400
commit6930dfc032c3f9f474e71ab4e021c0ef8384930e (patch)
tree34b919a3c34edaffda1750f161a629fc5b9a8020 /test
parentdce8c7a125cb99fad62c76cd145752d5afefae36 (diff)
downloadsqlalchemy-6930dfc032c3f9f474e71ab4e021c0ef8384930e.tar.gz
Convert execution to move through Session
This patch replaces the ORM execution flow with a single pathway through Session.execute() for all queries, including Core and ORM. Currently included is full support for ORM Query, Query.from_statement(), select(), as well as the baked query and horizontal shard systems. Initial changes have also been made to the dogpile caching example, which like baked query makes use of a new ORM-specific execution hook that replaces the use of both QueryEvents.before_compile() as well as Query._execute_and_instances() as the central ORM interception hooks. select() and Query() constructs alike can be passed to Session.execute() where they will return ORM results in a Results object. This API is currently used internally by Query. Full support for Session.execute()->results to behave in a fully 2.0 fashion will be in later changesets. bulk update/delete with ORM support will also be delivered via the update() and delete() constructs, however these have not yet been adapted to the new system and may follow in a subsequent update. Performance is also beginning to lag as of this commit and some previous ones. It is hoped that a few central functions such as the coercions functions can be rewritten in C to re-gain performance. Additionally, query caching is now available and some subsequent patches will attempt to cache more of the per-execution work from the ORM layer, e.g. column getters and adapters. This patch also contains initial "turn on" of the caching system enginewide via the query_cache_size parameter to create_engine(). Still defaulting at zero for "no caching". The caching system still needs adjustments in order to gain adequate performance. Change-Id: I047a7ebb26aa85dc01f6789fac2bff561dcd555d
Diffstat (limited to 'test')
-rw-r--r--test/aaa_profiling/test_memusage.py6
-rw-r--r--test/aaa_profiling/test_orm.py24
-rw-r--r--test/base/test_result.py53
-rw-r--r--test/ext/test_baked.py186
-rw-r--r--test/ext/test_horizontal_shard.py96
-rw-r--r--test/orm/inheritance/test_polymorphic_rel.py106
-rw-r--r--test/orm/test_bind.py257
-rw-r--r--test/orm/test_cache_key.py4
-rw-r--r--test/orm/test_core_compilation.py26
-rw-r--r--test/orm/test_expire.py7
-rw-r--r--test/orm/test_froms.py7
-rw-r--r--test/orm/test_loading.py2
-rw-r--r--test/orm/test_mapper.py2
-rw-r--r--test/orm/test_query.py238
-rw-r--r--test/orm/test_subquery_relations.py18
-rw-r--r--test/orm/test_transaction.py4
-rw-r--r--test/orm/test_versioning.py6
-rw-r--r--test/perf/orm2010.py16
-rw-r--r--test/profiles.txt184
-rw-r--r--test/sql/test_compare.py2
-rw-r--r--test/sql/test_compiler.py28
-rw-r--r--test/sql/test_deprecations.py16
-rw-r--r--test/sql/test_resultset.py29
23 files changed, 1010 insertions, 307 deletions
diff --git a/test/aaa_profiling/test_memusage.py b/test/aaa_profiling/test_memusage.py
index 494e078ab..2d5acca3b 100644
--- a/test/aaa_profiling/test_memusage.py
+++ b/test/aaa_profiling/test_memusage.py
@@ -129,7 +129,9 @@ def profile_memory(
)
raise
+
gc_collect()
+
samples.append(
get_num_objects()
if get_num_objects is not None
@@ -1299,7 +1301,7 @@ class CycleTest(_fixtures.FixtureTest):
# others as of cache key. The options themselves are now part of
# QueryCompileState which is not eagerly disposed yet, so this
# adds some more.
- @assert_cycles(36)
+ @assert_cycles(37)
def go():
generate()
@@ -1370,7 +1372,7 @@ class CycleTest(_fixtures.FixtureTest):
@assert_cycles(4)
def go():
- result = s.execute(stmt)
+ result = s.connection(mapper=User).execute(stmt)
while True:
row = result.fetchone()
if row is None:
diff --git a/test/aaa_profiling/test_orm.py b/test/aaa_profiling/test_orm.py
index ac6e6b55e..7456d5f5b 100644
--- a/test/aaa_profiling/test_orm.py
+++ b/test/aaa_profiling/test_orm.py
@@ -834,7 +834,7 @@ class JoinedEagerLoadTest(fixtures.MappedTest):
def test_fetch_results(self):
A, B, C, D, E, F, G = self.classes("A", "B", "C", "D", "E", "F", "G")
- sess = Session()
+ sess = Session(testing.db)
q = sess.query(A).options(
joinedload(A.bs).joinedload(B.cs).joinedload(C.ds),
@@ -842,16 +842,26 @@ class JoinedEagerLoadTest(fixtures.MappedTest):
defaultload(A.es).joinedload(E.gs),
)
- context = q._compile_context()
- compile_state = context.compile_state
- orig_attributes = dict(compile_state.attributes)
+ compile_state = q._compile_state()
+
+ from sqlalchemy.orm.context import ORMCompileState
@profiling.function_call_count()
def go():
for i in range(100):
- # make sure these get reset each time
- context.attributes = orig_attributes.copy()
- obj = q._execute_and_instances(context)
+ exec_opts = {}
+ bind_arguments = {}
+ ORMCompileState.orm_pre_session_exec(
+ sess, compile_state.query, exec_opts, bind_arguments
+ )
+
+ r = sess.connection().execute(
+ compile_state.statement,
+ execution_options=exec_opts,
+ bind_arguments=bind_arguments,
+ )
+ r.context.compiled.compile_state = compile_state
+ obj = ORMCompileState.orm_setup_cursor_result(sess, {}, r)
list(obj)
sess.close()
diff --git a/test/base/test_result.py b/test/base/test_result.py
index b179c3462..6cffcc323 100644
--- a/test/base/test_result.py
+++ b/test/base/test_result.py
@@ -115,6 +115,19 @@ class ResultTupleTest(fixtures.TestBase):
is_true("a" not in keyed_tuple)
is_true("z" not in keyed_tuple)
+ def test_contains_mapping(self):
+ keyed_tuple = self._fixture(["x", "y"], ["a", "b"])._mapping
+
+ is_false("x" in keyed_tuple)
+ is_false("z" in keyed_tuple)
+
+ is_true("z" not in keyed_tuple)
+ is_true("x" not in keyed_tuple)
+
+ # we do keys
+ is_true("a" in keyed_tuple)
+ is_true("b" in keyed_tuple)
+
def test_none_label(self):
keyed_tuple = self._fixture([1, 2, 3], ["a", None, "b"])
eq_(str(keyed_tuple), "(1, 2, 3)")
@@ -841,15 +854,12 @@ class OnlyScalarsTest(fixtures.TestBase):
def no_tuple_fixture(self):
data = [(1, 1, 1), (2, 1, 2), (1, 1, 1), (1, 3, 2), (4, 1, 2)]
- def chunks(num, as_tuples):
+ def chunks(num):
while data:
rows = data[0:num]
data[:] = []
- if as_tuples:
- assert False
- else:
- yield [row[0] for row in rows]
+ yield [row[0] for row in rows]
return chunks
@@ -857,15 +867,12 @@ class OnlyScalarsTest(fixtures.TestBase):
def normal_fixture(self):
data = [(1, 1, 1), (2, 1, 2), (1, 1, 1), (1, 3, 2), (4, 1, 2)]
- def chunks(num, as_tuples):
+ def chunks(num):
while data:
rows = data[0:num]
data[:] = []
- if as_tuples:
- yield rows
- else:
- yield [row[0] for row in rows]
+ yield [row[0] for row in rows]
return chunks
@@ -891,6 +898,26 @@ class OnlyScalarsTest(fixtures.TestBase):
eq_(r.all(), [1, 2, 4])
+ def test_scalar_mode_scalars_fetchmany(self, normal_fixture):
+ metadata = result.SimpleResultMetaData(["a", "b", "c"])
+
+ r = result.ChunkedIteratorResult(
+ metadata, normal_fixture, source_supports_scalars=True
+ )
+
+ r = r.scalars()
+ eq_(list(r.partitions(2)), [[1, 2], [1, 1], [4]])
+
+ def test_scalar_mode_unique_scalars_fetchmany(self, normal_fixture):
+ metadata = result.SimpleResultMetaData(["a", "b", "c"])
+
+ r = result.ChunkedIteratorResult(
+ metadata, normal_fixture, source_supports_scalars=True
+ )
+
+ r = r.scalars().unique()
+ eq_(list(r.partitions(2)), [[1, 2], [4]])
+
def test_scalar_mode_unique_tuples_all(self, normal_fixture):
metadata = result.SimpleResultMetaData(["a", "b", "c"])
@@ -900,7 +927,7 @@ class OnlyScalarsTest(fixtures.TestBase):
r = r.unique()
- eq_(r.all(), [(1, 1, 1), (2, 1, 2), (1, 3, 2), (4, 1, 2)])
+ eq_(r.all(), [(1,), (2,), (4,)])
def test_scalar_mode_tuples_all(self, normal_fixture):
metadata = result.SimpleResultMetaData(["a", "b", "c"])
@@ -909,7 +936,7 @@ class OnlyScalarsTest(fixtures.TestBase):
metadata, normal_fixture, source_supports_scalars=True
)
- eq_(r.all(), [(1, 1, 1), (2, 1, 2), (1, 1, 1), (1, 3, 2), (4, 1, 2)])
+ eq_(r.all(), [(1,), (2,), (1,), (1,), (4,)])
def test_scalar_mode_scalars_iterate(self, no_tuple_fixture):
metadata = result.SimpleResultMetaData(["a", "b", "c"])
@@ -929,4 +956,4 @@ class OnlyScalarsTest(fixtures.TestBase):
metadata, normal_fixture, source_supports_scalars=True
)
- eq_(list(r), [(1, 1, 1), (2, 1, 2), (1, 1, 1), (1, 3, 2), (4, 1, 2)])
+ eq_(list(r), [(1,), (2,), (1,), (1,), (4,)])
diff --git a/test/ext/test_baked.py b/test/ext/test_baked.py
index 77e57aa36..ecb5e3919 100644
--- a/test/ext/test_baked.py
+++ b/test/ext/test_baked.py
@@ -289,6 +289,7 @@ class LikeQueryTest(BakedTest):
# with multiple params, the **kwargs will be used
bq += lambda q: q.filter(User.id == bindparam("anid"))
eq_(bq(sess).params(uname="fred", anid=9).count(), 1)
+
eq_(
# wrong id, so 0 results:
bq(sess).params(uname="fred", anid=8).count(),
@@ -388,7 +389,12 @@ class ResultPostCriteriaTest(BakedTest):
def before_execute(
conn, clauseelement, multiparams, params, execution_options
):
- assert "yes" in conn._execution_options
+ # execution options are kind of moving around a bit,
+ # test both places
+ assert (
+ "yes" in clauseelement._execution_options
+ or "yes" in execution_options
+ )
bq = self.bakery(lambda s: s.query(User.id).order_by(User.id))
@@ -804,9 +810,7 @@ class ResultTest(BakedTest):
Address = self.classes.Address
Order = self.classes.Order
- # Override the default bakery for one with a smaller size. This used to
- # trigger a bug when unbaking subqueries.
- self.bakery = baked.bakery(size=3)
+ self.bakery = baked.bakery()
base_bq = self.bakery(lambda s: s.query(User))
base_bq += lambda q: q.options(
@@ -840,6 +844,7 @@ class ResultTest(BakedTest):
for cond1, cond2 in itertools.product(
*[(False, True) for j in range(2)]
):
+ print("HI----")
bq = base_bq._clone()
sess = Session()
@@ -903,7 +908,7 @@ class ResultTest(BakedTest):
)
]
- self.bakery = baked.bakery(size=3)
+ self.bakery = baked.bakery()
bq = self.bakery(lambda s: s.query(User))
@@ -1288,33 +1293,72 @@ class LazyLoaderTest(testing.AssertsCompiledSQL, BakedTest):
def _test_baked_lazy_loading_relationship_flag(self, flag):
User, Address = self._o2m_fixture(bake_queries=flag)
+ from sqlalchemy import inspect
- sess = Session()
- u1 = sess.query(User).first()
-
- from sqlalchemy.orm import Query
-
- canary = mock.Mock()
+ address_mapper = inspect(Address)
+ sess = Session(testing.db)
+
+ # there's no event in the compile process either at the ORM
+ # or core level and it is not easy to patch. the option object
+ # is the one thing that will get carried into the lazyload from the
+ # outside and invoked on a per-compile basis
+ mock_opt = mock.Mock(
+ _is_compile_state=True,
+ propagate_to_loaders=True,
+ _gen_cache_key=lambda *args: ("hi",),
+ _generate_path_cache_key=lambda path: ("hi",),
+ )
- # I would think Mock can do this but apparently
- # it cannot (wrap / autospec don't work together)
- real_compile_state = Query._compile_state
+ u1 = sess.query(User).options(mock_opt).first()
- def _my_compile_state(*arg, **kw):
- if arg[0].column_descriptions[0]["entity"] is Address:
- canary()
- return real_compile_state(*arg, **kw)
+ @event.listens_for(sess, "do_orm_execute")
+ def _my_compile_state(context):
+ if (
+ context.statement._raw_columns[0]._annotations["parententity"]
+ is address_mapper
+ ):
+ mock_opt.orm_execute()
- with mock.patch.object(Query, "_compile_state", _my_compile_state):
- u1.addresses
+ u1.addresses
- sess.expire(u1)
- u1.addresses
+ sess.expire(u1)
+ u1.addresses
if flag:
- eq_(canary.call_count, 1)
+ eq_(
+ mock_opt.mock_calls,
+ [
+ mock.call.process_query(mock.ANY),
+ mock.call.process_compile_state(mock.ANY), # query.first()
+ mock.call.process_query_conditionally(mock.ANY),
+ mock.call.orm_execute(), # lazyload addresses
+ mock.call.process_compile_state(mock.ANY), # emit lazyload
+ mock.call.process_compile_state(
+ mock.ANY
+ ), # load scalar attributes for user
+ # lazyload addresses, no call to process_compile_state
+ mock.call.orm_execute(),
+ ],
+ )
else:
- eq_(canary.call_count, 2)
+ eq_(
+ mock_opt.mock_calls,
+ [
+ mock.call.process_query(mock.ANY),
+ mock.call.process_compile_state(mock.ANY), # query.first()
+ mock.call.process_query_conditionally(mock.ANY),
+ mock.call.orm_execute(), # lazyload addresses
+ mock.call.process_compile_state(mock.ANY), # emit_lazyload
+ mock.call.process_compile_state(
+ mock.ANY
+ ), # load_scalar_attributes for user
+ mock.call.process_query_conditionally(mock.ANY),
+ mock.call.orm_execute(), # lazyload addresses
+ mock.call.process_compile_state(
+ mock.ANY
+ ), # emit_lazyload, here the query was not cached
+ ],
+ )
def test_baked_lazy_loading_option_o2m(self):
User, Address = self._o2m_fixture()
@@ -1571,58 +1615,57 @@ class CustomIntegrationTest(testing.AssertsCompiledSQL, BakedTest):
return User, Address
def _query_fixture(self):
- from sqlalchemy.orm.query import Query, _generative
+ from sqlalchemy.orm.query import Query
class CachingQuery(Query):
cache = {}
- @_generative
def set_cache_key(self, key):
- self._cache_key = key
-
- # in 1.4 / If1a23824ffb77d8d58cf2338cf35dd6b5963b17f ,
- # we no longer override ``__iter__`` because we need the
- # whole result object. The FrozenResult is added for this
- # use case. A new session-level event will be added within
- # the scope of ORM /execute() integration so that people
- # don't have to subclass this anymore.
-
- def _execute_and_instances(self, context, **kw):
- super_ = super(CachingQuery, self)
-
- if hasattr(self, "_cache_key"):
- return self.get_value(
- createfunc=lambda: super_._execute_and_instances(
- context, **kw
- )
- )
- else:
- return super_._execute_and_instances(context, **kw)
-
- def get_value(self, createfunc):
- if self._cache_key in self.cache:
- return self.cache[self._cache_key]()
- else:
- self.cache[
- self._cache_key
- ] = retval = createfunc().freeze()
- return retval()
+ return self.execution_options(_cache_key=key)
+
+ def set_cache_key_for_path(self, path, key):
+ return self.execution_options(**{"_cache_key_%s" % path: key})
+
+ def get_value(cache_key, cache, createfunc):
+ if cache_key in cache:
+ return cache[cache_key]()
+ else:
+ cache[cache_key] = retval = createfunc().freeze()
+ return retval()
+
+ s1 = Session(query_cls=CachingQuery)
+
+ @event.listens_for(s1, "do_orm_execute", retval=True)
+ def do_orm_execute(orm_context):
+ ckey = None
+ statement = orm_context.orm_query
+ for opt in orm_context.user_defined_options:
+ ckey = opt.get_cache_key(orm_context)
+ if ckey:
+ break
+ else:
+ if "_cache_key" in statement._execution_options:
+ ckey = statement._execution_options["_cache_key"]
+
+ if ckey is not None:
+ return get_value(
+ ckey, CachingQuery.cache, orm_context.invoke_statement,
+ )
- return Session(query_cls=CachingQuery)
+ return s1
def _option_fixture(self):
- from sqlalchemy.orm.interfaces import MapperOption
+ from sqlalchemy.orm.interfaces import UserDefinedOption
- class RelationshipCache(MapperOption):
+ class RelationshipCache(UserDefinedOption):
propagate_to_loaders = True
- def process_query_conditionally(self, query):
- if query._current_path:
- query._cache_key = "user7_addresses"
-
- def _generate_path_cache_key(self, path):
- return None
+ def get_cache_key(self, orm_context):
+ if orm_context.loader_strategy_path:
+ return "user7_addresses"
+ else:
+ return None
return RelationshipCache()
@@ -1641,6 +1684,21 @@ class CustomIntegrationTest(testing.AssertsCompiledSQL, BakedTest):
eq_(q.all(), [User(id=7, addresses=[Address(id=1)])])
+ def test_non_baked_tuples(self):
+ User, Address = self._o2m_fixture()
+
+ sess = self._query_fixture()
+ q = sess._query_cls
+ eq_(q.cache, {})
+
+ q = sess.query(User).filter(User.id == 7).set_cache_key("user7")
+
+ eq_(sess.execute(q).all(), [(User(id=7, addresses=[Address(id=1)]),)])
+
+ eq_(list(q.cache), ["user7"])
+
+ eq_(sess.execute(q).all(), [(User(id=7, addresses=[Address(id=1)]),)])
+
def test_use_w_baked(self):
User, Address = self._o2m_fixture()
diff --git a/test/ext/test_horizontal_shard.py b/test/ext/test_horizontal_shard.py
index 77b716b0a..eb9c5147a 100644
--- a/test/ext/test_horizontal_shard.py
+++ b/test/ext/test_horizontal_shard.py
@@ -15,6 +15,7 @@ from sqlalchemy import Table
from sqlalchemy import testing
from sqlalchemy import util
from sqlalchemy.ext.horizontal_shard import ShardedSession
+from sqlalchemy.future import select as future_select
from sqlalchemy.orm import clear_mappers
from sqlalchemy.orm import create_session
from sqlalchemy.orm import deferred
@@ -27,11 +28,11 @@ from sqlalchemy.pool import SingletonThreadPool
from sqlalchemy.sql import operators
from sqlalchemy.testing import eq_
from sqlalchemy.testing import fixtures
+from sqlalchemy.testing import is_
from sqlalchemy.testing import provision
from sqlalchemy.testing.engines import testing_engine
from sqlalchemy.testing.engines import testing_reaper
-
# TODO: ShardTest can be turned into a base for further subclasses
@@ -190,11 +191,45 @@ class ShardTest(object):
sess.close()
return sess
- def test_roundtrip(self):
+ def test_get(self):
sess = self._fixture_data()
- tokyo = sess.query(WeatherLocation).filter_by(city="Tokyo").one()
- tokyo.city # reload 'city' attribute on tokyo
- sess.expire_all()
+ tokyo = sess.query(WeatherLocation).get(1)
+ eq_(tokyo.city, "Tokyo")
+
+ newyork = sess.query(WeatherLocation).get(2)
+ eq_(newyork.city, "New York")
+
+ t2 = sess.query(WeatherLocation).get(1)
+ is_(t2, tokyo)
+
+ def test_get_explicit_shard(self):
+ sess = self._fixture_data()
+ tokyo = sess.query(WeatherLocation).set_shard("europe").get(1)
+ is_(tokyo, None)
+
+ newyork = sess.query(WeatherLocation).set_shard("north_america").get(2)
+ eq_(newyork.city, "New York")
+
+ # now it found it
+ t2 = sess.query(WeatherLocation).get(1)
+ eq_(t2.city, "Tokyo")
+
+ def test_query_explicit_shard_via_bind_opts(self):
+ sess = self._fixture_data()
+
+ stmt = future_select(WeatherLocation).filter(WeatherLocation.id == 1)
+
+ tokyo = (
+ sess.execute(stmt, bind_arguments={"shard_id": "asia"})
+ .scalars()
+ .first()
+ )
+
+ eq_(tokyo.city, "Tokyo")
+
+ def test_plain_db_lookup(self):
+ self._fixture_data()
+ # not sure what this is testing except the fixture data itself
eq_(
db2.execute(weather_locations.select()).fetchall(),
[(1, "Asia", "Tokyo")],
@@ -206,12 +241,45 @@ class ShardTest(object):
(3, "North America", "Toronto"),
],
)
+
+ def test_plain_core_lookup_w_shard(self):
+ sess = self._fixture_data()
eq_(
sess.execute(
weather_locations.select(), shard_id="asia"
).fetchall(),
[(1, "Asia", "Tokyo")],
)
+
+ def test_roundtrip_future(self):
+ sess = self._fixture_data()
+
+ tokyo = (
+ sess.execute(
+ future_select(WeatherLocation).filter_by(city="Tokyo")
+ )
+ .scalars()
+ .one()
+ )
+ eq_(tokyo.city, "Tokyo")
+
+ asia_and_europe = sess.execute(
+ future_select(WeatherLocation).filter(
+ WeatherLocation.continent.in_(["Europe", "Asia"])
+ )
+ ).scalars()
+ eq_(
+ {c.city for c in asia_and_europe}, {"Tokyo", "London", "Dublin"},
+ )
+
+ def test_roundtrip(self):
+ sess = self._fixture_data()
+ tokyo = sess.query(WeatherLocation).filter_by(city="Tokyo").one()
+
+ eq_(tokyo.city, "Tokyo")
+ tokyo.city # reload 'city' attribute on tokyo
+ sess.expire_all()
+
t = sess.query(WeatherLocation).get(tokyo.id)
eq_(t.city, tokyo.city)
eq_(t.reports[0].temperature, 80.0)
@@ -219,26 +287,23 @@ class ShardTest(object):
WeatherLocation.continent == "North America"
)
eq_(
- set([c.city for c in north_american_cities]),
- set(["New York", "Toronto"]),
+ {c.city for c in north_american_cities}, {"New York", "Toronto"},
)
asia_and_europe = sess.query(WeatherLocation).filter(
WeatherLocation.continent.in_(["Europe", "Asia"])
)
eq_(
- set([c.city for c in asia_and_europe]),
- set(["Tokyo", "London", "Dublin"]),
+ {c.city for c in asia_and_europe}, {"Tokyo", "London", "Dublin"},
)
# inspect the shard token stored with each instance
eq_(
- set(inspect(c).key[2] for c in asia_and_europe),
- set(["europe", "asia"]),
+ {inspect(c).key[2] for c in asia_and_europe}, {"europe", "asia"},
)
eq_(
- set(inspect(c).identity_token for c in asia_and_europe),
- set(["europe", "asia"]),
+ {inspect(c).identity_token for c in asia_and_europe},
+ {"europe", "asia"},
)
newyork = sess.query(WeatherLocation).filter_by(city="New York").one()
@@ -324,7 +389,7 @@ class ShardTest(object):
canary = []
def load(instance, ctx):
- canary.append(ctx.attributes["shard_id"])
+ canary.append(ctx.bind_arguments["shard_id"])
event.listen(WeatherLocation, "load", load)
sess = self._fixture_data()
@@ -571,6 +636,9 @@ class RefreshDeferExpireTest(fixtures.DeclarativeMappedTest):
s.commit()
def _session_fixture(self, **kw):
+ # the "fake" key here is to ensure that neither id_chooser
+ # nor query_chooser are actually used, only shard_chooser
+ # should be used.
return ShardedSession(
shards={"main": testing.db},
diff --git a/test/orm/inheritance/test_polymorphic_rel.py b/test/orm/inheritance/test_polymorphic_rel.py
index 9ee5ce2ab..549414507 100644
--- a/test/orm/inheritance/test_polymorphic_rel.py
+++ b/test/orm/inheritance/test_polymorphic_rel.py
@@ -4,6 +4,7 @@ from sqlalchemy import func
from sqlalchemy import select
from sqlalchemy import testing
from sqlalchemy import true
+from sqlalchemy.future import select as future_select
from sqlalchemy.orm import aliased
from sqlalchemy.orm import create_session
from sqlalchemy.orm import defaultload
@@ -209,10 +210,66 @@ class _PolymorphicTestBase(object):
],
)
+ def test_multi_join_future(self):
+ sess = create_session()
+ e = aliased(Person)
+ c = aliased(Company)
+
+ q = (
+ future_select(Company, Person, c, e)
+ .join(Person, Company.employees)
+ .join(e, c.employees)
+ .filter(Person.person_id != e.person_id)
+ .filter(Person.name == "dilbert")
+ .filter(e.name == "wally")
+ )
+
+ eq_(
+ sess.execute(
+ future_select(func.count()).select_from(q.subquery())
+ ).scalar(),
+ 1,
+ )
+
+ eq_(
+ sess.execute(q).all(),
+ [
+ (
+ Company(company_id=1, name="MegaCorp, Inc."),
+ Engineer(
+ status="regular engineer",
+ engineer_name="dilbert",
+ name="dilbert",
+ company_id=1,
+ primary_language="java",
+ person_id=1,
+ type="engineer",
+ ),
+ Company(company_id=1, name="MegaCorp, Inc."),
+ Engineer(
+ status="regular engineer",
+ engineer_name="wally",
+ name="wally",
+ company_id=1,
+ primary_language="c++",
+ person_id=2,
+ type="engineer",
+ ),
+ )
+ ],
+ )
+
def test_filter_on_subclass_one(self):
sess = create_session()
eq_(sess.query(Engineer).all()[0], Engineer(name="dilbert"))
+ def test_filter_on_subclass_one_future(self):
+ sess = create_session()
+ eq_(
+ sess.execute(future_select(Engineer)).scalar(),
+ Engineer(name="dilbert"),
+ )
+
def test_filter_on_subclass_two(self):
sess = create_session()
eq_(sess.query(Engineer).first(), Engineer(name="dilbert"))
@@ -261,6 +318,20 @@ class _PolymorphicTestBase(object):
[b1, m1],
)
+ def test_join_from_polymorphic_nonaliased_one_future(self):
+ sess = create_session()
+ eq_(
+ sess.execute(
+ future_select(Person)
+ .join(Person.paperwork)
+ .filter(Paperwork.description.like("%review%"))
+ )
+ .unique()
+ .scalars()
+ .all(),
+ [b1, m1],
+ )
+
def test_join_from_polymorphic_nonaliased_two(self):
sess = create_session()
eq_(
@@ -306,6 +377,23 @@ class _PolymorphicTestBase(object):
[b1, m1],
)
+ def test_join_from_polymorphic_flag_aliased_one_future(self):
+ sess = create_session()
+
+ pa = aliased(Paperwork)
+ eq_(
+ sess.execute(
+ future_select(Person)
+ .order_by(Person.person_id)
+ .join(Person.paperwork.of_type(pa))
+ .filter(pa.description.like("%review%"))
+ )
+ .unique()
+ .scalars()
+ .all(),
+ [b1, m1],
+ )
+
def test_join_from_polymorphic_explicit_aliased_one(self):
sess = create_session()
pa = aliased(Paperwork)
@@ -389,6 +477,23 @@ class _PolymorphicTestBase(object):
[b1, m1],
)
+ def test_join_from_with_polymorphic_nonaliased_one_future(self):
+ sess = create_session()
+
+ pm = with_polymorphic(Person, [Manager])
+ eq_(
+ sess.execute(
+ future_select(pm)
+ .order_by(pm.person_id)
+ .join(pm.paperwork)
+ .filter(Paperwork.description.like("%review%"))
+ )
+ .unique()
+ .scalars()
+ .all(),
+ [b1, m1],
+ )
+
def test_join_from_with_polymorphic_nonaliased_two(self):
sess = create_session()
eq_(
@@ -1429,6 +1534,7 @@ class _PolymorphicTestBase(object):
.filter(Engineer.primary_language == "java")
.statement.scalar_subquery()
)
+
eq_(sess.query(Person).filter(Person.person_id.in_(subq)).one(), e1)
def test_mixed_entities_one(self):
diff --git a/test/orm/test_bind.py b/test/orm/test_bind.py
index 63588d73e..8e6d73ca4 100644
--- a/test/orm/test_bind.py
+++ b/test/orm/test_bind.py
@@ -1,19 +1,26 @@
import sqlalchemy as sa
from sqlalchemy import ForeignKey
+from sqlalchemy import inspect
from sqlalchemy import Integer
from sqlalchemy import MetaData
+from sqlalchemy import select
+from sqlalchemy import table
from sqlalchemy import testing
+from sqlalchemy import true
+from sqlalchemy.future import select as future_select
from sqlalchemy.orm import backref
from sqlalchemy.orm import create_session
from sqlalchemy.orm import mapper
from sqlalchemy.orm import relationship
from sqlalchemy.orm import Session
from sqlalchemy.orm import sessionmaker
+from sqlalchemy.orm.query import Query
from sqlalchemy.testing import assert_raises_message
from sqlalchemy.testing import engines
from sqlalchemy.testing import eq_
from sqlalchemy.testing import fixtures
from sqlalchemy.testing import is_
+from sqlalchemy.testing import mock
from sqlalchemy.testing.mock import Mock
from sqlalchemy.testing.schema import Column
from sqlalchemy.testing.schema import Table
@@ -155,7 +162,92 @@ class BindIntegrationTest(_fixtures.FixtureTest):
assert len(session.query(User).filter_by(name="Johnny").all()) == 0
session.close()
- def test_bind_arguments(self):
+ @testing.combinations(
+ (lambda: {}, "e3"),
+ (lambda e1: {"bind": e1}, "e1"),
+ (lambda e1, Address: {"bind": e1, "mapper": Address}, "e1"),
+ (
+ lambda e1, Address: {
+ "bind": e1,
+ "clause": Query([Address])._statement_20(),
+ },
+ "e1",
+ ),
+ (lambda Address: {"mapper": Address}, "e2"),
+ (lambda Address: {"clause": Query([Address])._statement_20()}, "e2"),
+ (lambda addresses: {"clause": select([addresses])}, "e2"),
+ (
+ lambda User, addresses: {
+ "mapper": User,
+ "clause": select([addresses]),
+ },
+ "e1",
+ ),
+ (
+ lambda e2, User, addresses: {
+ "mapper": User,
+ "clause": select([addresses]),
+ "bind": e2,
+ },
+ "e2",
+ ),
+ (
+ lambda User, Address: {
+ "clause": future_select(1).join_from(User, Address)
+ },
+ "e1",
+ ),
+ (
+ lambda User, Address: {
+ "clause": future_select(1).join_from(Address, User)
+ },
+ "e2",
+ ),
+ (
+ lambda User: {
+ "clause": future_select(1).where(User.name == "ed"),
+ },
+ "e1",
+ ),
+ (lambda: {"clause": future_select(1)}, "e3"),
+ (lambda User: {"clause": Query([User])._statement_20()}, "e1"),
+ (lambda: {"clause": Query([1])._statement_20()}, "e3"),
+ (
+ lambda User: {
+ "clause": Query([1]).select_from(User)._statement_20()
+ },
+ "e1",
+ ),
+ (
+ lambda User: {
+ "clause": Query([1])
+ .select_from(User)
+ .join(User.addresses)
+ ._statement_20()
+ },
+ "e1",
+ ),
+ (
+ # forcing the "onclause" argument to be considered
+ # in visitors.iterate()
+ lambda User: {
+ "clause": Query([1])
+ .select_from(User)
+ .join(table("foo"), User.addresses)
+ ._statement_20()
+ },
+ "e1",
+ ),
+ (
+ lambda User: {
+ "clause": future_select(1)
+ .select_from(User)
+ .join(User.addresses)
+ },
+ "e1",
+ ),
+ )
+ def test_get_bind(self, testcase, expected):
users, Address, addresses, User = (
self.tables.users,
self.classes.Address,
@@ -163,33 +255,130 @@ class BindIntegrationTest(_fixtures.FixtureTest):
self.classes.User,
)
- mapper(User, users)
+ mapper(User, users, properties={"addresses": relationship(Address)})
mapper(Address, addresses)
e1 = engines.testing_engine()
e2 = engines.testing_engine()
e3 = engines.testing_engine()
+ testcase = testing.resolve_lambda(
+ testcase,
+ User=User,
+ Address=Address,
+ e1=e1,
+ e2=e2,
+ e3=e3,
+ addresses=addresses,
+ )
+
sess = Session(e3)
sess.bind_mapper(User, e1)
sess.bind_mapper(Address, e2)
- assert sess.connection().engine is e3
- assert sess.connection(bind=e1).engine is e1
- assert sess.connection(mapper=Address, bind=e1).engine is e1
- assert sess.connection(mapper=Address).engine is e2
- assert sess.connection(clause=addresses.select()).engine is e2
- assert (
- sess.connection(mapper=User, clause=addresses.select()).engine
- is e1
+ engine = {"e1": e1, "e2": e2, "e3": e3}[expected]
+ conn = sess.connection(**testcase)
+ is_(conn.engine, engine)
+
+ sess.close()
+
+ @testing.combinations(
+ (
+ lambda session, Address: session.query(Address),
+ lambda Address: {"mapper": inspect(Address), "clause": mock.ANY},
+ "e2",
+ ),
+ (lambda: future_select(1), lambda: {"clause": mock.ANY}, "e3"),
+ (
+ lambda User, Address: future_select(1).join_from(User, Address),
+ lambda User: {"clause": mock.ANY, "mapper": inspect(User)},
+ "e1",
+ ),
+ (
+ lambda User, Address: future_select(1).join_from(Address, User),
+ lambda Address: {"clause": mock.ANY, "mapper": inspect(Address)},
+ "e2",
+ ),
+ (
+ lambda User: future_select(1).where(User.name == "ed"),
+ # no mapper for this one becuase the plugin is not "orm"
+ lambda User: {"clause": mock.ANY},
+ "e1",
+ ),
+ (
+ lambda User: future_select(1)
+ .select_from(User)
+ .where(User.name == "ed"),
+ lambda User: {"clause": mock.ANY, "mapper": inspect(User)},
+ "e1",
+ ),
+ (
+ lambda User: future_select(User.id),
+ lambda User: {"clause": mock.ANY, "mapper": inspect(User)},
+ "e1",
+ ),
+ )
+ def test_bind_through_execute(
+ self, statement, expected_get_bind_args, expected_engine_name
+ ):
+ users, Address, addresses, User = (
+ self.tables.users,
+ self.classes.Address,
+ self.tables.addresses,
+ self.classes.User,
)
- assert (
- sess.connection(
- mapper=User, clause=addresses.select(), bind=e2
- ).engine
- is e2
+
+ mapper(User, users, properties={"addresses": relationship(Address)})
+ mapper(Address, addresses)
+
+ e1 = engines.testing_engine()
+ e2 = engines.testing_engine()
+ e3 = engines.testing_engine()
+
+ canary = mock.Mock()
+
+ class GetBindSession(Session):
+ def _connection_for_bind(self, bind, **kw):
+ canary._connection_for_bind(bind, **kw)
+ return mock.Mock()
+
+ def get_bind(self, **kw):
+ canary.get_bind(**kw)
+ return Session.get_bind(self, **kw)
+
+ sess = GetBindSession(e3)
+ sess.bind_mapper(User, e1)
+ sess.bind_mapper(Address, e2)
+
+ lambda_args = dict(
+ session=sess,
+ User=User,
+ Address=Address,
+ e1=e1,
+ e2=e2,
+ e3=e3,
+ addresses=addresses,
+ )
+ statement = testing.resolve_lambda(statement, **lambda_args)
+
+ expected_get_bind_args = testing.resolve_lambda(
+ expected_get_bind_args, **lambda_args
)
+ engine = {"e1": e1, "e2": e2, "e3": e3}[expected_engine_name]
+
+ with mock.patch(
+ "sqlalchemy.orm.context.ORMCompileState.orm_setup_cursor_result"
+ ):
+ sess.execute(statement)
+
+ eq_(
+ canary.mock_calls,
+ [
+ mock.call.get_bind(**expected_get_bind_args),
+ mock.call._connection_for_bind(engine, close_with_result=True),
+ ],
+ )
sess.close()
def test_bind_arg(self):
@@ -495,3 +684,41 @@ class GetBindTest(fixtures.MappedTest):
is_(session.get_bind(self.classes.BaseClass), base_class_bind)
is_(session.get_bind(self.classes.ConcreteSubClass), concrete_sub_bind)
+
+ @testing.fixture
+ def two_table_fixture(self):
+ base_class_bind = Mock(name="base")
+ concrete_sub_bind = Mock(name="concrete")
+
+ session = self._fixture(
+ {
+ self.tables.base_table: base_class_bind,
+ self.tables.concrete_sub_table: concrete_sub_bind,
+ }
+ )
+ return session, base_class_bind, concrete_sub_bind
+
+ def test_bind_selectable_table(self, two_table_fixture):
+ session, base_class_bind, concrete_sub_bind = two_table_fixture
+
+ is_(session.get_bind(clause=self.tables.base_table), base_class_bind)
+ is_(
+ session.get_bind(clause=self.tables.concrete_sub_table),
+ concrete_sub_bind,
+ )
+
+ def test_bind_selectable_join(self, two_table_fixture):
+ session, base_class_bind, concrete_sub_bind = two_table_fixture
+
+ stmt = self.tables.base_table.join(
+ self.tables.concrete_sub_table, true()
+ )
+ is_(session.get_bind(clause=stmt), base_class_bind)
+
+ def test_bind_selectable_union(self, two_table_fixture):
+ session, base_class_bind, concrete_sub_bind = two_table_fixture
+
+ stmt = select([self.tables.base_table]).union(
+ select([self.tables.concrete_sub_table])
+ )
+ is_(session.get_bind(clause=stmt), base_class_bind)
diff --git a/test/orm/test_cache_key.py b/test/orm/test_cache_key.py
index 53cb45171..b431ea6b2 100644
--- a/test/orm/test_cache_key.py
+++ b/test/orm/test_cache_key.py
@@ -69,6 +69,7 @@ class CacheKeyTest(CacheKeyFixture, _fixtures.FixtureTest):
joinedload(User.orders).selectinload(Order.items),
defer(User.id),
defer("id"),
+ defer("*"),
defer(Address.id),
joinedload(User.addresses).defer(Address.id),
joinedload(aliased(User).addresses).defer(Address.id),
@@ -100,6 +101,7 @@ class CacheKeyTest(CacheKeyFixture, _fixtures.FixtureTest):
Load(User).defer(User.id),
Load(User).subqueryload("addresses"),
Load(Address).defer("id"),
+ Load(Address).defer("*"),
Load(aliased(Address)).defer("id"),
Load(User).joinedload(User.addresses).defer(Address.id),
Load(User).joinedload(User.orders).joinedload(Order.items),
@@ -111,6 +113,8 @@ class CacheKeyTest(CacheKeyFixture, _fixtures.FixtureTest):
.defer(Item.description),
Load(User).defaultload(User.orders).defaultload(Order.items),
Load(User).defaultload(User.orders),
+ Load(Address).raiseload("*"),
+ Load(Address).raiseload("user"),
),
compare_values=True,
)
diff --git a/test/orm/test_core_compilation.py b/test/orm/test_core_compilation.py
index 86edf53af..61df1d277 100644
--- a/test/orm/test_core_compilation.py
+++ b/test/orm/test_core_compilation.py
@@ -79,7 +79,8 @@ class JoinTest(QueryTest, AssertsCompiledSQL):
stmt = select(User).join(Address, User.orders)
assert_raises_message(
exc.InvalidRequestError,
- "Selectable 'addresses' is not derived from 'orders'",
+ "Join target .*Address.* does not correspond to the right side "
+ "of join condition User.orders",
stmt.compile,
)
@@ -371,10 +372,7 @@ class ImplicitWithPolymorphicTest(
.order_by(Engineer.person_id)
)
- # the ORM has a different column selection than what a purely core
- # select does, in terms of engineers.person_id vs. people.person_id
-
- expected = (
+ plain_expected = ( # noqa
"SELECT engineers.person_id, people.person_id, people.company_id, "
"people.name, "
"people.type, engineers.status, "
@@ -383,9 +381,23 @@ class ImplicitWithPolymorphicTest(
"ON people.person_id = engineers.person_id "
"WHERE people.name = :name_1 ORDER BY engineers.person_id"
)
+ # when we have disambiguating labels turned on
+ disambiguate_expected = ( # noqa
+ "SELECT engineers.person_id, people.person_id AS person_id_1, "
+ "people.company_id, "
+ "people.name, "
+ "people.type, engineers.status, "
+ "engineers.engineer_name, engineers.primary_language "
+ "FROM people JOIN engineers "
+ "ON people.person_id = engineers.person_id "
+ "WHERE people.name = :name_1 ORDER BY engineers.person_id"
+ )
- self.assert_compile(stmt, expected)
- self.assert_compile(q.statement, expected)
+ # these change based on how we decide to apply labels
+ # in context.py
+ self.assert_compile(stmt, disambiguate_expected)
+
+ self.assert_compile(q.statement, disambiguate_expected)
def test_select_where_columns_subclass(self):
diff --git a/test/orm/test_expire.py b/test/orm/test_expire.py
index f38f917da..ae3e18b09 100644
--- a/test/orm/test_expire.py
+++ b/test/orm/test_expire.py
@@ -319,13 +319,6 @@ class ExpireTest(_fixtures.FixtureTest):
["addresses"],
)
- # in contrast to a regular query with no columns
- assert_raises_message(
- sa_exc.InvalidRequestError,
- "no columns with which to SELECT",
- s.query().all,
- )
-
def test_refresh_cancels_expire(self):
users, User = self.tables.users, self.classes.User
diff --git a/test/orm/test_froms.py b/test/orm/test_froms.py
index 4b20dfca6..ce687fdee 100644
--- a/test/orm/test_froms.py
+++ b/test/orm/test_froms.py
@@ -3389,7 +3389,7 @@ class ExternalColumnsTest(QueryTest):
},
)
- mapper(Address, addresses, properties={"user": relationship(User)})
+ mapper(Address, addresses, properties={"user": relationship(User,)})
sess = create_session()
@@ -3412,6 +3412,11 @@ class ExternalColumnsTest(QueryTest):
Address(id=4, user=User(id=8, concat=16, count=3)),
Address(id=5, user=User(id=9, concat=18, count=1)),
]
+ # TODO: ISSUE: BUG: cached metadata is confusing the user.id
+ # column here with the anon_1 for some reason, when we
+ # use compiled cache. this bug may even be present in
+ # regular master / 1.3. right now the caching of result
+ # metadata is disabled.
eq_(sess.query(Address).all(), address_result)
# run the eager version twice to test caching of aliased clauses
diff --git a/test/orm/test_loading.py b/test/orm/test_loading.py
index 968c8229b..096717165 100644
--- a/test/orm/test_loading.py
+++ b/test/orm/test_loading.py
@@ -78,7 +78,7 @@ class InstancesTest(_fixtures.FixtureTest):
ctx.compile_state._entities = [
mock.Mock(row_processor=mock.Mock(side_effect=Exception("boom")))
]
- assert_raises(Exception, loading.instances, q, cursor, ctx)
+ assert_raises(Exception, loading.instances, cursor, ctx)
assert cursor.close.called, "Cursor wasn't closed"
def test_row_proc_not_created(self):
diff --git a/test/orm/test_mapper.py b/test/orm/test_mapper.py
index a090d0044..ab52e5aac 100644
--- a/test/orm/test_mapper.py
+++ b/test/orm/test_mapper.py
@@ -256,7 +256,7 @@ class MapperTest(_fixtures.FixtureTest, AssertsCompiledSQL):
m = mapper(User, users)
session = create_session()
- session.connection(m)
+ session.connection(mapper=m)
def test_incomplete_columns(self):
"""Loading from a select which does not contain all columns"""
diff --git a/test/orm/test_query.py b/test/orm/test_query.py
index 030e6c870..76706b37b 100644
--- a/test/orm/test_query.py
+++ b/test/orm/test_query.py
@@ -6,6 +6,7 @@ from sqlalchemy import and_
from sqlalchemy import between
from sqlalchemy import bindparam
from sqlalchemy import Boolean
+from sqlalchemy import case
from sqlalchemy import cast
from sqlalchemy import collate
from sqlalchemy import column
@@ -29,11 +30,13 @@ from sqlalchemy import table
from sqlalchemy import testing
from sqlalchemy import text
from sqlalchemy import true
+from sqlalchemy import type_coerce
from sqlalchemy import Unicode
from sqlalchemy import union
from sqlalchemy import util
from sqlalchemy.engine import default
from sqlalchemy.ext.compiler import compiles
+from sqlalchemy.future import select as future_select
from sqlalchemy.orm import aliased
from sqlalchemy.orm import attributes
from sqlalchemy.orm import backref
@@ -47,6 +50,7 @@ from sqlalchemy.orm import lazyload
from sqlalchemy.orm import mapper
from sqlalchemy.orm import Query
from sqlalchemy.orm import relationship
+from sqlalchemy.orm import selectinload
from sqlalchemy.orm import Session
from sqlalchemy.orm import subqueryload
from sqlalchemy.orm import synonym
@@ -59,7 +63,6 @@ from sqlalchemy.testing import AssertsCompiledSQL
from sqlalchemy.testing import fixtures
from sqlalchemy.testing import is_
from sqlalchemy.testing import is_false
-from sqlalchemy.testing import is_not_
from sqlalchemy.testing import is_true
from sqlalchemy.testing import mock
from sqlalchemy.testing.assertions import assert_raises
@@ -149,6 +152,67 @@ class RowTupleTest(QueryTest):
eq_(row.id, 7)
eq_(row.uname, "jack")
+ @testing.combinations(
+ (lambda s, users: s.query(users),),
+ (lambda s, User: s.query(User.id, User.name),),
+ (lambda s, users: s.query(users.c.id, users.c.name),),
+ (lambda s, users: s.query(users.c.id, users.c.name),),
+ )
+ def test_modern_tuple(self, test_case):
+ # check we are not getting a LegacyRow back
+
+ User, users = self.classes.User, self.tables.users
+
+ mapper(User, users)
+
+ s = Session()
+
+ q = testing.resolve_lambda(test_case, **locals())
+
+ row = q.order_by(User.id).first()
+ assert "jack" in row
+
+ @testing.combinations(
+ (lambda s, users: s.query(users),),
+ (lambda s, User: s.query(User.id, User.name),),
+ (lambda s, users: s.query(users.c.id, users.c.name),),
+ (lambda s, users: future_select(users),),
+ (lambda s, User: future_select(User.id, User.name),),
+ (lambda s, users: future_select(users.c.id, users.c.name),),
+ )
+ def test_modern_tuple_future(self, test_case):
+ # check we are not getting a LegacyRow back
+
+ User, users = self.classes.User, self.tables.users
+
+ mapper(User, users)
+
+ s = Session()
+
+ q = testing.resolve_lambda(test_case, **locals())
+
+ row = s.execute(q.order_by(User.id)).first()
+ assert "jack" in row
+
+ @testing.combinations(
+ (lambda s, users: select([users]),),
+ (lambda s, User: select([User.id, User.name]),),
+ (lambda s, users: select([users.c.id, users.c.name]),),
+ )
+ def test_legacy_tuple_old_select(self, test_case):
+
+ User, users = self.classes.User, self.tables.users
+
+ mapper(User, users)
+
+ s = Session()
+
+ q = testing.resolve_lambda(test_case, **locals())
+
+ row = s.execute(q.order_by(User.id)).first()
+ assert "jack" not in row
+ assert "jack" in tuple(row)
+
def test_entity_mapping_access(self):
User, users = self.classes.User, self.tables.users
Address, addresses = self.classes.Address, self.tables.addresses
@@ -188,34 +252,6 @@ class RowTupleTest(QueryTest):
assert_raises(KeyError, lambda: row._mapping[User.name])
assert_raises(KeyError, lambda: row._mapping[users.c.name])
- def test_deep_entity(self):
- users, User = (self.tables.users, self.classes.User)
-
- mapper(User, users)
-
- sess = create_session()
- bundle = Bundle("b1", User.id, User.name)
- subq1 = sess.query(User.id).subquery()
- subq2 = sess.query(bundle).subquery()
- cte = sess.query(User.id).cte()
- ex = sess.query(User).exists()
-
- is_(
- sess.query(subq1)._compile_state()._deep_entity_zero(),
- inspect(User),
- )
- is_(
- sess.query(subq2)._compile_state()._deep_entity_zero(),
- inspect(User),
- )
- is_(
- sess.query(cte)._compile_state()._deep_entity_zero(),
- inspect(User),
- )
- is_(
- sess.query(ex)._compile_state()._deep_entity_zero(), inspect(User),
- )
-
@testing.combinations(
lambda sess, User: (
sess.query(User),
@@ -4502,22 +4538,65 @@ class TextTest(QueryTest, AssertsCompiledSQL):
self.assert_sql_count(testing.db, go, 1)
- def test_other_eager_loads(self):
- # this is new in 1.4. with textclause, we build up column loaders
- # normally, so that eager loaders also get installed. previously,
- # _compile_context() didn't build up column loaders and attempted
- # to get them after the fact.
+ def test_columns_multi_table_uselabels_cols_contains_eager(self):
+ # test that columns using column._label match, as well as that
+ # ordering doesn't matter.
User = self.classes.User
+ Address = self.classes.Address
s = create_session()
q = (
s.query(User)
- .from_statement(text("select * from users"))
- .options(subqueryload(User.addresses))
+ .from_statement(
+ text(
+ "select users.name AS users_name, users.id AS users_id, "
+ "addresses.id AS addresses_id FROM users JOIN addresses "
+ "ON users.id = addresses.user_id WHERE users.id=8 "
+ "ORDER BY addresses.id"
+ ).columns(User.name, User.id, Address.id)
+ )
+ .options(contains_eager(User.addresses))
+ )
+
+ def go():
+ r = q.all()
+ eq_(r[0].addresses, [Address(id=2), Address(id=3), Address(id=4)])
+
+ self.assert_sql_count(testing.db, go, 1)
+
+ @testing.combinations(
+ (
+ False,
+ subqueryload,
+ # sqlite seems happy to interpret the broken SQL and give you the
+ # correct result somehow, this is a bug in SQLite so don't rely
+ # upon it doing that
+ testing.fails("not working yet") + testing.skip_if("sqlite"),
+ ),
+ (True, subqueryload, testing.fails("not sure about implementation")),
+ (False, selectinload),
+ (True, selectinload),
+ )
+ def test_related_eagerload_against_text(self, add_columns, loader_option):
+ # new in 1.4. textual selects have columns so subqueryloaders
+ # and selectinloaders can join onto them. we add columns
+ # automatiacally to TextClause as well, however subqueryloader
+ # is not working at the moment due to execution model refactor,
+ # it creates a subquery w/ adapter before those columns are
+ # available. this is a super edge case and as we want to rewrite
+ # the loaders to use select(), maybe we can get it then.
+ User = self.classes.User
+
+ text_clause = text("select * from users")
+ if add_columns:
+ text_clause = text_clause.columns(User.id, User.name)
+
+ s = create_session()
+ q = (
+ s.query(User)
+ .from_statement(text_clause)
+ .options(loader_option(User.addresses))
)
- # we can't ORDER BY in this test because SQL server won't let the
- # ORDER BY work inside the subqueryload; the test needs to use
- # subqueryload (not selectinload) to confirm the feature
def go():
eq_(set(q.all()), set(self.static.user_address_result))
@@ -5897,41 +5976,52 @@ class SessionBindTest(QueryTest):
yield
for call_ in get_bind.mock_calls:
if expect_mapped_bind:
- is_(call_[1][0], inspect(self.classes.User))
+ eq_(
+ call_,
+ mock.call(
+ clause=mock.ANY, mapper=inspect(self.classes.User)
+ ),
+ )
else:
- is_(call_[1][0], None)
- is_not_(call_[2]["clause"], None)
+ eq_(call_, mock.call(clause=mock.ANY))
def test_single_entity_q(self):
User = self.classes.User
session = Session()
- with self._assert_bind_args(session):
+ with self._assert_bind_args(session, expect_mapped_bind=True):
session.query(User).all()
def test_aliased_entity_q(self):
User = self.classes.User
u = aliased(User)
session = Session()
- with self._assert_bind_args(session):
+ with self._assert_bind_args(session, expect_mapped_bind=True):
session.query(u).all()
def test_sql_expr_entity_q(self):
User = self.classes.User
session = Session()
- with self._assert_bind_args(session):
+ with self._assert_bind_args(session, expect_mapped_bind=True):
session.query(User.id).all()
def test_sql_expr_subquery_from_entity(self):
User = self.classes.User
session = Session()
- with self._assert_bind_args(session):
+ with self._assert_bind_args(session, expect_mapped_bind=True):
subq = session.query(User.id).subquery()
session.query(subq).all()
+ def test_sql_expr_exists_from_entity(self):
+ User = self.classes.User
+ session = Session()
+ with self._assert_bind_args(session, expect_mapped_bind=True):
+ subq = session.query(User.id).exists()
+ session.query(subq).all()
+
def test_sql_expr_cte_from_entity(self):
User = self.classes.User
session = Session()
- with self._assert_bind_args(session):
+ with self._assert_bind_args(session, expect_mapped_bind=True):
cte = session.query(User.id).cte()
subq = session.query(cte).subquery()
session.query(subq).all()
@@ -5939,7 +6029,7 @@ class SessionBindTest(QueryTest):
def test_sql_expr_bundle_cte_from_entity(self):
User = self.classes.User
session = Session()
- with self._assert_bind_args(session):
+ with self._assert_bind_args(session, expect_mapped_bind=True):
cte = session.query(User.id, User.name).cte()
subq = session.query(cte).subquery()
bundle = Bundle(subq.c.id, subq.c.name)
@@ -5948,15 +6038,58 @@ class SessionBindTest(QueryTest):
def test_count(self):
User = self.classes.User
session = Session()
- with self._assert_bind_args(session):
+ with self._assert_bind_args(session, expect_mapped_bind=True):
session.query(User).count()
+ def test_single_col(self):
+ User = self.classes.User
+ session = Session()
+ with self._assert_bind_args(session, expect_mapped_bind=True):
+ session.query(User.name).all()
+
+ def test_single_col_from_subq(self):
+ User = self.classes.User
+ session = Session()
+ with self._assert_bind_args(session, expect_mapped_bind=True):
+ subq = session.query(User.id, User.name).subquery()
+ session.query(subq.c.name).all()
+
def test_aggregate_fn(self):
User = self.classes.User
session = Session()
- with self._assert_bind_args(session):
+ with self._assert_bind_args(session, expect_mapped_bind=True):
session.query(func.max(User.name)).all()
+ def test_case(self):
+ User = self.classes.User
+ session = Session()
+ with self._assert_bind_args(session, expect_mapped_bind=True):
+ session.query(case([(User.name == "x", "C")], else_="W")).all()
+
+ def test_cast(self):
+ User = self.classes.User
+ session = Session()
+ with self._assert_bind_args(session, expect_mapped_bind=True):
+ session.query(cast(User.name, String())).all()
+
+ def test_type_coerce(self):
+ User = self.classes.User
+ session = Session()
+ with self._assert_bind_args(session, expect_mapped_bind=True):
+ session.query(type_coerce(User.name, String())).all()
+
+ def test_binary_op(self):
+ User = self.classes.User
+ session = Session()
+ with self._assert_bind_args(session, expect_mapped_bind=True):
+ session.query(User.name + "x").all()
+
+ def test_boolean_op(self):
+ User = self.classes.User
+ session = Session()
+ with self._assert_bind_args(session, expect_mapped_bind=True):
+ session.query(User.name == "x").all()
+
def test_bulk_update_no_sync(self):
User = self.classes.User
session = Session()
@@ -5998,7 +6131,7 @@ class SessionBindTest(QueryTest):
column_property(func.coalesce(self.tables.users.c.name, None)),
)
session = Session()
- with self._assert_bind_args(session):
+ with self._assert_bind_args(session, expect_mapped_bind=True):
session.query(func.max(User.score)).scalar()
def test_plain_table(self):
@@ -6008,9 +6141,10 @@ class SessionBindTest(QueryTest):
with self._assert_bind_args(session, expect_mapped_bind=False):
session.query(inspect(User).local_table).all()
- def test_plain_table_from_self(self):
+ def _test_plain_table_from_self(self):
User = self.classes.User
+ # TODO: this test is dumb
session = Session()
with self._assert_bind_args(session, expect_mapped_bind=False):
session.query(inspect(User).local_table).from_self().all()
diff --git a/test/orm/test_subquery_relations.py b/test/orm/test_subquery_relations.py
index 39e4f89ab..3d43bb441 100644
--- a/test/orm/test_subquery_relations.py
+++ b/test/orm/test_subquery_relations.py
@@ -2822,7 +2822,7 @@ class SubqueryloadDistinctTest(
# Director.photos
expect_distinct = director_strategy_level in (True, None)
- s = create_session()
+ s = create_session(testing.db)
q = s.query(Movie).options(
subqueryload(Movie.director).subqueryload(Director.photos)
@@ -2847,7 +2847,9 @@ class SubqueryloadDistinctTest(
)
ctx2 = q2._compile_context()
- result = s.execute(q2)
+ stmt = q2.statement
+
+ result = s.connection().execute(stmt)
rows = result.fetchall()
if expect_distinct:
@@ -2876,7 +2878,11 @@ class SubqueryloadDistinctTest(
"ON director_1.id = director_photo.director_id"
% (" DISTINCT" if expect_distinct else ""),
)
- result = s.execute(q3)
+
+ stmt = q3.statement
+
+ result = s.connection().execute(stmt)
+
rows = result.fetchall()
if expect_distinct:
eq_(
@@ -2911,7 +2917,7 @@ class SubqueryloadDistinctTest(
Movie = self.classes.Movie
Credit = self.classes.Credit
- s = create_session()
+ s = create_session(testing.db)
q = s.query(Credit).options(
subqueryload(Credit.movie).subqueryload(Movie.director)
@@ -2927,7 +2933,9 @@ class SubqueryloadDistinctTest(
("subqueryload_data", (inspect(Movie), Movie.director.property))
]["query"]
- result = s.execute(q3)
+ stmt = q3.statement
+
+ result = s.connection().execute(stmt)
eq_(result.fetchall(), [(1, "Woody Allen", 1), (1, "Woody Allen", 1)])
diff --git a/test/orm/test_transaction.py b/test/orm/test_transaction.py
index 6be6898be..4b4411080 100644
--- a/test/orm/test_transaction.py
+++ b/test/orm/test_transaction.py
@@ -366,7 +366,7 @@ class SessionTransactionTest(fixtures.RemovesEvents, FixtureTest):
u = User(name="u1")
sess.add(u)
sess.flush()
- c1 = sess.connection(User)
+ c1 = sess.connection(bind_arguments={"mapper": User})
dbapi_conn = c1.connection
assert dbapi_conn.is_valid
@@ -383,7 +383,7 @@ class SessionTransactionTest(fixtures.RemovesEvents, FixtureTest):
assert not dbapi_conn.is_valid
eq_(sess.query(User).all(), [])
- c2 = sess.connection(User)
+ c2 = sess.connection(bind_arguments={"mapper": User})
assert not c2.invalidated
assert c2.connection.is_valid
diff --git a/test/orm/test_versioning.py b/test/orm/test_versioning.py
index 2a7d09fad..86221a08f 100644
--- a/test/orm/test_versioning.py
+++ b/test/orm/test_versioning.py
@@ -740,7 +740,7 @@ class VersionOnPostUpdateTest(fixtures.MappedTest):
# outwit the database transaction isolation and SQLA's
# expiration at the same time by using different Session on
# same transaction
- s2 = Session(bind=s.connection(Node))
+ s2 = Session(bind=s.connection(mapper=Node))
s2.query(Node).filter(Node.id == n2.id).update({"version_id": 3})
s2.commit()
@@ -762,7 +762,7 @@ class VersionOnPostUpdateTest(fixtures.MappedTest):
), patch.object(
config.db.dialect, "supports_sane_multi_rowcount", False
):
- s2 = Session(bind=s.connection(Node))
+ s2 = Session(bind=s.connection(mapper=Node))
s2.query(Node).filter(Node.id == n2.id).update({"version_id": 3})
s2.commit()
@@ -783,7 +783,7 @@ class VersionOnPostUpdateTest(fixtures.MappedTest):
# outwit the database transaction isolation and SQLA's
# expiration at the same time by using different Session on
# same transaction
- s2 = Session(bind=s.connection(Node))
+ s2 = Session(bind=s.connection(mapper=Node))
s2.query(Node).filter(Node.id == n1.id).update({"version_id": 3})
s2.commit()
diff --git a/test/perf/orm2010.py b/test/perf/orm2010.py
index d9efc50a3..568219770 100644
--- a/test/perf/orm2010.py
+++ b/test/perf/orm2010.py
@@ -68,7 +68,7 @@ if os.path.exists("orm2010.db"):
os.remove("orm2010.db")
# use a file based database so that cursor.execute() has some
# palpable overhead.
-engine = create_engine("sqlite:///orm2010.db")
+engine = create_engine("sqlite:///orm2010.db", query_cache_size=100)
Base.metadata.create_all(engine)
@@ -178,7 +178,7 @@ def run_with_profile(runsnake=False, dump=False):
if dump:
# stats.sort_stats("nfl")
- stats.sort_stats("file", "name")
+ stats.sort_stats("cumtime", "calls")
stats.print_stats()
# stats.print_callers()
@@ -186,7 +186,7 @@ def run_with_profile(runsnake=False, dump=False):
os.system("runsnake %s" % filename)
-def run_with_time():
+def run_with_time(factor):
import time
now = time.time()
@@ -222,7 +222,13 @@ if __name__ == "__main__":
action="store_true",
help="invoke runsnakerun (implies --profile)",
)
-
+ parser.add_argument(
+ "--factor",
+ type=int,
+ default=10,
+ help="scale factor, a multiple of how many records to work with. "
+ "defaults to 10",
+ )
args = parser.parse_args()
args.profile = args.profile or args.dump or args.runsnake
@@ -230,4 +236,4 @@ if __name__ == "__main__":
if args.profile:
run_with_profile(runsnake=args.runsnake, dump=args.dump)
else:
- run_with_time()
+ run_with_time(args.factor)
diff --git a/test/profiles.txt b/test/profiles.txt
index 842caf4cd..b52c99e98 100644
--- a/test/profiles.txt
+++ b/test/profiles.txt
@@ -165,66 +165,66 @@ test.aaa_profiling.test_misc.EnumTest.test_create_enum_from_pep_435_w_expensive_
# TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 2.7_sqlite_pysqlite_dbapiunicode_cextensions 45805
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 56605
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 3.8_sqlite_pysqlite_dbapiunicode_cextensions 49605
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 60905
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 2.7_sqlite_pysqlite_dbapiunicode_cextensions 47405
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 58405
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 3.8_sqlite_pysqlite_dbapiunicode_cextensions 51005
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 63005
# TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 2.7_sqlite_pysqlite_dbapiunicode_cextensions 44305
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 55105
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 3.8_sqlite_pysqlite_dbapiunicode_cextensions 48105
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 59405
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 2.7_sqlite_pysqlite_dbapiunicode_cextensions 46305
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 57305
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 3.8_sqlite_pysqlite_dbapiunicode_cextensions 49905
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_wo_annotation 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 61905
# TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 43405
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 51705
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 3.8_sqlite_pysqlite_dbapiunicode_cextensions 46605
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 55405
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 45305
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 53805
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 3.8_sqlite_pysqlite_dbapiunicode_cextensions 48205
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_w_annotations 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 57705
# TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 42605
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 50905
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 3.8_sqlite_pysqlite_dbapiunicode_cextensions 45805
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 54605
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 44505
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 53005
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 3.8_sqlite_pysqlite_dbapiunicode_cextensions 47405
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_entity_wo_annotations 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 56905
# TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle 2.7_sqlite_pysqlite_dbapiunicode_cextensions 42905
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 46405
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle 3.8_sqlite_pysqlite_dbapiunicode_cextensions 45505
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 49505
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle 2.7_sqlite_pysqlite_dbapiunicode_cextensions 44905
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 48605
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle 3.8_sqlite_pysqlite_dbapiunicode_cextensions 47205
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 51905
# TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 43405
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 51705
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 3.8_sqlite_pysqlite_dbapiunicode_cextensions 46605
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 55405
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 45305
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 53805
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 3.8_sqlite_pysqlite_dbapiunicode_cextensions 48205
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_w_annotations 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 57705
# TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 42605
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 50905
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 3.8_sqlite_pysqlite_dbapiunicode_cextensions 45805
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 54605
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 44505
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 53005
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 3.8_sqlite_pysqlite_dbapiunicode_cextensions 47405
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_bundle_wo_annotations 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 56905
# TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 27805
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 30005
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations 3.8_sqlite_pysqlite_dbapiunicode_cextensions 30605
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 32705
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 29705
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 32105
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations 3.8_sqlite_pysqlite_dbapiunicode_cextensions 32205
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_w_annotations 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 35005
# TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 27005
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 29205
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations 3.8_sqlite_pysqlite_dbapiunicode_cextensions 29805
-test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 31905
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_cextensions 28905
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 31305
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations 3.8_sqlite_pysqlite_dbapiunicode_cextensions 31405
+test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 34205
# TEST: test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set
@@ -263,66 +263,66 @@ test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_key_bound_branchi
# 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_sqlite_pysqlite_dbapiunicode_cextensions 404
-test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 404
-test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.8_sqlite_pysqlite_dbapiunicode_cextensions 410
-test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 410
+test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 2.7_sqlite_pysqlite_dbapiunicode_cextensions 409
+test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 409
+test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.8_sqlite_pysqlite_dbapiunicode_cextensions 415
+test.aaa_profiling.test_orm.BranchedOptionTest.test_query_opts_unbound_branching 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 415
# TEST: test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline
-test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_sqlite_pysqlite_dbapiunicode_cextensions 15169
-test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 26174
-test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.8_sqlite_pysqlite_dbapiunicode_cextensions 15206
-test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 27211
+test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_sqlite_pysqlite_dbapiunicode_cextensions 15186
+test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 26199
+test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.8_sqlite_pysqlite_dbapiunicode_cextensions 15220
+test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 27238
# TEST: test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols
-test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 2.7_sqlite_pysqlite_dbapiunicode_cextensions 21308
-test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 26313
-test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 3.8_sqlite_pysqlite_dbapiunicode_cextensions 21352
-test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 27357
+test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 2.7_sqlite_pysqlite_dbapiunicode_cextensions 21337
+test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 26350
+test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 3.8_sqlite_pysqlite_dbapiunicode_cextensions 21378
+test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 27396
# TEST: test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_b_aliased
test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_b_aliased 2.7_sqlite_pysqlite_dbapiunicode_cextensions 9603
-test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_b_aliased 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 9603
+test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_b_aliased 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 9753
test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_b_aliased 3.8_sqlite_pysqlite_dbapiunicode_cextensions 10054
-test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_b_aliased 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 10054
+test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_b_aliased 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 10204
# TEST: test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_b_plain
test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_b_plain 2.7_sqlite_pysqlite_dbapiunicode_cextensions 3803
-test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_b_plain 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 3803
+test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_b_plain 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 3953
test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_b_plain 3.8_sqlite_pysqlite_dbapiunicode_cextensions 3804
-test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_b_plain 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 3804
+test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_b_plain 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 3954
# TEST: test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d
-test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d 2.7_sqlite_pysqlite_dbapiunicode_cextensions 93288
-test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 93288
-test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d 3.8_sqlite_pysqlite_dbapiunicode_cextensions 100904
-test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 100904
+test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d 2.7_sqlite_pysqlite_dbapiunicode_cextensions 93388
+test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 93738
+test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d 3.8_sqlite_pysqlite_dbapiunicode_cextensions 101204
+test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 101354
# TEST: test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d_aliased
-test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d_aliased 2.7_sqlite_pysqlite_dbapiunicode_cextensions 91388
-test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d_aliased 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 91388
-test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d_aliased 3.8_sqlite_pysqlite_dbapiunicode_cextensions 99319
-test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d_aliased 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 99319
+test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d_aliased 2.7_sqlite_pysqlite_dbapiunicode_cextensions 91488
+test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d_aliased 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 91838
+test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d_aliased 3.8_sqlite_pysqlite_dbapiunicode_cextensions 99619
+test.aaa_profiling.test_orm.JoinConditionTest.test_a_to_d_aliased 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 99769
# TEST: test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query
-test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_sqlite_pysqlite_dbapiunicode_cextensions 433700
-test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 433690
-test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.8_sqlite_pysqlite_dbapiunicode_cextensions 464467
-test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 464467
+test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_sqlite_pysqlite_dbapiunicode_cextensions 435824
+test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 437676
+test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.8_sqlite_pysqlite_dbapiunicode_cextensions 466586
+test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_build_query 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 468428
# TEST: test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results
-test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 2.7_sqlite_pysqlite_dbapiunicode_cextensions 448792
-test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 463192
-test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 3.8_sqlite_pysqlite_dbapiunicode_cextensions 453801
-test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 472001
+test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 2.7_sqlite_pysqlite_dbapiunicode_cextensions 438787
+test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 455887
+test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 3.8_sqlite_pysqlite_dbapiunicode_cextensions 445894
+test.aaa_profiling.test_orm.JoinedEagerLoadTest.test_fetch_results 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 463494
# TEST: test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity
@@ -333,24 +333,24 @@ test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_
# TEST: test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity
-test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_sqlite_pysqlite_dbapiunicode_cextensions 93373
-test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 96080
-test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.8_sqlite_pysqlite_dbapiunicode_cextensions 94821
-test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 98576
+test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_sqlite_pysqlite_dbapiunicode_cextensions 89497
+test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 92264
+test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.8_sqlite_pysqlite_dbapiunicode_cextensions 91083
+test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 94852
# TEST: test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks
-test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_sqlite_pysqlite_dbapiunicode_cextensions 19452
-test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 19728
-test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.8_sqlite_pysqlite_dbapiunicode_cextensions 20298
-test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 20700
+test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_sqlite_pysqlite_dbapiunicode_cextensions 19498
+test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 19970
+test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.8_sqlite_pysqlite_dbapiunicode_cextensions 20344
+test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 20924
# TEST: test.aaa_profiling.test_orm.MergeTest.test_merge_load
-test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_sqlite_pysqlite_dbapiunicode_cextensions 1134
-test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 1157
-test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.8_sqlite_pysqlite_dbapiunicode_cextensions 1168
-test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 1199
+test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_sqlite_pysqlite_dbapiunicode_cextensions 1141
+test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 1175
+test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.8_sqlite_pysqlite_dbapiunicode_cextensions 1177
+test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 1221
# TEST: test.aaa_profiling.test_orm.MergeTest.test_merge_no_load
@@ -361,24 +361,24 @@ test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 3.8_sqlite_pysqlite_dba
# TEST: test.aaa_profiling.test_orm.QueryTest.test_query_cols
-test.aaa_profiling.test_orm.QueryTest.test_query_cols 2.7_sqlite_pysqlite_dbapiunicode_cextensions 5437
-test.aaa_profiling.test_orm.QueryTest.test_query_cols 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 6157
-test.aaa_profiling.test_orm.QueryTest.test_query_cols 3.8_sqlite_pysqlite_dbapiunicode_cextensions 5795
-test.aaa_profiling.test_orm.QueryTest.test_query_cols 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 6505
+test.aaa_profiling.test_orm.QueryTest.test_query_cols 2.7_sqlite_pysqlite_dbapiunicode_cextensions 5559
+test.aaa_profiling.test_orm.QueryTest.test_query_cols 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 6299
+test.aaa_profiling.test_orm.QueryTest.test_query_cols 3.8_sqlite_pysqlite_dbapiunicode_cextensions 5887
+test.aaa_profiling.test_orm.QueryTest.test_query_cols 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 6667
# TEST: test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results
-test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_sqlite_pysqlite_dbapiunicode_cextensions 184177
-test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 200783
-test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 3.8_sqlite_pysqlite_dbapiunicode_cextensions 189638
-test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 207344
+test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_sqlite_pysqlite_dbapiunicode_cextensions 182806
+test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 199629
+test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 3.8_sqlite_pysqlite_dbapiunicode_cextensions 187973
+test.aaa_profiling.test_orm.SelectInEagerLoadTest.test_round_trip_results 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 206403
# TEST: test.aaa_profiling.test_orm.SessionTest.test_expire_lots
-test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_sqlite_pysqlite_dbapiunicode_cextensions 1150
-test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 1166
-test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.8_sqlite_pysqlite_dbapiunicode_cextensions 1263
-test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 1259
+test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_sqlite_pysqlite_dbapiunicode_cextensions 1155
+test.aaa_profiling.test_orm.SessionTest.test_expire_lots 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 1152
+test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.8_sqlite_pysqlite_dbapiunicode_cextensions 1246
+test.aaa_profiling.test_orm.SessionTest.test_expire_lots 3.8_sqlite_pysqlite_dbapiunicode_nocextensions 1266
# TEST: test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect
diff --git a/test/sql/test_compare.py b/test/sql/test_compare.py
index 247332d8c..d3d21cb0e 100644
--- a/test/sql/test_compare.py
+++ b/test/sql/test_compare.py
@@ -681,7 +681,7 @@ class CacheKeyFixture(object):
continue
eq_(a_key.key, b_key.key)
- eq_(hash(a_key), hash(b_key))
+ eq_(hash(a_key.key), hash(b_key.key))
for a_param, b_param in zip(
a_key.bindparams, b_key.bindparams
diff --git a/test/sql/test_compiler.py b/test/sql/test_compiler.py
index c580e972d..efe4d08c5 100644
--- a/test/sql/test_compiler.py
+++ b/test/sql/test_compiler.py
@@ -84,6 +84,7 @@ from sqlalchemy.testing import eq_
from sqlalchemy.testing import eq_ignore_whitespace
from sqlalchemy.testing import fixtures
from sqlalchemy.testing import is_
+from sqlalchemy.testing import mock
from sqlalchemy.util import u
table1 = table(
@@ -5198,9 +5199,16 @@ class ResultMapTest(fixtures.TestBase):
wrapped_again = select([c for c in wrapped.c])
- compiled = wrapped_again.compile(
- compile_kwargs={"select_wraps_for": stmt}
- )
+ dialect = default.DefaultDialect()
+
+ with mock.patch.object(
+ dialect.statement_compiler,
+ "translate_select_structure",
+ lambda self, to_translate, **kw: wrapped_again
+ if to_translate is stmt
+ else to_translate,
+ ):
+ compiled = stmt.compile(dialect=dialect)
proxied = [obj[0] for (k, n, obj, type_) in compiled._result_columns]
for orig_obj, proxied_obj in zip(orig, proxied):
@@ -5245,9 +5253,17 @@ class ResultMapTest(fixtures.TestBase):
# so the compiler logic that matches up the "wrapper" to the
# "select_wraps_for" can't use inner_columns to match because
# these collections are not the same
- compiled = wrapped_again.compile(
- compile_kwargs={"select_wraps_for": stmt}
- )
+
+ dialect = default.DefaultDialect()
+
+ with mock.patch.object(
+ dialect.statement_compiler,
+ "translate_select_structure",
+ lambda self, to_translate, **kw: wrapped_again
+ if to_translate is stmt
+ else to_translate,
+ ):
+ compiled = stmt.compile(dialect=dialect)
proxied = [obj[0] for (k, n, obj, type_) in compiled._result_columns]
for orig_obj, proxied_obj in zip(orig, proxied):
diff --git a/test/sql/test_deprecations.py b/test/sql/test_deprecations.py
index 578743750..202216723 100644
--- a/test/sql/test_deprecations.py
+++ b/test/sql/test_deprecations.py
@@ -1120,10 +1120,10 @@ class CursorResultTest(fixtures.TablesTest):
users = self.tables.users
with testing.expect_deprecated(
- "Retreiving row values using Column objects "
- "with only matching names",
- "Using non-integer/slice indices on Row is "
- "deprecated and will be removed in version 2.0",
+ # "Retreiving row values using Column objects "
+ # "with only matching names",
+ # "Using non-integer/slice indices on Row is "
+ # "deprecated and will be removed in version 2.0",
):
# this will create column() objects inside
# the select(), these need to match on name anyway
@@ -1137,14 +1137,14 @@ class CursorResultTest(fixtures.TablesTest):
r._keymap.pop(users.c.user_id) # reset lookup
with testing.expect_deprecated(
- "Retreiving row values using Column objects "
- "with only matching names"
+ # "Retreiving row values using Column objects "
+ # "with only matching names"
):
eq_(r._mapping[users.c.user_id], 2)
with testing.expect_deprecated(
- "Retreiving row values using Column objects "
- "with only matching names"
+ # "Retreiving row values using Column objects "
+ # "with only matching names"
):
eq_(r._mapping[users.c.user_name], "jack")
diff --git a/test/sql/test_resultset.py b/test/sql/test_resultset.py
index 6c83697dc..0eff94635 100644
--- a/test/sql/test_resultset.py
+++ b/test/sql/test_resultset.py
@@ -1856,7 +1856,34 @@ class KeyTargetingTest(fixtures.TablesTest):
is_(
existing_metadata._keymap[k], adapted_metadata._keymap[other_k]
)
- return stmt1, existing_metadata, stmt2, adapted_metadata
+
+ @testing.combinations(
+ _adapt_result_columns_fixture_one,
+ _adapt_result_columns_fixture_two,
+ _adapt_result_columns_fixture_three,
+ _adapt_result_columns_fixture_four,
+ argnames="stmt_fn",
+ )
+ def test_adapt_result_columns_from_cache(self, connection, stmt_fn):
+ stmt1 = stmt_fn(self)
+ stmt2 = stmt_fn(self)
+
+ cache = {}
+ result = connection._execute_20(
+ stmt1,
+ execution_options={"compiled_cache": cache, "future_result": True},
+ )
+ result.close()
+ assert cache
+
+ result = connection._execute_20(
+ stmt2,
+ execution_options={"compiled_cache": cache, "future_result": True},
+ )
+
+ row = result.first()
+ for col in stmt2.selected_columns:
+ assert col in row._mapping
class PositionalTextTest(fixtures.TablesTest):