diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2020-04-27 12:58:12 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2020-05-25 13:56:37 -0400 |
| commit | 6930dfc032c3f9f474e71ab4e021c0ef8384930e (patch) | |
| tree | 34b919a3c34edaffda1750f161a629fc5b9a8020 /test | |
| parent | dce8c7a125cb99fad62c76cd145752d5afefae36 (diff) | |
| download | sqlalchemy-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.py | 6 | ||||
| -rw-r--r-- | test/aaa_profiling/test_orm.py | 24 | ||||
| -rw-r--r-- | test/base/test_result.py | 53 | ||||
| -rw-r--r-- | test/ext/test_baked.py | 186 | ||||
| -rw-r--r-- | test/ext/test_horizontal_shard.py | 96 | ||||
| -rw-r--r-- | test/orm/inheritance/test_polymorphic_rel.py | 106 | ||||
| -rw-r--r-- | test/orm/test_bind.py | 257 | ||||
| -rw-r--r-- | test/orm/test_cache_key.py | 4 | ||||
| -rw-r--r-- | test/orm/test_core_compilation.py | 26 | ||||
| -rw-r--r-- | test/orm/test_expire.py | 7 | ||||
| -rw-r--r-- | test/orm/test_froms.py | 7 | ||||
| -rw-r--r-- | test/orm/test_loading.py | 2 | ||||
| -rw-r--r-- | test/orm/test_mapper.py | 2 | ||||
| -rw-r--r-- | test/orm/test_query.py | 238 | ||||
| -rw-r--r-- | test/orm/test_subquery_relations.py | 18 | ||||
| -rw-r--r-- | test/orm/test_transaction.py | 4 | ||||
| -rw-r--r-- | test/orm/test_versioning.py | 6 | ||||
| -rw-r--r-- | test/perf/orm2010.py | 16 | ||||
| -rw-r--r-- | test/profiles.txt | 184 | ||||
| -rw-r--r-- | test/sql/test_compare.py | 2 | ||||
| -rw-r--r-- | test/sql/test_compiler.py | 28 | ||||
| -rw-r--r-- | test/sql/test_deprecations.py | 16 | ||||
| -rw-r--r-- | test/sql/test_resultset.py | 29 |
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): |
