def _do_enter(cls, state, decorator_args):
        _init_storage()

        mandatory = decorator_args.get("mandatory", False)
        independent = decorator_args.get("independent", False)
        read_only = decorator_args.get("read_only", False)
        using = decorator_args.get("using", "default")

        mandatory = False if mandatory is None else mandatory
        independent = False if independent is None else independent
        read_only = False if read_only is None else read_only
        state.using = using = "default" if using is None else using

        enable_cache = decorator_args.get("enable_cache", True)
        context = caching.get_context()
        state.original_context_enabled = context.context_enabled

        # Only force-disable cache, do not force enable (e.g. if already disabled
        # in the context, leave as is)
        if enable_cache is False:
            context.context_enabled = enable_cache

        new_transaction = None

        connection = connections[using]

        # Connect if necessary (mainly in tests)
        if not connection.connection:
            connection.connect()

        connection = connection.connection
        assert (connection)

        if independent:
            new_transaction = IndependentTransaction(connection)
        elif in_atomic_block():
            new_transaction = NestedTransaction(connection)
        elif mandatory:
            raise TransactionFailedError(
                "You've specified that an outer transaction is mandatory, but one doesn't exist"
            )
        else:
            new_transaction = NormalTransaction(connection)

        _STORAGE.transaction_stack.setdefault(using,
                                              []).append(new_transaction)
        _STORAGE.transaction_stack[using][-1].enter()

        if isinstance(new_transaction,
                      (IndependentTransaction, NormalTransaction)):
            caching.get_context().stack.push()

        # We may have created a new transaction, we may not. current_transaction() returns
        # the actual active transaction (highest NormalTransaction or lowest IndependentTransaction)
        # or None if we're in a non_atomic, or there are no transactions
        return current_transaction()
    def _do_enter(cls, state, decorator_args):
        _init_storage()

        context = caching.get_context()

        state.using = using = decorator_args.get("using", "default")
        connection = connections[using]

        # Connect if necessary (mainly in tests)
        if not connection.connection:
            connection.connect()

        connection = connection.connection
        assert (connection)

        # For non_atomic blocks we pass a Batch as the transaction
        new_transaction = NoTransaction(connection.gclient.batch())

        _STORAGE.transaction_stack.setdefault(using,
                                              []).append(new_transaction)
        _STORAGE.transaction_stack[using][-1].enter()

        # Store the current state of the stack (aside from the first entry)
        state.original_stack = copy.deepcopy(context.stack.stack[1:])

        # Unwind the in-context stack leaving just the first entry
        while len(context.stack.stack) > 1:
            context.stack.pop(discard=True)

        return current_transaction()
    def _do_exit(cls, state, decorator_args, exception):
        _init_storage()

        transaction = _STORAGE.transaction_stack[state.using].pop()

        try:
            if transaction._datastore_transaction:
                if exception:
                    transaction._datastore_transaction.rollback()
                else:
                    try:
                        transaction._datastore_transaction.commit()
                    except exceptions.GoogleCloudError:
                        raise TransactionFailedError()
        finally:
            if isinstance(transaction,
                          (IndependentTransaction, NormalTransaction)):
                context = caching.get_context()

                # Clear the context cache at the end of a transaction
                if exception:
                    context.stack.pop(discard=True)
                else:
                    context.stack.pop(apply_staged=True, clear_staged=True)

            transaction.exit()
    def _do_exit(cls, state, decorator_args, exception):
        _init_storage()

        context = caching.get_context()

        transaction = _STORAGE.transaction_stack[state.using].pop()

        try:
            if transaction._datastore_transaction:
                if exception:
                    transaction._datastore_transaction.rollback()
                else:
                    try:
                        transaction._datastore_transaction.commit()
                    except exceptions.GoogleAPIError:
                        raise TransactionFailedError()
        finally:
            # Restore the context stack as it was
            context.stack.stack = context.stack.stack + state.original_stack
            transaction.exit()
 def __enter__(self):
     self.context = caching.get_context()
     self.context.context_enabled = False
     return self