1"""Logic for our ratelimit result.""" 2import datetime 3import typing 4 5import attr 6 7 8@attr.s(frozen=True) 9class RateLimitResult: 10 """A result of checking a ratelimit. 11 12 The attributes on this object are: 13 14 .. attribute:: limit 15 16 The integer limit that was checked against, e.g., if the user's 17 ratelimit is 10,000 this value will be 10,000 regardless of how much 18 they have consumed. 19 20 .. attribute:: limited 21 22 Whether or not the user should be ratelimited (a.k.a., throttled). 23 24 .. attribute:: remaining 25 26 The integer representing how much of the user's ratelimit is left. 27 This should be the number of requests made during the time period, 28 ``N``, subtracted from the limit, ``L``, or ``L - N``. 29 30 .. attribute:: reset_after 31 32 This will be a :class:`~datetime.timedelta` representing how much time 33 is left until the ratelimit resets. For example if the ratelimit will 34 reset in 800ms then this might look like: 35 36 .. code-block:: python 37 38 datetime.timedelta(0, 0, 800000) 39 # == datetime.timedelta(milliseconds=800) 40 41 .. attribute:: retry_after 42 43 This will be a :class:`~datetime.timedelta` representing the length of 44 time after which a retry can be made. 45 46 """ 47 48 limit: int = attr.ib() 49 limited: bool = attr.ib() 50 remaining: int = attr.ib() 51 reset_after: datetime.timedelta = attr.ib() 52 retry_after: datetime.timedelta = attr.ib() 53 54 @staticmethod 55 def _now() -> datetime.datetime: 56 return datetime.datetime.now(datetime.timezone.utc) 57 58 def resets_at( 59 self, from_when: typing.Optional[datetime.datetime] = None 60 ) -> datetime.datetime: 61 """Calculate the reset time from UTC now. 62 63 :returns: 64 The UTC timezone-aware datetime representing when the limit 65 resets. 66 """ 67 if from_when is None: 68 from_when = self._now() 69 return from_when + self.reset_after 70 71 def retry_at( 72 self, from_when: typing.Optional[datetime.datetime] = None 73 ) -> datetime.datetime: 74 """Calculate the retry time from UTC now. 75 76 :returns: 77 The UTC timezone-aware datetime representing when the user 78 can retry. 79 """ 80 if from_when is None: 81 from_when = self._now() 82 return from_when + self.retry_after 83