Removed unused commit_on_success decorator and its tests
This commit is contained in:
@@ -18,136 +18,6 @@ OUTER_ATOMIC_CACHE_NAME = 'db.outer_atomic'
|
||||
MYSQL_MAX_INT = (2 ** 31) - 1
|
||||
|
||||
|
||||
class CommitOnSuccessManager(object):
|
||||
"""
|
||||
This class implements the commit_on_success() API that was available till Django 1.5.
|
||||
|
||||
An instance can be used either as a decorator or as a context manager. However, it
|
||||
cannot be nested inside an atomic block.
|
||||
|
||||
It is mostly taken from https://github.com/django/django/blob/1.8.5/django/db/transaction.py#L110-L277
|
||||
but instead of using save points commits all pending queries at the end of a block.
|
||||
|
||||
The goal is to behave as close as possible to:
|
||||
https://github.com/django/django/blob/1.4.22/django/db/transaction.py#L263-L289
|
||||
"""
|
||||
|
||||
# Tests in TestCase subclasses are wrapped in an atomic block to speed up database restoration.
|
||||
# So we must disabled this manager.
|
||||
# https://github.com/django/django/blob/1.8.5/django/core/handlers/base.py#L129-L132
|
||||
ENABLED = True
|
||||
|
||||
def __init__(self, using, read_committed=False):
|
||||
self.using = using
|
||||
self.read_committed = read_committed
|
||||
|
||||
def __enter__(self):
|
||||
|
||||
if not self.ENABLED:
|
||||
return
|
||||
|
||||
connection = transaction.get_connection(self.using)
|
||||
|
||||
if connection.in_atomic_block:
|
||||
raise transaction.TransactionManagementError('Cannot be inside an atomic block.')
|
||||
|
||||
if getattr(connection, 'commit_on_success_block_level', 0) == 0:
|
||||
connection.commit_on_success_block_level = 1
|
||||
|
||||
# This will set the transaction isolation level to READ COMMITTED for the next transaction.
|
||||
if self.read_committed is True:
|
||||
if connection.vendor == 'mysql':
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("SET TRANSACTION ISOLATION LEVEL READ COMMITTED")
|
||||
|
||||
# We aren't in a transaction yet; create one.
|
||||
# The usual way to start a transaction is to turn autocommit off.
|
||||
# However, some database adapters (namely sqlite3) don't handle
|
||||
# transactions and savepoints properly when autocommit is off.
|
||||
# In such cases, start an explicit transaction instead, which has
|
||||
# the side-effect of disabling autocommit.
|
||||
if connection.features.autocommits_when_autocommit_is_off:
|
||||
connection._start_transaction_under_autocommit() # pylint: disable=protected-access
|
||||
connection.autocommit = False
|
||||
else:
|
||||
connection.set_autocommit(False)
|
||||
else:
|
||||
if self.read_committed is True:
|
||||
raise transaction.TransactionManagementError('Cannot change isolation level when nested.')
|
||||
|
||||
connection.commit_on_success_block_level += 1
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
|
||||
if not self.ENABLED:
|
||||
return
|
||||
|
||||
connection = transaction.get_connection(self.using)
|
||||
|
||||
try:
|
||||
if exc_type is None:
|
||||
# Commit transaction
|
||||
try:
|
||||
connection.commit()
|
||||
except DatabaseError:
|
||||
try:
|
||||
connection.rollback()
|
||||
except Error:
|
||||
# An error during rollback means that something
|
||||
# went wrong with the connection. Drop it.
|
||||
connection.close()
|
||||
raise
|
||||
else:
|
||||
# Roll back transaction
|
||||
try:
|
||||
connection.rollback()
|
||||
except Error:
|
||||
# An error during rollback means that something
|
||||
# went wrong with the connection. Drop it.
|
||||
connection.close()
|
||||
|
||||
finally:
|
||||
connection.commit_on_success_block_level -= 1
|
||||
|
||||
# Outermost block exit when autocommit was enabled.
|
||||
if connection.commit_on_success_block_level == 0:
|
||||
if connection.features.autocommits_when_autocommit_is_off:
|
||||
connection.autocommit = True
|
||||
else:
|
||||
connection.set_autocommit(True)
|
||||
|
||||
def __call__(self, func):
|
||||
@wraps(func)
|
||||
def decorated(*args, **kwds): # pylint: disable=missing-docstring
|
||||
with self:
|
||||
return func(*args, **kwds)
|
||||
return decorated
|
||||
|
||||
|
||||
def commit_on_success(using=None, read_committed=False):
|
||||
"""
|
||||
This function implements the commit_on_success() API that was available till Django 1.5.
|
||||
|
||||
It can be used either as a decorator or as a context manager. However, it
|
||||
cannot be nested inside an atomic block.
|
||||
|
||||
If the wrapped function or block returns a response the transaction is committed
|
||||
and if it raises an exception the transaction is rolled back.
|
||||
|
||||
Arguments:
|
||||
using (str): the name of the database.
|
||||
read_committed (bool): Whether to use read committed isolation level.
|
||||
|
||||
Raises:
|
||||
TransactionManagementError: if already inside an atomic block.
|
||||
"""
|
||||
if callable(using):
|
||||
return CommitOnSuccessManager(DEFAULT_DB_ALIAS, read_committed)(using)
|
||||
# Decorator: @commit_on_success(...) or context manager: with commit_on_success(...): ...
|
||||
else:
|
||||
return CommitOnSuccessManager(using, read_committed)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def enable_named_outer_atomic(*names):
|
||||
"""
|
||||
|
||||
@@ -12,7 +12,7 @@ from django.test import TestCase
|
||||
from django.urls import clear_url_caches, resolve
|
||||
from mock import patch
|
||||
|
||||
from util.db import CommitOnSuccessManager, OuterAtomic
|
||||
from util.db import OuterAtomic
|
||||
|
||||
if six.PY3:
|
||||
from importlib import reload # pylint: disable=no-name-in-module,redefined-builtin
|
||||
@@ -156,7 +156,6 @@ def patch_testcase():
|
||||
"""
|
||||
Method that performs atomic-entering accounting.
|
||||
"""
|
||||
CommitOnSuccessManager.ENABLED = False
|
||||
OuterAtomic.ALLOW_NESTED = True
|
||||
if not hasattr(OuterAtomic, 'atomic_for_testcase_calls'):
|
||||
OuterAtomic.atomic_for_testcase_calls = 0
|
||||
@@ -174,7 +173,6 @@ def patch_testcase():
|
||||
"""
|
||||
Method that performs atomic-rollback accounting.
|
||||
"""
|
||||
CommitOnSuccessManager.ENABLED = True
|
||||
OuterAtomic.ALLOW_NESTED = False
|
||||
OuterAtomic.atomic_for_testcase_calls -= 1
|
||||
return wrapped_func(*args, **kwargs)
|
||||
|
||||
@@ -15,7 +15,7 @@ from django.test.utils import override_settings
|
||||
from django.utils.six import StringIO
|
||||
from six.moves import range
|
||||
|
||||
from util.db import commit_on_success, enable_named_outer_atomic, generate_int_id, outer_atomic
|
||||
from util.db import enable_named_outer_atomic, generate_int_id, outer_atomic
|
||||
|
||||
|
||||
def do_nothing():
|
||||
@@ -26,7 +26,7 @@ def do_nothing():
|
||||
@ddt.ddt
|
||||
class TransactionManagersTestCase(TransactionTestCase):
|
||||
"""
|
||||
Tests commit_on_success and outer_atomic.
|
||||
Tests outer_atomic.
|
||||
|
||||
Note: This TestCase only works with MySQL.
|
||||
|
||||
@@ -35,15 +35,11 @@ class TransactionManagersTestCase(TransactionTestCase):
|
||||
DECORATORS = {
|
||||
'outer_atomic': outer_atomic(),
|
||||
'outer_atomic_read_committed': outer_atomic(read_committed=True),
|
||||
'commit_on_success': commit_on_success(),
|
||||
'commit_on_success_read_committed': commit_on_success(read_committed=True),
|
||||
}
|
||||
|
||||
@ddt.data(
|
||||
('outer_atomic', IntegrityError, None, True),
|
||||
('outer_atomic_read_committed', type(None), False, True),
|
||||
('commit_on_success', IntegrityError, None, True),
|
||||
('commit_on_success_read_committed', type(None), False, True),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_concurrent_requests(self, transaction_decorator_name, exception_class, created_in_1, created_in_2):
|
||||
@@ -120,27 +116,6 @@ class TransactionManagersTestCase(TransactionTestCase):
|
||||
with outer_atomic():
|
||||
outer_atomic()(do_nothing)()
|
||||
|
||||
def test_commit_on_success_nesting(self):
|
||||
"""
|
||||
Test that commit_on_success raises an error if it is nested inside
|
||||
atomic or if the isolation level is changed when it is nested
|
||||
inside another commit_on_success.
|
||||
"""
|
||||
# pylint: disable=not-callable
|
||||
|
||||
if connection.vendor != 'mysql':
|
||||
raise unittest.SkipTest('Only works on MySQL.')
|
||||
|
||||
commit_on_success(read_committed=True)(do_nothing)()
|
||||
|
||||
with self.assertRaisesRegex(TransactionManagementError, 'Cannot change isolation level when nested.'):
|
||||
with commit_on_success():
|
||||
commit_on_success(read_committed=True)(do_nothing)()
|
||||
|
||||
with self.assertRaisesRegex(TransactionManagementError, 'Cannot be inside an atomic block.'):
|
||||
with atomic():
|
||||
commit_on_success(read_committed=True)(do_nothing)()
|
||||
|
||||
def test_named_outer_atomic_nesting(self):
|
||||
"""
|
||||
Test that a named outer_atomic raises an error only if nested in
|
||||
|
||||
Reference in New Issue
Block a user