From: Mike Bayer Date: Sun, 31 Oct 2021 00:45:26 +0000 (-0400) Subject: remove ORM autocommit and public-facing subtransactions concept X-Git-Tag: rel_2_0_0b1~688 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cdce33e2ccb60365f12eb07c0b86fdc2b89b5033;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git 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 --- diff --git a/doc/build/orm/session_basics.rst b/doc/build/orm/session_basics.rst index 529f786c1a..a4faed69db 100644 --- a/doc/build/orm/session_basics.rst +++ b/doc/build/orm/session_basics.rst @@ -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 `_ 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 --------------------- diff --git a/doc/build/orm/session_transaction.rst b/doc/build/orm/session_transaction.rst index 6d7c4dd18e..199e76b43c 100644 --- a/doc/build/orm/session_transaction.rst +++ b/doc/build/orm/session_transaction.rst @@ -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: diff --git a/lib/sqlalchemy/orm/__init__.py b/lib/sqlalchemy/orm/__init__.py index bdc5cbf674..c49ff4ec64 100644 --- a/lib/sqlalchemy/orm/__init__.py +++ b/lib/sqlalchemy/orm/__init__.py @@ -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) diff --git a/lib/sqlalchemy/orm/loading.py b/lib/sqlalchemy/orm/loading.py index bbad98144d..d004db0a3b 100644 --- a/lib/sqlalchemy/orm/loading.py +++ b/lib/sqlalchemy/orm/loading.py @@ -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 diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index bb12f7021d..415826e5f4 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -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 diff --git a/test/ext/test_horizontal_shard.py b/test/ext/test_horizontal_shard.py index a269b8bcba..edc2711b6f 100644 --- a/test/ext/test_horizontal_shard.py +++ b/test/ext/test_horizontal_shard.py @@ -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, diff --git a/test/orm/test_cycles.py b/test/orm/test_cycles.py index 9d0369191e..15155293fa 100644 --- a/test/orm/test_cycles.py +++ b/test/orm/test_cycles.py @@ -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() diff --git a/test/orm/test_deprecations.py b/test/orm/test_deprecations.py index 692a29b306..fc2bc5b931 100644 --- a/test/orm/test_deprecations.py +++ b/test/orm/test_deprecations.py @@ -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" diff --git a/test/orm/test_dynamic.py b/test/orm/test_dynamic.py index 8efd452382..e037ef1918 100644 --- a/test/orm/test_dynamic.py +++ b/test/orm/test_dynamic.py @@ -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") diff --git a/test/orm/test_events.py b/test/orm/test_events.py index 4dfea6a6de..39d1e8ad96 100644 --- a/test/orm/test_events.py +++ b/test/orm/test_events.py @@ -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) diff --git a/test/orm/test_expire.py b/test/orm/test_expire.py index 5a12a7da4b..ae7ac010b5 100644 --- a/test/orm/test_expire.py +++ b/test/orm/test_expire.py @@ -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, diff --git a/test/orm/test_mapper.py b/test/orm/test_mapper.py index 0f84923ac8..33939e3d82 100644 --- a/test/orm/test_mapper.py +++ b/test/orm/test_mapper.py @@ -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() diff --git a/test/orm/test_merge.py b/test/orm/test_merge.py index d2eade0ea1..bc79140278 100644 --- a/test/orm/test_merge.py +++ b/test/orm/test_merge.py @@ -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) diff --git a/test/orm/test_query.py b/test/orm/test_query.py index c567cf1d16..29ba24b1bf 100644 --- a/test/orm/test_query.py +++ b/test/orm/test_query.py @@ -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() diff --git a/test/orm/test_session.py b/test/orm/test_session.py index 4ee71fd5ba..e31acf0246 100644 --- a/test/orm/test_session.py +++ b/test/orm/test_session.py @@ -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() diff --git a/test/orm/test_transaction.py b/test/orm/test_transaction.py index f0ef37230c..b7062cf427 100644 --- a/test/orm/test_transaction.py +++ b/test/orm/test_transaction.py @@ -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() diff --git a/test/orm/test_unitofwork.py b/test/orm/test_unitofwork.py index 7b7cb0db6f..627fbc853e 100644 --- a/test/orm/test_unitofwork.py +++ b/test/orm/test_unitofwork.py @@ -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() diff --git a/test/orm/test_unitofworkv2.py b/test/orm/test_unitofworkv2.py index af38a4bab0..430f1d005b 100644 --- a/test/orm/test_unitofworkv2.py +++ b/test/orm/test_unitofworkv2.py @@ -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) diff --git a/test/orm/test_versioning.py b/test/orm/test_versioning.py index 45fad9ab74..0d11f68a7d 100644 --- a/test/orm/test_versioning.py +++ b/test/orm/test_versioning.py @@ -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)