Skip to content

Commit 3729600

Browse files
committed
Add initial docstrings to RateLimit classes
1 parent 8c4095d commit 3729600

1 file changed

Lines changed: 72 additions & 0 deletions

File tree

xbox/webapi/common/ratelimits/__init__.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,55 @@
1212

1313

1414
class RateLimit(metaclass=ABCMeta):
15+
"""
16+
Abstract class for varying implementations/types of rate limits.
17+
All methods in this class are overriden in every implementation.
18+
However, different implementations may have additional functions not present in this parent abstract class.
19+
20+
A class implementing RateLimit functions without any external threads.
21+
When the first increment request is recieved (after a counter reset or a new instaniciation)
22+
a reset_after variable is set detailing when the rate limit(s) reset.
23+
24+
Upon each function invokation, the reset_after variable is checked and the timer is automatically reset if the reset_after time has passed.
25+
"""
26+
1527
@abstractmethod
1628
def get_counter(self) -> int:
29+
# Docstrings are defined in child classes due to their differing implementations.
1730
pass
1831

1932
@abstractmethod
2033
def get_reset_after(self) -> Union[datetime, None]:
34+
# Docstrings are defined in child classes due to their differing implementations.
2135
pass
2236

2337
@abstractmethod
2438
def is_exceeded(self) -> bool:
39+
# Docstrings are defined in child classes due to their differing implementations.
2540
pass
2641

2742
@abstractmethod
2843
def increment(self) -> IncrementResult:
44+
"""
45+
The increment function adds one to the rate limit request counter.
46+
47+
If the reset_after time has passed, the counter will first be reset before counting the request.
48+
49+
When the counter hits 1, the reset_after time is calculated and stored.
50+
51+
This function returns an `IncrementResult` object, containing the keys `counter: int` and `exceeded: bool`.
52+
This can be used by the caller to determine the current state of the rate-limit object without making an additional function call.
53+
"""
54+
2955
pass
3056

3157

3258
class SingleRateLimit(RateLimit):
59+
"""
60+
A rate limit implementation for a single rate limit, such as a burst or sustain limit.
61+
This class is mainly used by the CombinedRateLimit class.
62+
"""
63+
3364
def __init__(self, time_period: TimePeriod, type: LimitType, limit: int):
3465
self.__time_period = time_period
3566
self.__type = type
@@ -41,6 +72,10 @@ def __init__(self, time_period: TimePeriod, type: LimitType, limit: int):
4172
self.__reset_after: Union[datetime, None] = None
4273

4374
def get_counter(self) -> int:
75+
"""
76+
This function returns the current request counter variable.
77+
"""
78+
4479
return self.__counter
4580

4681
def get_time_period(self) -> "TimePeriod":
@@ -53,9 +88,21 @@ def get_limit_type(self) -> "LimitType":
5388
return self.__type
5489

5590
def get_reset_after(self) -> Union[datetime, None]:
91+
"""
92+
This getter returns the current state of the reset_after counter.
93+
94+
If the counter in use, it's corresponding `datetime` object is returned.
95+
96+
If the counter is not in use, `None` is returned.
97+
"""
98+
5699
return self.__reset_after
57100

58101
def is_exceeded(self) -> bool:
102+
"""
103+
This functions returns `True` if the rate limit has been exceeded.
104+
"""
105+
59106
self.__reset_counter_if_required()
60107
return self.__exceeded
61108

@@ -101,6 +148,11 @@ def __set_reset_after(self):
101148

102149

103150
class CombinedRateLimit(RateLimit):
151+
"""
152+
A rate limit implementation for multiple rate limits, such as burst and sustain.
153+
154+
"""
155+
104156
def __init__(self, *parsed_limits: ParsedRateLimit, type: LimitType):
105157
# *parsed_limits is a tuple
106158

@@ -123,6 +175,12 @@ def __init__(self, *parsed_limits: ParsedRateLimit, type: LimitType):
123175
)
124176

125177
def get_counter(self) -> int:
178+
"""
179+
This function returns the request counter with the **highest** value.
180+
181+
A `CombinedRateLimit` consists of multiple different rate limits, which may have differing counter values.
182+
"""
183+
126184
# Map self.__limits to (limit).get_counter()
127185
counter_map = map(lambda limit: limit.get_counter(), self.__limits)
128186
counters = list(counter_map)
@@ -137,6 +195,16 @@ def get_counter(self) -> int:
137195
# We don't want a datetime response for a limit that has not been exceeded.
138196
# Otherwise eg. 10 burst requests -> 300s timeout (should be 30 (burst exceeded), 300s (not exceeded)
139197
def get_reset_after(self) -> Union[datetime, None]:
198+
"""
199+
This getter returns either a `datetime` object or `None` object depending on the status of the rate limit.
200+
201+
If the counter is in use, the rate limit with the **latest** reset_after is returned.
202+
203+
This is so that this function can reliably be used as a indicator of when all rate limits have been reset.
204+
205+
If the counter is not in use, `None` is returned.
206+
"""
207+
140208
# Get a list of limits that *have been exceeded*
141209
dates_exceeded_only = filter(lambda limit: limit.is_exceeded(), self.__limits)
142210

@@ -185,6 +253,10 @@ def get_limits_by_period(self, period: TimePeriod) -> List[SingleRateLimit]:
185253
return list(matches)
186254

187255
def is_exceeded(self) -> bool:
256+
"""
257+
This function returns `True` if **any** rate limit has been exceeded.
258+
"""
259+
188260
# Map self.__limits to (limit).is_exceeded()
189261
is_exceeded_map = map(lambda limit: limit.is_exceeded(), self.__limits)
190262
is_exceeded_list = list(is_exceeded_map)

0 commit comments

Comments
 (0)