|
8 | 8 | For async code, use: from caldav import aio |
9 | 9 | """ |
10 | 10 |
|
| 11 | +import time |
11 | 12 | import logging |
12 | 13 | import sys |
13 | 14 | import warnings |
@@ -208,6 +209,9 @@ def __init__( |
208 | 209 | features: FeatureSet | dict | str = None, |
209 | 210 | enable_rfc6764: bool = True, |
210 | 211 | require_tls: bool = True, |
| 212 | + rate_limit_handle: bool = False, |
| 213 | + rate_limit_default_sleep: int = None, |
| 214 | + rate_limit_max_sleep: int = None, |
211 | 215 | ) -> None: |
212 | 216 | """ |
213 | 217 | Sets up a HTTPConnection object towards the server in the url. |
@@ -245,6 +249,13 @@ def __init__( |
245 | 249 | redirect to unencrypted HTTP. Set to False ONLY if you need to |
246 | 250 | support non-TLS servers and trust your DNS infrastructure. |
247 | 251 | This parameter has no effect if enable_rfc6764=False. |
| 252 | + rate_limit_handle: boolean, a parameter that determines whether the rate limit response |
| 253 | + should be handled. Default: False. |
| 254 | + rate_limit_default_sleep: integer, the default number of seconds to sleep if the server |
| 255 | + response cannot be parsed, or if no retry-after is specified |
| 256 | + and the HTTP response status code is 429. Default: None. |
| 257 | + rate_limit_max_sleep: integer, the maximum number of seconds the script will sleep |
| 258 | + when encountering a rate limit. Default: None. |
248 | 259 |
|
249 | 260 | The niquests library will honor a .netrc-file, if such a file exists |
250 | 261 | username and password may be omitted. |
@@ -343,6 +354,10 @@ def __init__( |
343 | 354 |
|
344 | 355 | self._principal = None |
345 | 356 |
|
| 357 | + self.rate_limit_handle = rate_limit_handle |
| 358 | + self.rate_limit_default_sleep = rate_limit_default_sleep |
| 359 | + self.rate_limit_max_sleep = rate_limit_max_sleep |
| 360 | + |
346 | 361 | def __enter__(self) -> Self: |
347 | 362 | ## Used for tests, to set up a temporarily test server |
348 | 363 | if hasattr(self, "setup"): |
@@ -933,7 +948,22 @@ def request( |
933 | 948 | Returns: |
934 | 949 | DAVResponse |
935 | 950 | """ |
936 | | - return self._sync_request(url, method, body, headers) |
| 951 | + try: |
| 952 | + return self._sync_request(url, method, body, headers) |
| 953 | + except error.RateLimitError as e: |
| 954 | + if self.rate_limit_handle: |
| 955 | + retry_after_seconds = self.rate_limit_default_sleep |
| 956 | + if e.retry_after_seconds is not None: |
| 957 | + retry_after_seconds = e.retry_after_seconds |
| 958 | + retry_after_seconds = max( |
| 959 | + [retry_after_seconds or 0, self.rate_limit_max_sleep or 0] |
| 960 | + ) |
| 961 | + if retry_after_seconds <= 0: |
| 962 | + raise e |
| 963 | + time.sleep(retry_after_seconds) |
| 964 | + return self._sync_request(url, method, body, headers) |
| 965 | + |
| 966 | + raise e |
937 | 967 |
|
938 | 968 | def _sync_request( |
939 | 969 | self, |
|
0 commit comments