remove ORM autocommit and public-facing subtransactions concept

In order to do LegacyRow we have to do Connection, which means
we lose close_with_result (hooray) which then means we
have to get rid of ORM session autocommit which relies on it, so
let's do that first.

Change-Id: I115f614733b1d0ba19f320ffa9a49f0d762db094
This commit is contained in:
Mike Bayer
2021-10-30 20:45:26 -04:00
parent 06aecd14b9
commit cdce33e2cc
19 changed files with 158 additions and 1093 deletions
+15 -8
View File
@@ -445,18 +445,25 @@ More conveniently, it can be turned off within a context managed block using :at
mysession.add(some_object)
mysession.flush()
The flush process *always* occurs within a transaction, even if the
:class:`~sqlalchemy.orm.session.Session` has been configured with
``autocommit=True``, a setting that disables the session's persistent
transactional state. If no transaction is present,
:meth:`~.Session.flush` creates its own transaction and
commits it. Any failures during flush will always result in a rollback of
whatever transaction is present. If the Session is not in ``autocommit=True``
mode, an explicit call to :meth:`~.Session.rollback` is
The flush process *always* occurs within a transaction (subject
to the :ref:`isolation level <session_transaction_isolation>`_ of the
database transaction), which is
*never* committed automatically; the :meth:`_orm.Session.commit` method
must be called, or an appropriate context manager which does the same
thing must be used, in order for the database changes to be committed.
Any failures during flush will always result in a rollback of
whatever transaction is present. In order to continue using that
same :class:`_orm.Session`, an explicit call to :meth:`~.Session.rollback` is
required after a flush fails, even though the underlying transaction will have
been rolled back already - this is so that the overall nesting pattern of
so-called "subtransactions" is consistently maintained.
.. seealso::
:ref:`faq_session_rollback` - further background on why
:meth:`_orm.Session.rollback` must be called when a flush fails.
Expiring / Refreshing
---------------------
-95
View File
@@ -323,25 +323,11 @@ Session::
.. _session_autocommit:
.. _session_explicit_begin:
Explicit Begin
---------------
.. versionchanged:: 1.4
SQLAlchemy 1.4 deprecates "autocommit mode", which is historically enabled
by using the :paramref:`_orm.Session.autocommit` flag. Going forward,
a new approach to allowing usage of the :meth:`_orm.Session.begin` method
is new "autobegin" behavior so that the method may now be called when
a :class:`_orm.Session` is first constructed, or after the previous
transaction has ended and before it begins a new one.
For background on migrating away from the "subtransaction" pattern for
frameworks that rely upon nesting of begin()/commit() pairs, see the
next section :ref:`session_subtransactions`.
The :class:`_orm.Session` features "autobegin" behavior, meaning that as soon
as operations begin to take place, it ensures a :class:`_orm.SessionTransaction`
is present to track ongoing operations. This transaction is completed
@@ -383,87 +369,6 @@ when it occurs; this hook is used by frameworks in order to integrate their
own transactional processes with that of the ORM :class:`_orm.Session`.
.. _session_subtransactions:
Migrating from the "subtransaction" pattern
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 1.4 The :paramref:`_orm.Session.begin.subtransactions`
flag is deprecated. While the :class:`_orm.Session` still uses the
"subtransactions" pattern internally, it is not suitable for end-user
use as it leads to confusion, and additionally it may be removed from
the :class:`_orm.Session` itself in version 2.0 once "autocommit"
mode is removed.
The "subtransaction" pattern that was often used with autocommit mode is
also deprecated in 1.4. This pattern allowed the use of the
:meth:`_orm.Session.begin` method when a transaction were already begun,
resulting in a construct called a "subtransaction", which was essentially
a block that would prevent the :meth:`_orm.Session.commit` method from actually
committing.
This pattern has been shown to be confusing in real world applications, and
it is preferable for an application to ensure that the top-most level of database
operations are performed with a single begin/commit pair.
To provide backwards compatibility for applications that make use of this
pattern, the following context manager or a similar implementation based on
a decorator may be used::
import contextlib
@contextlib.contextmanager
def transaction(session):
if not session.in_transaction():
with session.begin():
yield
else:
yield
The above context manager may be used in the same way the
"subtransaction" flag works, such as in the following example::
# method_a starts a transaction and calls method_b
def method_a(session):
with transaction(session):
method_b(session)
# method_b also starts a transaction, but when
# called from method_a participates in the ongoing
# transaction.
def method_b(session):
with transaction(session):
session.add(SomeObject('bat', 'lala'))
Session = sessionmaker(engine)
# create a Session and call method_a
with Session() as session:
method_a(session)
To compare towards the preferred idiomatic pattern, the begin block should
be at the outermost level. This removes the need for individual functions
or methods to be concerned with the details of transaction demarcation::
def method_a(session):
method_b(session)
def method_b(session):
session.add(SomeObject('bat', 'lala'))
Session = sessionmaker(engine)
# create a Session and call method_a
with Session() as session:
with session.begin():
method_a(session)
.. seealso::
:ref:`connections_subtransactions` - similar pattern based on Core only
.. _session_twophase:
+1 -12
View File
@@ -107,13 +107,7 @@ def create_session(bind=None, **kwargs):
The defaults of create_session() are the opposite of that of
:func:`sessionmaker`; ``autoflush`` and ``expire_on_commit`` are
False, ``autocommit`` is True. In this sense the session acts
more like the "classic" SQLAlchemy 0.3 session with these.
.. deprecated:: 1.4 The "autocommit" parameter will be removed in
SQLAlchemy 2.0. :func:`_orm.create_session` will return a
:class:`_orm.Session` that does not include "autocommit' behavior
in release 2.0.
False.
Usage::
@@ -125,11 +119,6 @@ def create_session(bind=None, **kwargs):
"""
if kwargs.get("future", False):
kwargs.setdefault("autocommit", False)
else:
kwargs.setdefault("autocommit", True)
kwargs.setdefault("autoflush", False)
kwargs.setdefault("expire_on_commit", False)
return Session(bind=bind, **kwargs)
+1 -3
View File
@@ -1375,9 +1375,7 @@ def load_scalar_attributes(mapper, state, attribute_names, passive):
result = False
no_autoflush = (
bool(passive & attributes.NO_AUTOFLUSH) or state.session.autocommit
)
no_autoflush = bool(passive & attributes.NO_AUTOFLUSH)
# in the case of inheritance, particularly concrete and abstract
# concrete inheritance, the class manager might have some keys
+34 -141
View File
@@ -556,7 +556,8 @@ class SessionTransaction(TransactionalContext):
:class:`.SessionTransaction` is at the top of the stack, and
corresponds to a real "COMMIT"/"ROLLBACK"
block. If non-``None``, then this is either a "subtransaction"
or a "nested" / SAVEPOINT transaction. If the
(an internal marker object used by the flush process) or a
"nested" / SAVEPOINT transaction. If the
:attr:`.SessionTransaction.nested` attribute is ``True``, then
this is a SAVEPOINT, and if ``False``, indicates this a subtransaction.
@@ -950,29 +951,18 @@ class Session(_SessionClassMethods):
_is_asyncio = False
@util.deprecated_params(
autocommit=(
"2.0",
"The :paramref:`.Session.autocommit` parameter is deprecated "
"and will be removed in SQLAlchemy version 2.0. The "
':class:`_orm.Session` now features "autobegin" behavior '
"such that the :meth:`.Session.begin` method may be called "
"if a transaction has not yet been started yet. See the section "
":ref:`session_explicit_begin` for background.",
),
)
def __init__(
self,
bind=None,
autoflush=True,
future=False,
expire_on_commit=True,
autocommit=False,
twophase=False,
binds=None,
enable_baked_queries=True,
info=None,
query_cls=None,
autocommit=False,
):
r"""Construct a new Session.
@@ -980,25 +970,11 @@ class Session(_SessionClassMethods):
generate a :class:`.Session`-producing callable with a given
set of arguments.
:param autocommit:
Defaults to ``False``. When ``True``, the
:class:`.Session` does not automatically begin transactions for
individual statement executions, will acquire connections from the
engine on an as-needed basis, releasing to the connection pool
after each statement. Flushes will begin and commit (or possibly
rollback) their own transaction if no transaction is present.
When using this mode, the
:meth:`.Session.begin` method may be used to explicitly start
transactions, but the usual "autobegin" behavior is not present.
:param autoflush: When ``True``, all query operations will issue a
:meth:`~.Session.flush` call to this ``Session`` before proceeding.
This is a convenience feature so that :meth:`~.Session.flush` need
not be called repeatedly in order for database queries to retrieve
results. It's typical that ``autoflush`` is used in conjunction
with ``autocommit=False``. In this scenario, explicit calls to
:meth:`~.Session.flush` are rarely needed; you usually only need to
call :meth:`~.Session.commit` (which flushes) to finalize changes.
results.
:param bind: An optional :class:`_engine.Engine` or
:class:`_engine.Connection` to
@@ -1077,10 +1053,6 @@ class Session(_SessionClassMethods):
otherwise be configured against the :class:`_orm.sessionmaker`
in use
* The "subtransactions" feature of :meth:`_orm.Session.begin` is
removed in version 2.0 and is disabled when the future flag is
set.
* The behavior of the :paramref:`_orm.relationship.cascade_backrefs`
flag on a :func:`_orm.relationship` will always assume
"False" behavior.
@@ -1111,7 +1083,19 @@ class Session(_SessionClassMethods):
called. This allows each database to roll back the entire
transaction, before each transaction is committed.
:param autocommit: the "autocommit" keyword is present for backwards
compatibility but must remain at its default value of ``False``.
"""
# considering allowing the "autocommit" keyword to still be accepted
# as long as it's False, so that external test suites, oslo.db etc
# continue to function as the argument appears to be passed in lots
# of cases including in our own test suite
if autocommit:
raise sa_exc.ArgumentError(
"autocommit=True is no longer supported"
)
self.identity_map = identity.WeakInstanceDict()
self._new = {} # InstanceState->object, strong refs object
@@ -1128,15 +1112,6 @@ class Session(_SessionClassMethods):
self.expire_on_commit = expire_on_commit
self.enable_baked_queries = enable_baked_queries
if autocommit:
if future:
raise sa_exc.ArgumentError(
"Cannot use autocommit mode with future=True."
)
self.autocommit = True
else:
self.autocommit = False
self.twophase = twophase
self._query_cls = query_cls if query_cls else query.Query
if info:
@@ -1248,7 +1223,7 @@ class Session(_SessionClassMethods):
return {}
def _autobegin(self):
if not self.autocommit and self._transaction is None:
if self._transaction is None:
trans = SessionTransaction(self, autobegin=True)
assert self._transaction is trans
@@ -1256,17 +1231,7 @@ class Session(_SessionClassMethods):
return False
@util.deprecated_params(
subtransactions=(
"2.0",
"The :paramref:`_orm.Session.begin.subtransactions` flag is "
"deprecated and "
"will be removed in SQLAlchemy version 2.0. See "
"the documentation at :ref:`session_subtransactions` for "
"background on a compatible alternative pattern.",
)
)
def begin(self, subtransactions=False, nested=False, _subtrans=False):
def begin(self, nested=False, _subtrans=False):
"""Begin a transaction, or nested transaction,
on this :class:`.Session`, if one is not already begun.
@@ -1284,13 +1249,10 @@ class Session(_SessionClassMethods):
documentation on SAVEPOINT transactions, please see
:ref:`session_begin_nested`.
:param subtransactions: if True, indicates that this
:meth:`~.Session.begin` can create a "subtransaction".
:return: the :class:`.SessionTransaction` object. Note that
:class:`.SessionTransaction`
acts as a Python context manager, allowing :meth:`.Session.begin`
to be used in a "with" block. See :ref:`session_autocommit` for
to be used in a "with" block. See :ref:`session_explicit_begin` for
an example.
.. seealso::
@@ -1304,18 +1266,12 @@ class Session(_SessionClassMethods):
"""
if subtransactions and self.future:
raise NotImplementedError(
"subtransactions are not implemented in future "
"Session objects."
)
if self._autobegin():
if not subtransactions and not nested and not _subtrans:
if not nested and not _subtrans:
return self._transaction
if self._transaction is not None:
if subtransactions or _subtrans or nested:
if _subtrans or nested:
trans = self._transaction._begin(nested=nested)
assert self._transaction is trans
if nested:
@@ -1324,18 +1280,13 @@ class Session(_SessionClassMethods):
raise sa_exc.InvalidRequestError(
"A transaction is already begun on this Session."
)
elif not self.autocommit:
else:
# outermost transaction. must be a not nested and not
# a subtransaction
assert not nested and not _subtrans and not subtransactions
assert not nested and not _subtrans
trans = SessionTransaction(self)
assert self._transaction is trans
else:
# legacy autocommit mode
assert not self.future
trans = SessionTransaction(self, nested=nested)
assert self._transaction is trans
return self._transaction # needed for __enter__/__exit__ hook
@@ -1407,13 +1358,6 @@ class Session(_SessionClassMethods):
transaction is committed unconditionally, automatically releasing any
SAVEPOINTs in effect.
When using legacy "autocommit" mode, this method is only
valid to call if a transaction is actually in progress, else
an error is raised. Similarly, when using legacy "subtransactions",
the method will instead close out the current "subtransaction",
rather than the actual database transaction, if a transaction
is in progress.
.. seealso::
:ref:`session_committing`
@@ -1444,29 +1388,17 @@ class Session(_SessionClassMethods):
self._transaction.prepare()
def connection(
self,
bind_arguments=None,
close_with_result=False,
execution_options=None,
**kw
):
def connection(self, bind_arguments=None, execution_options=None, **kw):
r"""Return a :class:`_engine.Connection` object corresponding to this
:class:`.Session` object's transactional state.
If this :class:`.Session` is configured with ``autocommit=False``,
either the :class:`_engine.Connection` corresponding to the current
Either the :class:`_engine.Connection` corresponding to the current
transaction is returned, or if no transaction is in progress, a new
one is begun and the :class:`_engine.Connection`
returned (note that no
transactional state is established with the DBAPI until the first
SQL statement is emitted).
Alternatively, if this :class:`.Session` is configured with
``autocommit=True``, an ad-hoc :class:`_engine.Connection` is returned
using :meth:`_engine.Engine.connect` on the underlying
:class:`_engine.Engine`.
Ambiguity in multi-bind or unbound :class:`.Session` objects can be
resolved through any of the optional keyword arguments. This
ultimately makes usage of the :meth:`.get_bind` method for resolution.
@@ -1484,16 +1416,6 @@ class Session(_SessionClassMethods):
:param clause:
deprecated; use bind_arguments
:param close_with_result: Passed to :meth:`_engine.Engine.connect`,
indicating the :class:`_engine.Connection` should be considered
"single use", automatically closing when the first result set is
closed. This flag only has an effect if this :class:`.Session` is
configured with ``autocommit=True`` and does not already have a
transaction in progress.
.. deprecated:: 1.4 this parameter is deprecated and will be removed
in SQLAlchemy 2.0
:param execution_options: a dictionary of execution options that will
be passed to :meth:`_engine.Connection.execution_options`, **when the
connection is first procured only**. If the connection is already
@@ -1518,24 +1440,17 @@ class Session(_SessionClassMethods):
return self._connection_for_bind(
bind,
close_with_result=close_with_result,
execution_options=execution_options,
)
def _connection_for_bind(self, engine, execution_options=None, **kw):
TransactionalContext._trans_ctx_check(self)
if self._transaction is not None or self._autobegin():
return self._transaction._connection_for_bind(
engine, execution_options
)
assert self._transaction is None
assert self.autocommit
conn = engine.connect(**kw)
if execution_options:
conn = conn.execution_options(**execution_options)
return conn
if self._transaction is None:
assert self._autobegin()
return self._transaction._connection_for_bind(
engine, execution_options
)
def execute(
self,
@@ -1676,16 +1591,7 @@ class Session(_SessionClassMethods):
bind = self.get_bind(**bind_arguments)
if self.autocommit:
# legacy stuff, we can't use future_result w/ autocommit because
# we rely upon close_with_result, also legacy. it's all
# interrelated
conn = self._connection_for_bind(bind, close_with_result=True)
execution_options = execution_options.union(
dict(future_result=False)
)
else:
conn = self._connection_for_bind(bind)
conn = self._connection_for_bind(bind)
result = conn._execute_20(statement, params or {}, execution_options)
if compile_state_cls:
@@ -2344,8 +2250,8 @@ class Session(_SessionClassMethods):
expire all state whenever the :meth:`Session.rollback`
or :meth:`Session.commit` methods are called, so that new
state can be loaded for the new transaction. For this reason,
calling :meth:`Session.expire_all` should not be needed when
autocommit is ``False``, assuming the transaction is isolated.
calling :meth:`Session.expire_all` is not usually needed,
assuming the transaction is isolated.
.. seealso::
@@ -3322,10 +3228,6 @@ class Session(_SessionClassMethods):
You may flush() as often as you like within a transaction to move
changes from Python to the database's transaction buffer.
For ``autocommit`` Sessions with no active manual transaction, flush()
will create a transaction on the fly that surrounds the entire set of
operations into the flush.
:param objects: Optional; restricts the flush operation to operate
only on elements that are in the given collection.
@@ -3914,12 +3816,7 @@ class Session(_SessionClassMethods):
:meth:`_orm.Session.in_transaction`
"""
if self.autocommit:
return (
self._transaction is not None and self._transaction.is_active
)
else:
return self._transaction is None or self._transaction.is_active
return self._transaction is None or self._transaction.is_active
identity_map = None
"""A mapping of object identities to objects themselves.
@@ -4090,7 +3987,6 @@ class sessionmaker(_SessionClassMethods):
bind=None,
class_=Session,
autoflush=True,
autocommit=False,
expire_on_commit=True,
info=None,
**kw
@@ -4108,8 +4004,6 @@ class sessionmaker(_SessionClassMethods):
objects. Defaults to :class:`.Session`.
:param autoflush: The autoflush setting to use with newly created
:class:`.Session` objects.
:param autocommit: The autocommit setting to use with newly created
:class:`.Session` objects.
:param expire_on_commit=True: the
:paramref:`_orm.Session.expire_on_commit` setting to use
with newly created :class:`.Session` objects.
@@ -4125,7 +4019,6 @@ class sessionmaker(_SessionClassMethods):
"""
kw["bind"] = bind
kw["autoflush"] = autoflush
kw["autocommit"] = autocommit
kw["expire_on_commit"] = expire_on_commit
if info is not None:
kw["info"] = info
+1 -3
View File
@@ -135,9 +135,7 @@ class ShardTest(object):
else:
return ids
sharded_session = sessionmaker(
class_=ShardedSession, autoflush=True, autocommit=False
)
sharded_session = sessionmaker(class_=ShardedSession, autoflush=True)
sharded_session.configure(
shards={
"north_america": db1,
+1 -1
View File
@@ -1228,7 +1228,7 @@ class OneToManyManyToOneTest(fixtures.MappedTest):
)
self.mapper_registry.map_imperatively(Person, person)
sess = fixture_session(autocommit=False, expire_on_commit=True)
sess = fixture_session(expire_on_commit=True)
p1 = Person()
sess.add(Ball(person=p1))
sess.commit()
+1 -758
View File
@@ -24,7 +24,6 @@ from sqlalchemy import true
from sqlalchemy import util
from sqlalchemy.engine import default
from sqlalchemy.engine import result_tuple
from sqlalchemy.engine.base import Engine
from sqlalchemy.orm import aliased
from sqlalchemy.orm import as_declarative
from sqlalchemy.orm import attributes
@@ -64,7 +63,6 @@ from sqlalchemy.orm import with_polymorphic
from sqlalchemy.orm.collections import attribute_mapped_collection
from sqlalchemy.orm.collections import collection
from sqlalchemy.orm.util import polymorphic_union
from sqlalchemy.sql import elements
from sqlalchemy.testing import assert_raises
from sqlalchemy.testing import assert_raises_message
from sqlalchemy.testing import assertions
@@ -127,15 +125,6 @@ join_tuple_form = (
"arguments in SQLAlchemy 2.0."
)
autocommit_dep = (
"The Session.autocommit parameter is deprecated "
"and will be removed in SQLAlchemy version 2.0."
)
subtransactions_dep = (
"The Session.begin.subtransactions flag is deprecated "
"and will be removed in SQLAlchemy version 2.0."
)
opt_strings_dep = (
"Using strings to indicate column or relationship "
"paths in loader options"
@@ -2788,19 +2777,6 @@ class SessionTest(fixtures.RemovesEvents, _LocalFixture):
s1 = Session(testing.db)
str(s1)
def test_subtransactions_deprecated(self):
s1 = Session(testing.db)
s1.begin()
with testing.expect_deprecated_20(subtransactions_dep):
s1.begin(subtransactions=True)
s1.close()
def test_autocommit_deprecated(Self):
with testing.expect_deprecated_20(autocommit_dep):
Session(autocommit=True)
@testing.combinations(
{"mapper": None},
{"clause": None},
@@ -2835,279 +2811,6 @@ class SessionTest(fixtures.RemovesEvents, _LocalFixture):
kw["clause"] = expr
eq_(m1.mock_calls, [call(**kw)])
@testing.requires.independent_connections
@testing.emits_warning(".*previous exception")
def test_failed_rollback_deactivates_transaction_ctx_integration(self):
# test #4050 in the same context as that of oslo.db
User = self.classes.User
with testing.expect_deprecated_20(
"The Session.autocommit parameter is deprecated"
):
session = Session(bind=testing.db, autocommit=True)
evented_exceptions = []
caught_exceptions = []
def canary(context):
evented_exceptions.append(context.original_exception)
rollback_error = testing.db.dialect.dbapi.InterfaceError(
"Can't roll back to savepoint"
)
def prevent_savepoint_rollback(
cursor, statement, parameters, context=None
):
if (
context is not None
and context.compiled
and isinstance(
context.compiled.statement,
elements.RollbackToSavepointClause,
)
):
raise rollback_error
self.event_listen(testing.db, "handle_error", canary, retval=True)
self.event_listen(
testing.db.dialect, "do_execute", prevent_savepoint_rollback
)
with session.begin():
session.add(User(id=1, name="x"))
try:
with session.begin():
try:
with session.begin_nested():
# raises IntegrityError on flush
session.add(User(id=1, name="x"))
# outermost is the failed SAVEPOINT rollback
# from the "with session.begin_nested()"
except sa_exc.DBAPIError as dbe_inner:
caught_exceptions.append(dbe_inner.orig)
raise
except sa_exc.DBAPIError as dbe_outer:
caught_exceptions.append(dbe_outer.orig)
is_true(
isinstance(
evented_exceptions[0], testing.db.dialect.dbapi.IntegrityError
)
)
eq_(evented_exceptions[1], rollback_error)
eq_(len(evented_exceptions), 2)
eq_(caught_exceptions, [rollback_error, rollback_error])
def test_contextmanager_commit(self):
User = self.classes.User
with testing.expect_deprecated_20(
"The Session.autocommit parameter is deprecated"
):
sess = Session(testing.db, autocommit=True)
with sess.begin():
sess.add(User(name="u1"))
sess.rollback()
eq_(sess.query(User).count(), 1)
def test_contextmanager_rollback(self):
User = self.classes.User
with testing.expect_deprecated_20(
"The Session.autocommit parameter is deprecated"
):
sess = Session(testing.db, autocommit=True)
def go():
with sess.begin():
sess.add(User()) # name can't be null
assert_raises(sa_exc.DBAPIError, go)
eq_(sess.query(User).count(), 0)
with sess.begin():
sess.add(User(name="u1"))
eq_(sess.query(User).count(), 1)
class TransScopingTest(_fixtures.FixtureTest):
run_inserts = None
__prefer_requires__ = ("independent_connections",)
@testing.combinations((True,), (False,), argnames="begin")
@testing.combinations((True,), (False,), argnames="expire_on_commit")
@testing.combinations((True,), (False,), argnames="modify_unconditional")
@testing.combinations(
("nothing",), ("modify",), ("add",), ("delete",), argnames="case_"
)
def test_autobegin_attr_change(
self, case_, begin, modify_unconditional, expire_on_commit
):
"""test :ticket:`6360`"""
autocommit = True
User, users = self.classes.User, self.tables.users
self.mapper_registry.map_imperatively(User, users)
with testing.expect_deprecated_20(autocommit_dep):
s = Session(
testing.db,
autocommit=autocommit,
expire_on_commit=expire_on_commit,
)
u = User(name="x")
u2 = User(name="d")
u3 = User(name="e")
s.add_all([u, u2, u3])
if autocommit:
s.flush()
else:
s.commit()
if begin:
s.begin()
if case_ == "add":
# this autobegins
s.add(User(name="q"))
elif case_ == "delete":
# this autobegins
s.delete(u2)
elif case_ == "modify":
# this autobegins
u3.name = "m"
if case_ == "nothing" and not begin:
assert not s._transaction
expect_expire = expire_on_commit
elif autocommit and not begin:
assert not s._transaction
expect_expire = expire_on_commit
else:
assert s._transaction
expect_expire = True
if modify_unconditional:
# this autobegins
u.name = "y"
expect_expire = True
if not expect_expire:
assert not s._transaction
# test is that state is consistent after rollback()
s.rollback()
if autocommit and not begin and modify_unconditional:
eq_(u.name, "y")
else:
if not expect_expire:
assert "name" in u.__dict__
else:
assert "name" not in u.__dict__
eq_(u.name, "x")
def test_no_autoflush_or_commit_in_expire_w_autocommit(self):
"""test second part of :ticket:`6233`.
Here we test that the "autoflush on unexpire" feature added
in :ticket:`5226` is turned off for a legacy autocommit session.
"""
with testing.expect_deprecated_20(autocommit_dep):
s = Session(
testing.db,
autocommit=True,
expire_on_commit=True,
autoflush=True,
)
User, users = self.classes.User, self.tables.users
self.mapper_registry.map_imperatively(User, users)
u1 = User(name="u1")
s.add(u1)
s.flush() # this commits
u1.name = "u2" # this does not commit
assert "id" not in u1.__dict__
u1.id # this unexpires
# never expired
eq_(u1.__dict__["name"], "u2")
eq_(u1.name, "u2")
# still in dirty collection
assert u1 in s.dirty
class AutocommitClosesOnFailTest(fixtures.MappedTest):
__requires__ = ("deferrable_fks",)
@classmethod
def define_tables(cls, metadata):
Table("t1", metadata, Column("id", Integer, primary_key=True))
Table(
"t2",
metadata,
Column("id", Integer, primary_key=True),
Column(
"t1_id",
Integer,
ForeignKey("t1.id", deferrable=True, initially="deferred"),
),
)
@classmethod
def setup_classes(cls):
class T1(cls.Comparable):
pass
class T2(cls.Comparable):
pass
@classmethod
def setup_mappers(cls):
T2, T1, t2, t1 = (
cls.classes.T2,
cls.classes.T1,
cls.tables.t2,
cls.tables.t1,
)
cls.mapper_registry.map_imperatively(T1, t1)
cls.mapper_registry.map_imperatively(T2, t2)
def test_close_transaction_on_commit_fail(self):
T2 = self.classes.T2
with testing.expect_deprecated_20(autocommit_dep):
session = Session(testing.db, autocommit=True)
# with a deferred constraint, this fails at COMMIT time instead
# of at INSERT time.
session.add(T2(id=1, t1_id=123))
assert_raises(
(sa.exc.IntegrityError, sa.exc.DatabaseError), session.flush
)
assert session._legacy_transaction() is None
class DeprecatedInhTest(_poly_fixtures._Polymorphic):
def test_with_polymorphic(self):
@@ -3284,7 +2987,7 @@ class DeprecatedMapperTest(_fixtures.FixtureTest, AssertsCompiledSQL):
m.add_property("_name", deferred(users.c.name))
m.add_property("name", synonym("_name"))
sess = fixture_session(autocommit=False)
sess = fixture_session()
assert sess.get(User, 7)
u = sess.query(User).filter_by(name="jack").one()
@@ -4381,445 +4084,9 @@ class DistinctOrderByImplicitTest(QueryTest, AssertsCompiledSQL):
)
class AutoCommitTest(_LocalFixture):
__backend__ = True
def test_begin_nested_requires_trans(self):
with assertions.expect_deprecated_20(autocommit_dep):
sess = fixture_session(autocommit=True)
assert_raises(sa_exc.InvalidRequestError, sess.begin_nested)
def test_begin_preflush(self):
User = self.classes.User
with assertions.expect_deprecated_20(autocommit_dep):
sess = fixture_session(autocommit=True)
u1 = User(name="ed")
sess.add(u1)
sess.begin()
u2 = User(name="some other user")
sess.add(u2)
sess.rollback()
assert u2 not in sess
assert u1 in sess
assert sess.query(User).filter_by(name="ed").one() is u1
def test_accounting_commit_fails_add(self):
User = self.classes.User
with assertions.expect_deprecated_20(autocommit_dep):
sess = fixture_session(autocommit=True)
fail = False
def fail_fn(*arg, **kw):
if fail:
raise Exception("commit fails")
event.listen(sess, "after_flush_postexec", fail_fn)
u1 = User(name="ed")
sess.add(u1)
fail = True
assert_raises(Exception, sess.flush)
fail = False
assert u1 not in sess
u1new = User(id=2, name="fred")
sess.add(u1new)
sess.add(u1)
sess.flush()
assert u1 in sess
eq_(
sess.query(User.name).order_by(User.name).all(),
[("ed",), ("fred",)],
)
def test_accounting_commit_fails_delete(self):
User = self.classes.User
with assertions.expect_deprecated_20(autocommit_dep):
sess = fixture_session(autocommit=True)
fail = False
def fail_fn(*arg, **kw):
if fail:
raise Exception("commit fails")
event.listen(sess, "after_flush_postexec", fail_fn)
u1 = User(name="ed")
sess.add(u1)
sess.flush()
sess.delete(u1)
fail = True
assert_raises(Exception, sess.flush)
fail = False
assert u1 in sess
assert u1 not in sess.deleted
sess.delete(u1)
sess.flush()
assert u1 not in sess
eq_(sess.query(User.name).order_by(User.name).all(), [])
@testing.requires.updateable_autoincrement_pks
def test_accounting_no_select_needed(self):
"""test that flush accounting works on non-expired instances
when autocommit=True/expire_on_commit=True."""
User = self.classes.User
with assertions.expect_deprecated_20(autocommit_dep):
sess = fixture_session(autocommit=True, expire_on_commit=True)
u1 = User(id=1, name="ed")
sess.add(u1)
sess.flush()
u1.id = 3
u1.name = "fred"
self.assert_sql_count(testing.db, sess.flush, 1)
assert "id" not in u1.__dict__
eq_(u1.id, 3)
class SessionStateTest(_fixtures.FixtureTest):
run_inserts = None
__prefer_requires__ = ("independent_connections",)
def test_autocommit_doesnt_raise_on_pending(self):
User, users = self.classes.User, self.tables.users
self.mapper_registry.map_imperatively(User, users)
with assertions.expect_deprecated_20(autocommit_dep):
session = Session(testing.db, autocommit=True)
session.add(User(name="ed"))
session.begin()
session.flush()
session.commit()
class SessionTransactionTest(fixtures.RemovesEvents, _fixtures.FixtureTest):
run_inserts = None
__backend__ = True
@testing.fixture
def conn(self):
with testing.db.connect() as conn:
yield conn
@testing.fixture
def future_conn(self):
engine = Engine._future_facade(testing.db)
with engine.connect() as conn:
yield conn
def test_deactive_status_check(self):
sess = fixture_session()
trans = sess.begin()
with assertions.expect_deprecated_20(subtransactions_dep):
trans2 = sess.begin(subtransactions=True)
trans2.rollback()
assert_raises_message(
sa_exc.InvalidRequestError,
"This session is in 'inactive' state, due to the SQL transaction "
"being rolled back; no further SQL can be emitted within this "
"transaction.",
trans.commit,
)
def test_deactive_status_check_w_exception(self):
sess = fixture_session()
trans = sess.begin()
with assertions.expect_deprecated_20(subtransactions_dep):
trans2 = sess.begin(subtransactions=True)
try:
raise Exception("test")
except Exception:
trans2.rollback(_capture_exception=True)
assert_raises_message(
sa_exc.PendingRollbackError,
r"This Session's transaction has been rolled back due to a "
r"previous exception during flush. To begin a new transaction "
r"with this Session, first issue Session.rollback\(\). "
r"Original exception was: test",
trans.commit,
)
def test_error_on_using_inactive_session_commands(self):
users, User = self.tables.users, self.classes.User
self.mapper_registry.map_imperatively(User, users)
with assertions.expect_deprecated_20(autocommit_dep):
sess = fixture_session(autocommit=True)
sess.begin()
with assertions.expect_deprecated_20(subtransactions_dep):
sess.begin(subtransactions=True)
sess.add(User(name="u1"))
sess.flush()
sess.rollback()
with assertions.expect_deprecated_20(subtransactions_dep):
assert_raises_message(
sa_exc.InvalidRequestError,
"This session is in 'inactive' state, due to the SQL "
"transaction "
"being rolled back; no further SQL can be emitted within this "
"transaction.",
sess.begin,
subtransactions=True,
)
sess.close()
def test_subtransaction_on_external_subtrans(self, conn):
users, User = self.tables.users, self.classes.User
self.mapper_registry.map_imperatively(User, users)
trans = conn.begin()
sess = Session(bind=conn, autocommit=False, autoflush=True)
with assertions.expect_deprecated_20(subtransactions_dep):
sess.begin(subtransactions=True)
u = User(name="ed")
sess.add(u)
sess.flush()
sess.commit() # commit does nothing
trans.rollback() # rolls back
assert len(sess.query(User).all()) == 0
sess.close()
def test_subtransaction_on_noautocommit(self):
User, users = self.classes.User, self.tables.users
self.mapper_registry.map_imperatively(User, users)
sess = fixture_session(autocommit=False, autoflush=True)
with assertions.expect_deprecated_20(subtransactions_dep):
sess.begin(subtransactions=True)
u = User(name="u1")
sess.add(u)
sess.flush()
sess.commit() # commit does nothing
sess.rollback() # rolls back
assert len(sess.query(User).all()) == 0
sess.close()
@testing.requires.savepoints
def test_heavy_nesting(self):
users = self.tables.users
session = fixture_session()
session.begin()
session.connection().execute(users.insert().values(name="user1"))
with assertions.expect_deprecated_20(subtransactions_dep):
session.begin(subtransactions=True)
session.begin_nested()
session.connection().execute(users.insert().values(name="user2"))
assert (
session.connection()
.exec_driver_sql("select count(1) from users")
.scalar()
== 2
)
session.rollback()
assert (
session.connection()
.exec_driver_sql("select count(1) from users")
.scalar()
== 1
)
session.connection().execute(users.insert().values(name="user3"))
session.commit()
assert (
session.connection()
.exec_driver_sql("select count(1) from users")
.scalar()
== 2
)
@testing.requires.savepoints
def test_heavy_nesting_future(self):
users = self.tables.users
from sqlalchemy.future import Engine
engine = Engine._future_facade(testing.db)
with Session(engine, autocommit=False) as session:
session.begin()
session.connection().execute(users.insert().values(name="user1"))
with assertions.expect_deprecated_20(subtransactions_dep):
session.begin(subtransactions=True)
session.begin_nested()
session.connection().execute(users.insert().values(name="user2"))
assert (
session.connection()
.exec_driver_sql("select count(1) from users")
.scalar()
== 2
)
session.rollback()
assert (
session.connection()
.exec_driver_sql("select count(1) from users")
.scalar()
== 1
)
session.connection().execute(users.insert().values(name="user3"))
session.commit()
assert (
session.connection()
.exec_driver_sql("select count(1) from users")
.scalar()
== 2
)
@testing.requires.savepoints
def test_mixed_transaction_control(self):
users, User = self.tables.users, self.classes.User
self.mapper_registry.map_imperatively(User, users)
with assertions.expect_deprecated_20(autocommit_dep):
sess = fixture_session(autocommit=True)
sess.begin()
sess.begin_nested()
with assertions.expect_deprecated_20(subtransactions_dep):
transaction = sess.begin(subtransactions=True)
sess.add(User(name="u1"))
transaction.commit()
sess.commit()
sess.commit()
sess.close()
eq_(len(sess.query(User).all()), 1)
t1 = sess.begin()
t2 = sess.begin_nested()
sess.add(User(name="u2"))
t2.commit()
assert sess._legacy_transaction() is t1
sess.close()
@testing.requires.savepoints
def test_nested_transaction_connection_add_autocommit(self):
users, User = self.tables.users, self.classes.User
self.mapper_registry.map_imperatively(User, users)
with assertions.expect_deprecated_20(autocommit_dep):
sess = fixture_session(autocommit=True)
sess.begin()
sess.begin_nested()
u1 = User(name="u1")
sess.add(u1)
sess.flush()
sess.rollback()
u2 = User(name="u2")
sess.add(u2)
sess.commit()
eq_(set(sess.query(User).all()), set([u2]))
sess.begin()
sess.begin_nested()
u3 = User(name="u3")
sess.add(u3)
sess.commit() # commit the nested transaction
sess.rollback()
eq_(set(sess.query(User).all()), set([u2]))
sess.close()
def test_active_flag_autocommit(self):
with assertions.expect_deprecated_20(autocommit_dep):
sess = Session(bind=testing.db, autocommit=True)
assert not sess.is_active
sess.begin()
assert sess.is_active
sess.rollback()
assert not sess.is_active
class SessionEventsTest(_RemoveListeners, _fixtures.FixtureTest):
run_inserts = None
def _listener_fixture(self, **kw):
canary = []
def listener(name):
def go(*arg, **kw):
canary.append(name)
return go
sess = fixture_session(**kw)
for evt in [
"after_transaction_create",
"after_transaction_end",
"before_commit",
"after_commit",
"after_rollback",
"after_soft_rollback",
"before_flush",
"after_flush",
"after_flush_postexec",
"after_begin",
"before_attach",
"after_attach",
"after_bulk_update",
"after_bulk_delete",
]:
event.listen(sess, evt, listener(evt))
return sess, canary
def test_flush_autocommit_hook(self):
User, users = self.classes.User, self.tables.users
self.mapper_registry.map_imperatively(User, users)
with assertions.expect_deprecated_20(autocommit_dep):
sess, canary = self._listener_fixture(
autoflush=False, autocommit=True, expire_on_commit=False
)
u = User(name="u1")
sess.add(u)
sess.flush()
eq_(
canary,
[
"before_attach",
"after_attach",
"before_flush",
"after_transaction_create",
"after_begin",
"after_flush",
"after_flush_postexec",
"before_commit",
"after_commit",
"after_transaction_end",
],
)
def test_on_bulk_update_hook(self):
User, users = self.classes.User, self.tables.users
@@ -9460,30 +8727,6 @@ class LazyTest(_fixtures.FixtureTest):
self.assert_sql_count(testing.db, go, 1)
class BindIntegrationTest(_fixtures.FixtureTest):
run_inserts = None
def test_bound_connection_transactional(self):
User, users = self.classes.User, self.tables.users
self.mapper_registry.map_imperatively(User, users)
with testing.db.connect() as c:
trans = c.begin()
with assertions.expect_deprecated_20(autocommit_dep):
sess = Session(bind=c, autocommit=True)
u = User(name="u3")
sess.add(u)
sess.flush()
assert c.in_transaction()
trans.commit()
assert not c.in_transaction()
assert (
c.exec_driver_sql("select count(1) from users").scalar() == 1
)
class MergeResultTest(_fixtures.FixtureTest):
run_setup_mappers = "once"
run_inserts = "once"
+13 -7
View File
@@ -797,7 +797,9 @@ class UOWTest(
User, Address = self._user_address_fixture(
addresses_args={"order_by": addresses.c.email_address}
)
sess = fixture_session(autoflush=True, autocommit=False)
sess = fixture_session(
autoflush=True,
)
u1 = User(name="jack")
a1 = Address(email_address="a1")
a2 = Address(email_address="a2")
@@ -885,9 +887,7 @@ class UOWTest(
def test_rollback(self):
User, Address = self._user_address_fixture()
sess = fixture_session(
expire_on_commit=False, autocommit=False, autoflush=True
)
sess = fixture_session(expire_on_commit=False, autoflush=True)
u1 = User(name="jack")
u1.addresses.append(Address(email_address="lala@hoho.com"))
sess.add(u1)
@@ -914,7 +914,9 @@ class UOWTest(
}
)
sess = fixture_session(autoflush=True, autocommit=False)
sess = fixture_session(
autoflush=True,
)
u = User(name="ed")
u.addresses.extend(
[Address(email_address=letter) for letter in "abcdef"]
@@ -1008,7 +1010,9 @@ class UOWTest(
}
)
sess = fixture_session(autoflush=True, autocommit=False)
sess = fixture_session(
autoflush=True,
)
u = User(name="ed")
u.addresses.extend(
[Address(email_address=letter) for letter in "abcdef"]
@@ -1029,7 +1033,9 @@ class UOWTest(
User, Address = self._user_address_fixture(
addresses_args={"backref": "user"}
)
sess = fixture_session(autoflush=autoflush, autocommit=False)
sess = fixture_session(
autoflush=autoflush,
)
u = User(name="buffy")
+1 -1
View File
@@ -3239,7 +3239,7 @@ class QueryEventsTest(
):
opts.update(context.execution_options)
sess = fixture_session(autocommit=False)
sess = fixture_session()
sess.query(User).first()
eq_(opts["my_option"], True)
+11 -7
View File
@@ -124,7 +124,7 @@ class ExpireTest(_fixtures.FixtureTest):
users, User = self.tables.users, self.classes.User
self.mapper_registry.map_imperatively(User, users)
s = fixture_session(autocommit=False)
s = fixture_session()
u = s.get(User, 10)
s.expire_all()
@@ -147,7 +147,7 @@ class ExpireTest(_fixtures.FixtureTest):
users, User = self.tables.users, self.classes.User
self.mapper_registry.map_imperatively(User, users)
s = fixture_session(autocommit=False)
s = fixture_session()
u = s.get(User, 10)
s.expire_all()
@@ -162,7 +162,7 @@ class ExpireTest(_fixtures.FixtureTest):
users, User = self.tables.users, self.classes.User
self.mapper_registry.map_imperatively(User, users)
s = fixture_session(autocommit=False)
s = fixture_session()
u = s.get(User, 10)
s.expire_all()
@@ -183,7 +183,7 @@ class ExpireTest(_fixtures.FixtureTest):
users, User = self.tables.users, self.classes.User
self.mapper_registry.map_imperatively(User, users)
s = fixture_session(autocommit=False)
s = fixture_session()
u = s.get(User, 10)
s.expire_all()
s.execute(users.delete().where(User.id == 10))
@@ -240,7 +240,7 @@ class ExpireTest(_fixtures.FixtureTest):
self.mapper_registry.map_imperatively(
User, users, properties={"name": deferred(users.c.name)}
)
s = fixture_session(autocommit=False)
s = fixture_session()
u = s.get(User, 10)
assert "name" not in u.__dict__
@@ -272,7 +272,9 @@ class ExpireTest(_fixtures.FixtureTest):
},
)
self.mapper_registry.map_imperatively(Address, addresses)
s = fixture_session(autoflush=True, autocommit=False)
s = fixture_session(
autoflush=True,
)
u = s.get(User, 8)
adlist = u.addresses
eq_(
@@ -316,7 +318,9 @@ class ExpireTest(_fixtures.FixtureTest):
},
)
self.mapper_registry.map_imperatively(Address, addresses)
s = fixture_session(autoflush=True, autocommit=False)
s = fixture_session(
autoflush=True,
)
u = s.get(User, 8)
assert_raises_message(
sa_exc.InvalidRequestError,
+1 -1
View File
@@ -723,7 +723,7 @@ class MapperTest(_fixtures.FixtureTest, AssertsCompiledSQL):
m.add_property("name", synonym("_name"))
m.add_property("addresses", relationship(Address))
sess = fixture_session(autocommit=False)
sess = fixture_session()
assert sess.get(User, 7)
u = sess.query(User).filter_by(name="jack").one()
+10 -4
View File
@@ -1430,7 +1430,7 @@ class MergeTest(_fixtures.FixtureTest):
self.tables.users,
)
s = fixture_session(autoflush=True, autocommit=False, future=True)
s = fixture_session(autoflush=True, future=True)
self.mapper_registry.map_imperatively(
User,
users,
@@ -1462,7 +1462,9 @@ class MergeTest(_fixtures.FixtureTest):
self.tables.users,
)
sess = fixture_session(autoflush=True, autocommit=False)
sess = fixture_session(
autoflush=True,
)
self.mapper_registry.map_imperatively(
User,
users,
@@ -1503,7 +1505,9 @@ class MergeTest(_fixtures.FixtureTest):
u = User(
id=7, name="fred", addresses=[Address(id=1, email_address="fred1")]
)
sess = fixture_session(autoflush=True, autocommit=False)
sess = fixture_session(
autoflush=True,
)
sess.add(u)
sess.commit()
@@ -1528,7 +1532,9 @@ class MergeTest(_fixtures.FixtureTest):
self.mapper_registry.map_imperatively(User, users)
u = User(id=7)
sess = fixture_session(autoflush=True, autocommit=False)
sess = fixture_session(
autoflush=True,
)
u = sess.merge(u)
assert not bool(attributes.instance_state(u).expired_attributes)
+3 -3
View File
@@ -7303,7 +7303,7 @@ class ExecutionOptionsTest(QueryTest):
def test_option_building(self):
User = self.classes.User
sess = fixture_session(autocommit=False)
sess = fixture_session()
q1 = sess.query(User)
eq_(q1._execution_options, dict())
@@ -7321,7 +7321,7 @@ class ExecutionOptionsTest(QueryTest):
def test_get_options(self):
User = self.classes.User
sess = fixture_session(autocommit=False)
sess = fixture_session()
q = sess.query(User).execution_options(foo="bar", stream_results=True)
eq_(q.get_execution_options(), dict(foo="bar", stream_results=True))
@@ -7341,7 +7341,7 @@ class ExecutionOptionsTest(QueryTest):
result.close()
return iter([])
sess = fixture_session(autocommit=False, query_cls=TQuery)
sess = fixture_session(query_cls=TQuery)
q1 = sess.query(User).execution_options(**execution_options)
q1.all()
+38 -22
View File
@@ -271,7 +271,7 @@ class TransScopingTest(_fixtures.FixtureTest):
conn1 = testing.db.connect()
conn2 = testing.db.connect()
sess = Session(autocommit=False, bind=conn1)
sess = Session(bind=conn1)
u = User(name="x")
sess.add(u)
sess.flush()
@@ -488,6 +488,14 @@ class SessionStateTest(_fixtures.FixtureTest):
s4 = maker2(info={"s4": 8})
eq_(s4.info, {"s4": 8})
def test_autocommit_kw_accepted_but_must_be_false(self):
Session(autocommit=False)
with expect_raises_message(
sa.exc.ArgumentError, "autocommit=True is no longer supported"
):
Session(autocommit=True)
@testing.requires.independent_connections
@engines.close_open_connections
def test_autoflush(self):
@@ -498,7 +506,7 @@ class SessionStateTest(_fixtures.FixtureTest):
conn1 = bind.connect()
conn2 = bind.connect()
sess = Session(bind=conn1, autocommit=False, autoflush=True)
sess = Session(bind=conn1, autoflush=True)
u = User()
u.name = "ed"
sess.add(u)
@@ -640,7 +648,7 @@ class SessionStateTest(_fixtures.FixtureTest):
User, users = self.classes.User, self.tables.users
self.mapper_registry.map_imperatively(User, users)
with fixture_session(autocommit=False, autoflush=True) as sess:
with fixture_session(autoflush=True) as sess:
u = User()
u.name = "ed"
sess.add(u)
@@ -680,7 +688,7 @@ class SessionStateTest(_fixtures.FixtureTest):
self.mapper_registry.map_imperatively(User, users)
conn1 = testing.db.connect()
sess = Session(bind=conn1, autocommit=False, autoflush=True)
sess = Session(bind=conn1, autoflush=True)
u = User()
u.name = "ed"
sess.add(u)
@@ -697,7 +705,9 @@ class SessionStateTest(_fixtures.FixtureTest):
sess.commit()
def test_active_flag_autobegin(self):
sess = Session(bind=config.db, autocommit=False)
sess = Session(
bind=config.db,
)
assert sess.is_active
assert not sess.in_transaction()
sess.begin()
@@ -715,7 +725,9 @@ class SessionStateTest(_fixtures.FixtureTest):
assert sess.is_active
def test_active_flag_partial_rollback(self):
sess = Session(bind=config.db, autocommit=False)
sess = Session(
bind=config.db,
)
assert sess.is_active
assert not sess.in_transaction()
sess.begin()
@@ -1133,7 +1145,9 @@ class DeferredRelationshipExpressionTest(_fixtures.FixtureTest):
"""
User, Address = self.classes("User", "Address")
sess = fixture_session(autoflush=True, autocommit=False)
sess = fixture_session(
autoflush=True,
)
u = User(name="ed", addresses=[Address(email_address="foo")])
sess.add(u)
eq_(
@@ -1144,9 +1158,7 @@ class DeferredRelationshipExpressionTest(_fixtures.FixtureTest):
def test_deferred_expression_obj_was_gced(self):
User, Address = self.classes("User", "Address")
sess = fixture_session(
autoflush=True, autocommit=False, expire_on_commit=False
)
sess = fixture_session(autoflush=True, expire_on_commit=False)
u = User(name="ed", addresses=[Address(email_address="foo")])
sess.add(u)
@@ -1166,9 +1178,7 @@ class DeferredRelationshipExpressionTest(_fixtures.FixtureTest):
User, Address = self.classes("User", "Address")
sess = fixture_session(
autoflush=True, autocommit=False, expire_on_commit=False
)
sess = fixture_session(autoflush=True, expire_on_commit=False)
u = User(name="ed", addresses=[Address(email_address="foo")])
sess.add(u)
sess.commit()
@@ -1181,7 +1191,9 @@ class DeferredRelationshipExpressionTest(_fixtures.FixtureTest):
def test_deferred_expression_obj_was_never_flushed(self):
User, Address = self.classes("User", "Address")
sess = fixture_session(autoflush=True, autocommit=False)
sess = fixture_session(
autoflush=True,
)
u = User(name="ed", addresses=[Address(email_address="foo")])
assert_raises_message(
@@ -1210,7 +1222,9 @@ class DeferredRelationshipExpressionTest(_fixtures.FixtureTest):
def test_deferred_expression_unflushed_obj_became_detached_unexpired(self):
User, Address = self.classes("User", "Address")
sess = fixture_session(autoflush=True, autocommit=False)
sess = fixture_session(
autoflush=True,
)
u = User(name="ed", addresses=[Address(email_address="foo")])
q = sess.query(Address).filter(Address.user == u)
@@ -1224,7 +1238,9 @@ class DeferredRelationshipExpressionTest(_fixtures.FixtureTest):
def test_deferred_expression_unflushed_obj_became_detached_expired(self):
User, Address = self.classes("User", "Address")
sess = fixture_session(autoflush=True, autocommit=False)
sess = fixture_session(
autoflush=True,
)
u = User(name="ed", addresses=[Address(email_address="foo")])
q = sess.query(Address).filter(Address.user == u)
@@ -1239,7 +1255,9 @@ class DeferredRelationshipExpressionTest(_fixtures.FixtureTest):
def test_deferred_expr_unflushed_obj_became_detached_expired_by_key(self):
User, Address = self.classes("User", "Address")
sess = fixture_session(autoflush=True, autocommit=False)
sess = fixture_session(
autoflush=True,
)
u = User(name="ed", addresses=[Address(email_address="foo")])
q = sess.query(Address).filter(Address.user == u)
@@ -1254,9 +1272,7 @@ class DeferredRelationshipExpressionTest(_fixtures.FixtureTest):
def test_deferred_expression_expired_obj_became_detached_expired(self):
User, Address = self.classes("User", "Address")
sess = fixture_session(
autoflush=True, autocommit=False, expire_on_commit=True
)
sess = fixture_session(autoflush=True, expire_on_commit=True)
u = User(name="ed", addresses=[Address(email_address="foo")])
sess.add(u)
@@ -1299,7 +1315,7 @@ class SessionStateWFixtureTest(_fixtures.FixtureTest):
User, users, properties={"addresses": relationship(Address)}
)
sess = fixture_session(autocommit=False, autoflush=True)
sess = fixture_session(autoflush=True)
u = sess.get(User, 8)
newad = Address(email_address="a new address")
u.addresses.append(newad)
@@ -1891,7 +1907,7 @@ class DisposedStates(fixtures.MappedTest):
self._test_session().expire_all()
def test_rollback(self):
sess = self._test_session(autocommit=False, expire_on_commit=True)
sess = self._test_session(expire_on_commit=True)
sess.commit()
sess.rollback()
+16 -16
View File
@@ -79,7 +79,7 @@ class SessionTransactionTest(fixtures.RemovesEvents, FixtureTest):
self.mapper_registry.map_imperatively(User, users)
trans = conn.begin()
sess = Session(bind=conn, autocommit=False, autoflush=True)
sess = Session(bind=conn, autoflush=True)
u = User(name="ed")
sess.add(u)
sess.flush()
@@ -94,7 +94,7 @@ class SessionTransactionTest(fixtures.RemovesEvents, FixtureTest):
self.mapper_registry.map_imperatively(User, users)
trans = conn.begin()
sess = Session(bind=conn, autocommit=False, autoflush=True)
sess = Session(bind=conn, autoflush=True)
u1 = User(name="u1")
sess.add(u1)
sess.flush()
@@ -116,7 +116,7 @@ class SessionTransactionTest(fixtures.RemovesEvents, FixtureTest):
conn = future_conn
conn.begin()
sess = Session(bind=conn, autocommit=False, autoflush=True)
sess = Session(bind=conn, autoflush=True)
u = User(name="ed")
sess.add(u)
sess.flush()
@@ -133,7 +133,7 @@ class SessionTransactionTest(fixtures.RemovesEvents, FixtureTest):
conn = future_conn
conn.begin()
sess = Session(bind=conn, autocommit=False, autoflush=True)
sess = Session(bind=conn, autoflush=True)
u = User(name="ed")
sess.add(u)
sess.flush()
@@ -150,7 +150,7 @@ class SessionTransactionTest(fixtures.RemovesEvents, FixtureTest):
conn = future_conn
conn.begin()
sess = Session(bind=conn, autocommit=False, autoflush=True)
sess = Session(bind=conn, autoflush=True)
u1 = User(name="u1")
sess.add(u1)
sess.flush()
@@ -264,8 +264,8 @@ class SessionTransactionTest(fixtures.RemovesEvents, FixtureTest):
self.mapper_registry.map_imperatively(User, users)
s1 = fixture_session(autocommit=False)
s2 = fixture_session(autocommit=False)
s1 = fixture_session()
s2 = fixture_session()
u1 = User(name="u1")
s1.add(u1)
s1.flush()
@@ -359,7 +359,7 @@ class SessionTransactionTest(fixtures.RemovesEvents, FixtureTest):
User, users = self.classes.User, self.tables.users
self.mapper_registry.map_imperatively(User, users)
sess = fixture_session(autocommit=False)
sess = fixture_session()
u = User(name="u1")
sess.add(u)
sess.flush()
@@ -381,7 +381,7 @@ class SessionTransactionTest(fixtures.RemovesEvents, FixtureTest):
User, users = self.classes.User, self.tables.users
self.mapper_registry.map_imperatively(User, users)
sess = fixture_session(autocommit=False, future=True)
sess = fixture_session(future=True)
u = User(name="u1")
sess.add(u)
sess.flush()
@@ -441,7 +441,7 @@ class SessionTransactionTest(fixtures.RemovesEvents, FixtureTest):
self.mapper_registry.map_imperatively(User, users)
sess = fixture_session(autocommit=False)
sess = fixture_session()
sess.begin_nested()
@@ -557,7 +557,7 @@ class SessionTransactionTest(fixtures.RemovesEvents, FixtureTest):
)
def test_no_sql_during_commit(self):
sess = fixture_session(autocommit=False)
sess = fixture_session()
@event.listens_for(sess, "after_commit")
def go(session):
@@ -571,7 +571,7 @@ class SessionTransactionTest(fixtures.RemovesEvents, FixtureTest):
)
def test_no_sql_during_prepare(self):
sess = fixture_session(autocommit=False, twophase=True)
sess = fixture_session(twophase=True)
sess.prepare()
@@ -584,7 +584,7 @@ class SessionTransactionTest(fixtures.RemovesEvents, FixtureTest):
)
def test_no_sql_during_rollback(self):
sess = fixture_session(autocommit=False)
sess = fixture_session()
sess.connection()
@@ -666,7 +666,7 @@ class SessionTransactionTest(fixtures.RemovesEvents, FixtureTest):
eq_(session.is_active, True)
def test_no_prepare_wo_twophase(self):
sess = fixture_session(autocommit=False)
sess = fixture_session()
assert_raises_message(
sa_exc.InvalidRequestError,
@@ -843,7 +843,7 @@ class SessionTransactionTest(fixtures.RemovesEvents, FixtureTest):
User, users = self.classes.User, self.tables.users
self.mapper_registry.map_imperatively(User, users)
session = fixture_session(autocommit=False)
session = fixture_session()
session.add(User(name="ed"))
session._legacy_transaction().commit()
@@ -853,7 +853,7 @@ class SessionTransactionTest(fixtures.RemovesEvents, FixtureTest):
User, users = self.classes.User, self.tables.users
self.mapper_registry.map_imperatively(User, users)
session = fixture_session(autocommit=False, future=True)
session = fixture_session(future=True)
session.add(User(name="ed"))
session._legacy_transaction().commit()
+5 -5
View File
@@ -69,7 +69,7 @@ class HistoryTest(_fixtures.FixtureTest):
),
)
session = fixture_session(autocommit=False)
session = fixture_session()
u = User(name="u1")
a = Address(email_address="u1@e")
@@ -128,7 +128,7 @@ class UnicodeTest(fixtures.MappedTest):
t1 = Test(id=1, txt=txt)
self.assert_(t1.txt == txt)
session = fixture_session(autocommit=False)
session = fixture_session()
session.add(t1)
session.commit()
@@ -151,7 +151,7 @@ class UnicodeTest(fixtures.MappedTest):
t1 = Test(txt=txt)
t1.t2s.append(Test2())
t1.t2s.append(Test2())
session = fixture_session(autocommit=False, expire_on_commit=False)
session = fixture_session(expire_on_commit=False)
session.add(t1)
session.commit()
session.close()
@@ -1151,7 +1151,7 @@ class DefaultTest(fixtures.MappedTest):
h4 = Hoho()
h5 = Hoho(foober="im the new foober")
session = fixture_session(autocommit=False, expire_on_commit=False)
session = fixture_session(expire_on_commit=False)
session.add_all((h1, h2, h3, h4, h5))
session.commit()
@@ -2013,7 +2013,7 @@ class SaveTest(_fixtures.FixtureTest):
# don't set deferred attribute, commit session
o = Order(id=42)
session = fixture_session(autocommit=False)
session = fixture_session()
session.add(o)
session.commit()
+1 -1
View File
@@ -1596,7 +1596,7 @@ class RowswitchAccountingTest(fixtures.MappedTest):
def test_switch_on_update(self):
Parent, Child = self._fixture()
sess = fixture_session(autocommit=False)
sess = fixture_session()
p1 = Parent(id=1, child=Child())
sess.add(p1)
+5 -5
View File
@@ -212,7 +212,7 @@ class VersioningTest(fixtures.MappedTest):
):
s1.commit()
s2 = fixture_session(autocommit=False)
s2 = fixture_session()
f1_s = s2.get(Foo, f1.id)
f1_s.value = "f1rev3"
with conditional_sane_rowcount_warnings(
@@ -372,7 +372,7 @@ class VersioningTest(fixtures.MappedTest):
s1.add(f1s1)
s1.commit()
s2 = fixture_session(autocommit=False)
s2 = fixture_session()
f1s2 = s2.get(Foo, f1s1.id)
f1s2.value = "f1 new value"
with conditional_sane_rowcount_warnings(
@@ -428,7 +428,7 @@ class VersioningTest(fixtures.MappedTest):
s1.add(f1s1)
s1.commit()
s2 = fixture_session(autocommit=False)
s2 = fixture_session()
f1s2 = s2.get(Foo, f1s1.id)
# not sure if I like this API
s2.refresh(f1s2, with_for_update=True)
@@ -505,13 +505,13 @@ class VersioningTest(fixtures.MappedTest):
Foo, version_table = self.classes.Foo, self.tables.version_table
s1 = fixture_session(autocommit=False)
s1 = fixture_session()
self.mapper_registry.map_imperatively(Foo, version_table)
f1s1 = Foo(value="foo", version_id=0)
s1.add(f1s1)
s1.commit()
s2 = fixture_session(autocommit=False)
s2 = fixture_session()
f1s2 = (
s2.query(Foo)
.with_for_update(read=True)