Beispiel #1
0
    def __enter__(self):

        connection = transaction.get_connection(self.using)

        cache = get_cache(OUTER_ATOMIC_CACHE_NAME)

        # By default it is enabled.
        enable = True
        # If name is set it is only enabled if requested by calling enable_named_outer_atomic().
        if self.name:
            enable = cache.get(self.name, False)

        if enable:
            # TestCase setup nests tests in two atomics - one for the test class and one for the individual test.
            # The outermost atomic starts a transaction - so does not have a savepoint.
            # The inner atomic starts a savepoint around the test.
            # So, for tests only, there should be exactly one savepoint_id and two atomic_for_testcase_calls.
            # atomic_for_testcase_calls below is added in a monkey-patch for tests only.
            if self.ALLOW_NESTED and (self.atomic_for_testcase_calls - len(connection.savepoint_ids)) < 1:  # lint-amnesty, pylint: disable=no-member
                raise transaction.TransactionManagementError('Cannot be inside an atomic block.')

            # Otherwise, this shouldn't be nested in any atomic block.
            if not self.ALLOW_NESTED and connection.in_atomic_block:
                raise transaction.TransactionManagementError('Cannot be inside an atomic block.')

        super().__enter__()
Beispiel #2
0
    def __enter__(self):

        connection = transaction.get_connection(self.using)

        # TestCase setup nests tests in two atomics - one for the test class and one for the individual test.
        # The outermost atomic starts a transaction - so does not have a savepoint.
        # The inner atomic starts a savepoint around the test.
        # So, for tests only, there should be exactly one savepoint_id and two atomic_for_testcase_calls.
        # atomic_for_testcase_calls below is added in a monkey-patch for tests only.
        if self.ALLOW_NESTED and (self.atomic_for_testcase_calls -
                                  len(connection.savepoint_ids)) < 1:
            raise transaction.TransactionManagementError(
                'Cannot be inside an atomic block.')

        # Otherwise, this shouldn't be nested in any atomic block.
        if not self.ALLOW_NESTED and connection.in_atomic_block:
            raise transaction.TransactionManagementError(
                'Cannot be inside an atomic block.')

        # 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")

        super(OuterAtomic, self).__enter__()
Beispiel #3
0
    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
Beispiel #4
0
    def testTearDown(cls):
        transaction.rollback()
        transaction.leave_transaction_management()

        try:
            transaction.leave_transaction_management()
        except transaction.TransactionManagementError:
            pass
        else:
            raise transaction.TransactionManagementError(
                "Call to enter_transaction_management must "
                "have a matching call to leave_transaction_management")
Beispiel #5
0
    def __enter__(self):

        connection = transaction.get_connection(self.using)

        cache = get_cache(OUTER_ATOMIC_CACHE_NAME)

        # By default it is enabled.
        enable = True
        # If name is set it is only enabled if requested by calling enable_named_outer_atomic().
        if self.name:
            enable = cache.get(self.name, False)

        if enable:
            # TestCase setup nests tests in two atomics - one for the test class and one for the individual test.
            # The outermost atomic starts a transaction - so does not have a savepoint.
            # The inner atomic starts a savepoint around the test.
            # So, for tests only, there should be exactly one savepoint_id and two atomic_for_testcase_calls.
            # atomic_for_testcase_calls below is added in a monkey-patch for tests only.
            if self.ALLOW_NESTED and (self.atomic_for_testcase_calls -
                                      len(connection.savepoint_ids)) < 1:  # lint-amnesty, pylint: disable=no-member
                raise transaction.TransactionManagementError(
                    'Cannot be inside an atomic block.')

            # Otherwise, this shouldn't be nested in any atomic block.
            if not self.ALLOW_NESTED and connection.in_atomic_block:
                raise transaction.TransactionManagementError(
                    'Cannot be inside an atomic block.')

            # 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")

        super(OuterAtomic, self).__enter__()  # lint-amnesty, pylint: disable=super-with-arguments
Beispiel #6
0
    def wrapper(*args, **kwargs):  # pylint: disable=missing-docstring

        if connection.vendor == 'mysql':
            # The isolation level cannot be changed while a transaction is in progress. So we close any existing one.
            if connection.transaction_state:
                if len(connection.transaction_state) == 1:
                    connection.commit()
                # We can commit all open transactions. But it does not seem like a good idea.
                elif len(connection.transaction_state) > 1:
                    raise transaction.TransactionManagementError('Cannot change isolation level. '
                                                                 'More than 1 level of nested transactions.')

            # This will set the transaction isolation level to READ COMMITTED for the next transaction.
            cursor = connection.cursor()
            cursor.execute("SET TRANSACTION ISOLATION LEVEL READ COMMITTED")

        with transaction.commit_on_success():
            return func(*args, **kwargs)