# Path: aredis/exceptions.py
# class RedisClusterException(Exception):
#     pass
# 
# class WatchError(RedisError):
#     pass
# 
# Path: aredis/utils.py
# def string_keys_to_dict(key_string, callback):
#     return dict.fromkeys(key_string.split(), callback)
# 
# def bool_ok(response):
#     return nativestr(response) == 'OK'


import asyncio
import warnings
from aredis.exceptions import (RedisClusterException,
                               WatchError)
from aredis.utils import (string_keys_to_dict,
                          bool_ok)


class TransactionCommandMixin:

    RESPONSE_CALLBACKS = string_keys_to_dict(
            'WATCH UNWATCH',
            bool_ok
        )

    async def transaction(self, func, *watches, **kwargs):
        """
        Convenience method for executing the callable `func` as a transaction
        while watching all keys specified in `watches`. The 'func' callable
        should expect a single argument which is a Pipeline object.
        """
        shard_hint = kwargs.pop('shard_hint', None)
        value_from_callable = kwargs.pop('value_from_callable', False)
        watch_delay = kwargs.pop('watch_delay', None)
        async with await self.pipeline(True, shard_hint) as pipe:
            while True:
                try:
                    if watches:
                        await pipe.watch(*watches)
                    func_value = await func(pipe)
                    exec_value = await pipe.execute()
                    return func_value if value_from_callable else exec_value

# Path: aredis/exceptions.py
# class RedisClusterException(Exception):
#     pass
# 
# class WatchError(RedisError):
#     pass
# 
# Path: aredis/utils.py
# def string_keys_to_dict(key_string, callback):
#     return dict.fromkeys(key_string.split(), callback)
# 
# def bool_ok(response):
#     return nativestr(response) == 'OK'


# Path: aredis/commands/transaction.py
import asyncio
import warnings
from aredis.exceptions import (RedisClusterException,
                               WatchError)
from aredis.utils import (string_keys_to_dict,
                          bool_ok)



class TransactionCommandMixin:

    RESPONSE_CALLBACKS = string_keys_to_dict(
            'WATCH UNWATCH',
            bool_ok
        )

    async def transaction(self, func, *watches, **kwargs):
        """
        Convenience method for executing the callable `func` as a transaction
        while watching all keys specified in `watches`. The 'func' callable
        should expect a single argument which is a Pipeline object.
        """
        shard_hint = kwargs.pop('shard_hint', None)
        value_from_callable = kwargs.pop('value_from_callable', False)
        watch_delay = kwargs.pop('watch_delay', None)
        async with await self.pipeline(True, shard_hint) as pipe:
            while True:
                try:
                    if watches:
                        await pipe.watch(*watches)
                    func_value = await func(pipe)
                    exec_value = await pipe.execute()
                    return func_value if value_from_callable else exec_value

                except WatchError: