# Source code for limits.util

    """

    """
    import re
    import sys

    from .limits import GRANULARITIES

    SEPARATORS = re.compile(r"[,;|]{1}")
    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
    )
    EXPR = re.compile(
        r"^{SINGLE}(:?{SEPARATORS}{SINGLE})*$".format(SINGLE=SINGLE_EXPR.pattern, SEPARATORS=SEPARATORS.pattern),
        re.IGNORECASE
    )

    def get_dependency(dep):
        """
        safe function to import a module programmatically
        :return: module or None (if not importable)
        """
        try:
            __import__(dep)
            return sys.modules[dep]
        except ImportError: # pragma: no cover
            return None

    def parse_many(limit_string):
        """
        parses rate limits in string notation containing multiple rate limits
        (e.g. '1/second; 5/minute')

        :param string limit_string: rate limit string using :ref:`ratelimit-string`
        :raise ValueError: if the string notation is invalid.
        :return: a list of :class:`RateLimitItem` instances.

        """
        if not EXPR.match(limit_string):
            raise ValueError("couldn't parse rate limit string '%s'" % limit_string)
        limits = []
        for limit in SEPARATORS.split(limit_string):
            amount, _, multiples, granularity_string = SINGLE_EXPR.match(limit).groups()
            granularity = granularity_from_string(granularity_string)
            limits.append(granularity(amount, multiples))
        return limits

    def parse(limit_string):
        """
        parses a single rate limit in string notation (e.g. '1/second' or '1 per second'

        :param string limit_string: rate limit string using :ref:`ratelimit-string`
        :raise ValueError: if the string notation is invalid.
        :return: an instance of :class:`RateLimitItem`

        """
        return list(parse_many(limit_string))[0]

    def granularity_from_string(granularity_string):
        """

        :param granularity_string:
        :return: a subclass of :class:`RateLimitItem`
        :raise ValueError:
        """
        for granularity in GRANULARITIES.values():
            if granularity.check_granularity_string(granularity_string):
                return granularity
        raise ValueError("no granularity matched for %s" % granularity_string)