Source code for freiner.util

import re
from typing import Sequence, Type, cast

from .limits import GRANULARITIES, RateLimitItem


SEPARATORS = re.compile(r"[,;|]")
SINGLE_EXPR = re.compile(
    r"""
    \s*([0-9]+)
    \s*(?:/|\s*per\s*)
    \s*([0-9]+)
    *\s*(hour|minute|second|day|month|year)s?\s*""",
    re.IGNORECASE | re.VERBOSE,
)
EXPR = re.compile(
    r"^{SINGLE}(?:{SEPARATORS}{SINGLE})*$".format(
        SINGLE=SINGLE_EXPR.pattern, SEPARATORS=SEPARATORS.pattern
    ),
    re.IGNORECASE | re.VERBOSE,
)


[docs]def parse_many(limit_string: str) -> Sequence[RateLimitItem]: """ Parses rate limits in string notation containing multiple rate limits (e.g. '1/second; 5/minute'). :param limit_string: The rate limit string. using :ref:`ratelimit-string`. :raises TypeError: If something other than a string was supplied. :raises ValueError: If the string notation is invalid. :return: A sequence of :class:`freiner.limits.RateLimitItem` instances. """ if not isinstance(limit_string, str): raise TypeError("Invalid rate limit string supplied.") if not EXPR.match(limit_string): raise ValueError(f"Failed to parse rate limit string: {limit_string}") limits = [] for limit in SEPARATORS.split(limit_string): # This cast is fine because we already verified that it will match # in the EXPR.match check above. limit_match = cast(re.Match, SINGLE_EXPR.match(limit)) amount, multiples, granularity_string = limit_match.groups() granularity = granularity_from_string(granularity_string) limits.append(granularity(amount, multiples)) return tuple(limits)
[docs]def parse(limit_string: str) -> RateLimitItem: """ Parses a single rate limit in string notation (e.g. '1/second' or '1 per second'). # noqa: DAR402 :param limit_string: The rate limit string. using :ref:`ratelimit-string`. :raises TypeError: If something other than a string was supplied. :raises ValueError: If the string notation is invalid. :return: An instance of :class:`freiner.limits.RateLimitItem`. """ return parse_many(limit_string)[0]
def granularity_from_string(granularity_string: str) -> Type[RateLimitItem]: """ :param granularity_string: A representation of the granularity (eg. "second", "minute"). :raises ValueError: If the supplied granularity is unknown. :return: A subclass of :class:`freiner.limits.RateLimitItem`. """ for granularity in GRANULARITIES.values(): if granularity.check_granularity_string(granularity_string): return granularity raise ValueError(f"No granularity matched for: {granularity_string}")