skip to Main Content

I am very fond of the returns library in python, and I would like to use it more. I have a little issue right now. Currently, I have a function that uses a redis client and gets the value corresponding to a key, like so:

from redis import Redis
from returns.context import RequiresContext


def get_value(key: str) -> RequiresContext[str, Redis]:
    def inner(client: Redis) -> str:
        value = client.get(key)
        return value.decode("utf-8")

    return RequiresContext(inner)

Obviously, that function works like a charm:

with Redis(
        host=redis_host,
        port=redis_port,
        password=redis_password,
    ) as redis_client:
        value = get_value(key="my-key")(redis_client)
        print("value = ", value)

Now, I would like to use the asyncio pendant of that code, i.e. use the redis.asyncio.Redis. Unfortunately, it looks like things become a bit more complicated in that case. I should probably switch from RequiresContext to RequiresContextFutureResultE, but I was not able to find a working solution. Here’s the best code I was able to come up with:

async def get_value(key: str) -> RequiresContextFutureResultE[str, Redis]:
    async def inner(client: Redis) -> FutureResultE[str]:
        value = await client.get(key)
        return FutureResult.from_value(value.decode("utf-8"))

    return RequiresContextFutureResultE(inner)

When I run it like this:

async def main():
    async with Redis(
        host="localhost",
        port=6379,
        password="902nks291",
        db=15,
    ) as redis_client:
        rcfr = get_value(key="user-id")
        value = await rcfr(redis_client)
        print("value: ", value)

asyncio.run(main())

I get the error that rcfr is not a callable. Can someone help me figure out how I should fix my code to make it work the way I want?

2

Answers


  1. Chosen as BEST ANSWER

    Based on the advice of @mkrieger1 and @sobolevn, here's the fixed code:

    from redis.asyncio.client import Redis
    from returns.context import RequiresContext, RequiresContextFutureResultE, RequiresContextFutureResult
    import asyncio
    from returns.result import ResultE
    from returns.future import FutureResult, FutureResultE
    
    def get_value(key: str) -> RequiresContextFutureResultE[str, Redis]:
        async def inner(client: Redis) -> FutureResultE[str]:
            value = await client.get(key)
            return FutureResult.from_value(value.decode("utf-8"))
    
        return RequiresContextFutureResultE(inner)
        
    async def main():
        async with Redis(
            host="localhost",
            port=6379,
            password="902nks291",
            db=15,
        ) as redis_client:
            value = await get_value(key="user-id")(redis_client)
            print("value: ", value)
            
    asyncio.run(main())
    

  2. If you call a function (get_value) defined with async def you get an awaitable which you must use with await to get its return value. That’s why you get the error.

    But get_value shouldn’t be async def. It just defines and returns a function (wrapped by RequiresContextFutureResultE), it doesn’t perform any IO itself.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search