$ pip install rlim
Create and use a RateLimiter instance:
@RateLimiter(Rate(2), Limit(50, 40))
def f():
...
@RateLimiter(Rate(2), Limit(50, 40))
async def f():
...Apply a RateLimiter instance to a function decorated with placeholder:
@placeholder
def f():
...
rl_set(f, RateLimiter(Rate(2), Limit(50, 40)))
@placeholder
async def f():
...
rl_set(f, RateLimiter(Rate(2), Limit(50, 40)))Use an instance as a context manager:
rl = RateLimiter(Rate(2), Limit(50, 40))
def f():
with rl:
...
async def f():
async with rl:
...Notice that in the above, Rate and Limit are two distinct types. Rate is used to define a constant calling speed - for example, Rate(2) would equate to 1 call every 0.5 seconds. Limit is used to define a maximum number of calls (at any speed) within a certain period of time (sliding window) - for example, Limit(50, 40) would mean the user could make calls at any speed, so long as they don't surpass 50 calls within the last 40 seconds. Together, this means the user can many calls at a max speed of 0.5s/call, and must stay below (or equal to) 50 calls in the past 40 seconds.
Bundles allow you to bundle together numerous rate limiters, with methods for applying them to the methods of a given class or class instance. When a bundle is applied to a class instance, the RateLimiter instances (or copies of them, if desired) within the bundle will be applied to each of the class's methods upon class instantiation.
Creating a Bundle:
bdl = Bundle(
fn1=RateLimiter(...),
fn2=RateLimiter(...),
...
)Applying a Bundle instance to a class:
@bdl
class Example:
def fn1(self) -> None:
return
def fn2(self) -> None:
returnNow, when you create an instance of Example, fn1 and fn2 will have their corresponding RateLimiter instances applied to them.
RateLimiter.copy(**overrides) -> RateLimiterCreate a copy of the
RateLimiterinstance with optional overrides (that will be passed intoRateLimiter.__init__).
RateLimiter.apply(func: Callable[_P, _R_co]) -> Callable[_P, _R_co]
RateLimiter.apply(func: Callable[_P, Awaitable[_R_co]]) -> Callable[_P, Awaitable[_R_co]]Manually wrap the given function to use the
RateLimiterinstance for rate limiting.RateLimiter.__call__(the function that makes it possible to decorate another function with aRateLimiterinstance) is simply an alias ofRateLimiter.apply.
Bundle.apply(
inst: object,
ignore: bool = MISSING,
copy: bool = MISSING,
**overrides
) -> NoneApply the
RateLimiterinstances in thisBundleto the given class instance.
ignore(defaultFalse) will make it soRateLimiterErrorwill not be raised if a function in the decorated class does not have a correspondingRateLimiter.copy(defaultTrue) will make it so copies of theRateLimiterinstances are applied, instead of the same instances.**overridesare keyword overrides that will be passed intoRateLimiter.copy(only ifcopyisTrue).
Bundle.decorate(
ignore: bool = MISSING,
copy: bool = MISSING,
**overrides
) -> Callable[[Type[T]], Callable[_P, T]]This function allows the user to have more control over how the
RateLimiterinstances are applied to the decorated class's methods. It returns a decorator.ignore,copy, and**overrideswill be passed intoBundle.apply.
Bundle.bake(
ignore: bool = MISSING,
copy: bool = MISSING,
**overrides
) -> NoneBake arguments for calls to
Bundle.applyandBundle.decorateinto theBundleinstance. Any arguments provided toBundle.applyorBundle.decoratehave precedence over baked arguments.