[docs]classWindowStats(NamedTuple):""" tuple to describe a rate limited window """#: Time as seconds since the Epoch when this window will be resetreset_time:float#: Quantity remaining in this windowremaining:int
@dataclasses.dataclassclassDependency:name:strversion_required:Version|Noneversion_found:Version|Nonemodule:ModuleTypeMissingModule=ModuleType("Missing")ifTYPE_CHECKING:_UserDict=UserDict[str,Dependency]else:_UserDict=UserDictclassDependencyDict(_UserDict):def__getitem__(self,key:str)->Dependency:dependency=super().__getitem__(key)ifdependency.moduleisMissingModule:message=f"'{dependency.name}' prerequisite not available."ifdependency.version_required:message+=(f" A minimum version of {dependency.version_required} is required."ifdependency.version_requiredelse"")message+=(" See https://limits.readthedocs.io/en/stable/storage.html#supported-versions"" for more details.")raiseConfigurationError(message)elifdependency.version_requiredand(notdependency.version_foundordependency.version_found<dependency.version_required):raiseConfigurationError(f"The minimum version of {dependency.version_required}"f" for '{dependency.name}' could not be found. Found version: {dependency.version_found}")returndependencyclassLazyDependency:""" Simple utility that provides an :attr:`dependency` to the child class to fetch any dependencies without having to import them explicitly. """DEPENDENCIES:dict[str,Version|None]|list[str]=[]""" The python modules this class has a dependency on. Used to lazily populate the :attr:`dependencies` """def__init__(self)->None:self._dependencies:DependencyDict=DependencyDict()@propertydefdependencies(self)->DependencyDict:""" Cached mapping of the modules this storage depends on. This is done so that the module is only imported lazily when the storage is instantiated. :meta private: """ifnotgetattr(self,"_dependencies",None):dependencies=DependencyDict()mapping:dict[str,Version|None]ifisinstance(self.DEPENDENCIES,list):mapping={dependency:Nonefordependencyinself.DEPENDENCIES}else:mapping=self.DEPENDENCIESforname,minimum_versioninmapping.items():dependency,version=get_dependency(name)dependencies[name]=Dependency(name,minimum_version,version,dependency)self._dependencies=dependenciesreturnself._dependenciesdefget_dependency(module_path:str)->tuple[ModuleType,Version|None]:""" safe function to import a module at runtime """try:ifmodule_pathnotinsys.modules:__import__(module_path)root=module_path.split(".")[0]version=getattr(sys.modules[root],"__version__","0.0.0")returnsys.modules[module_path],Version(version)exceptImportError:# pragma: no coverreturnMissingModule,Nonedefget_package_data(path:str)->bytes:returnimportlib.resources.files("limits").joinpath(path).read_bytes()
[docs]defparse_many(limit_string:str)->list[RateLimitItem]:""" parses rate limits in string notation containing multiple rate limits (e.g. ``1/second; 5/minute``) :param limit_string: rate limit string using :ref:`ratelimit-string` :raise ValueError: if the string notation is invalid. """ifnot(isinstance(limit_string,str)andEXPR.match(limit_string)):raiseValueError(f"couldn't parse rate limit string '{limit_string}'")limits=[]forlimitinSEPARATORS.split(limit_string):match=SINGLE_EXPR.match(limit)ifmatch:amount,_,multiples,granularity_string=match.groups()granularity=granularity_from_string(granularity_string)limits.append(granularity(int(amount),multiplesandint(multiples)orNone))returnlimits
[docs]defparse(limit_string:str)->RateLimitItem:""" parses a single rate limit in string notation (e.g. ``1/second`` or ``1 per second``) :param limit_string: rate limit string using :ref:`ratelimit-string` :raise ValueError: if the string notation is invalid. """returnlist(parse_many(limit_string))[0]
defgranularity_from_string(granularity_string:str)->type[RateLimitItem]:""" :param granularity_string: :raise ValueError: """forgranularityinGRANULARITIES.values():ifgranularity.check_granularity_string(granularity_string):returngranularityraiseValueError(f"no granularity matched for {granularity_string}")