vutran1710/PyrateLimiter

The "Delay not integer" error is confusing and descriptiveness

Opened this issue · 1 comments

Reproducible example

import os 
import asyncio
import logging

from redis.asyncio import Redis as AsyncRedis
from pyrate_limiter import Duration, Rate, Limiter, RedisBucket

async_redis = AsyncRedis(
        host=os.environ["REDIS_HOST"],
        port=int(os.environ["REDIS_PORT"]),
        password=os.environ["REDIS_PASSWORD"],
        decode_responses=True,
        socket_keepalive=True,
        protocol=3,
    )


logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.DEBUG)

rate = Rate(1, Duration.SECOND)


class Example:
    
    def __init__(self, limiter):
        self.limiter = limiter
        
    async def func(self) -> None:        
        await self.limiter.try_acquire("test")  # After reading the docs, I am not sure what I need to put here.
        # No errors with the bucket, so we can run our rate-limited code:
        logger.info("Start")
        await asyncio.sleep(2)  # Imitate a long running function, e.g. a network request.
        logger.info("End.")


async def main():
    redis_bucket = await RedisBucket.init([rate], async_redis, "my-bucket-name")
    limiter = Limiter(
        redis_bucket,
        max_delay=5000,
        raise_when_fail=True
    )
    e = Example(limiter)
    await asyncio.gather(
        *[e.func() for _ in range(10)]
    )

asyncio.run(main())

Error

Traceback (most recent call last):
  File "/opt/pysetup/try_rate_limit.py", line 44, in <module>
    asyncio.run(main())
  File "/usr/local/lib/python3.11/asyncio/runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/asyncio/base_events.py", line 653, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/opt/pysetup/try_rate_limit.py", line 40, in main
    await asyncio.gather(
  File "/opt/pysetup/try_rate_limit.py", line 23, in request
    await self.limiter.try_acquire("test")
  File "/opt/pysetup/.venv/lib/python3.11/site-packages/pyrate_limiter/limiter.py", line 307, in _handle_async_result
    result = await result
             ^^^^^^^^^^^^
  File "/opt/pysetup/.venv/lib/python3.11/site-packages/pyrate_limiter/limiter.py", line 259, in _put_async
    result = await result
             ^^^^^^^^^^^^
  File "/opt/pysetup/.venv/lib/python3.11/site-packages/pyrate_limiter/limiter.py", line 183, in _handle_async
    assert isinstance(delay, int), "Delay not integer"
AssertionError: Delay not integer

Expected behavior

I debugged the current delay value and in the code example I have:

    assert isinstance(delay, int), f"Delay not integer: {delay=}"
AssertionError: Delay not integer: delay=998.0

Without further debugging it is not clear right away from where I got 998.0 and what is a problem with a float.

  1. Make a descriptive useful message. An example:
    assert isinstance(delay, int), f'Expected an integer for "Delay", but got: {delay} of type {type(delay)}'
  2. The error is confusing. Is this not documented or I overlooked something in the documentation?

UPDATE 1

Allowing a float

                assert isinstance(delay, float)

at least allows to do not fail the code. I see a warning mentioned in #128 but that is OK for now.

That looks strange, I'll check soon