Mercurial > p > roundup > code
comparison roundup/rate_limit.py @ 7590:5fbd3af526bd
fix: issue2551278 - datetime.datetime.utcnow deprecation.
We now use the timezone aware utc dates for python 3.11+.
But we have to make all the rest of the dates (datetime.min, unix
epoch date) timezon aware so we can subtract them. Also need to
marshall/unmarshall timezone aware iso formatted date strings.
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Thu, 27 Jul 2023 00:53:36 -0400 |
| parents | 8f29e4ea05ce |
| children | 224ccb8b49ca |
comparison
equal
deleted
inserted
replaced
| 7589:6894f152d49a | 7590:5fbd3af526bd |
|---|---|
| 3 # with imports, modifications for python 2, implementation of | 3 # with imports, modifications for python 2, implementation of |
| 4 # set/get_tat and marshaling as string, support for testonly | 4 # set/get_tat and marshaling as string, support for testonly |
| 5 # and status method. | 5 # and status method. |
| 6 | 6 |
| 7 from datetime import timedelta, datetime | 7 from datetime import timedelta, datetime |
| 8 | |
| 9 try: | |
| 10 # used by python 3.11 and newer use tz aware dates | |
| 11 from datetime import UTC | |
| 12 dt_min = datetime.min.replace(tzinfo=UTC) | |
| 13 # start of unix epoch | |
| 14 dt_epoch = datetime(1970, 1, 1, tzinfo=UTC) | |
| 15 fromisoformat = datetime.fromisoformat | |
| 16 except ImportError: | |
| 17 # python 2.7 and older than 3.11 - use naive dates | |
| 18 dt_min = datetime.min | |
| 19 dt_epoch = datetime(1970, 1, 1) | |
| 20 def fromisoformat(date): | |
| 21 # only for naive dates | |
| 22 return datetime.strptime(date, "%Y-%m-%dT%H:%M:%S.%f") | |
| 8 | 23 |
| 9 from roundup.anypy.datetime_ import utcnow | 24 from roundup.anypy.datetime_ import utcnow |
| 10 | 25 |
| 11 | 26 |
| 12 class RateLimit: # pylint: disable=too-few-public-methods | 27 class RateLimit: # pylint: disable=too-few-public-methods |
| 26 def get_tat(self, key): | 41 def get_tat(self, key): |
| 27 # This should return a previous tat for the key or the current time. | 42 # This should return a previous tat for the key or the current time. |
| 28 if key in self.memory: | 43 if key in self.memory: |
| 29 return self.memory[key] | 44 return self.memory[key] |
| 30 else: | 45 else: |
| 31 return datetime.min | 46 return dt_min |
| 32 | 47 |
| 33 def set_tat(self, key, tat): | 48 def set_tat(self, key, tat): |
| 34 self.memory[key] = tat | 49 self.memory[key] = tat |
| 35 | 50 |
| 36 def get_tat_as_string(self, key): | 51 def get_tat_as_string(self, key): |
| 38 # YYYY-MM-DDTHH:MM:SS.mmmmmm | 53 # YYYY-MM-DDTHH:MM:SS.mmmmmm |
| 39 # to allow it to be marshalled/unmarshaled | 54 # to allow it to be marshalled/unmarshaled |
| 40 if key in self.memory: | 55 if key in self.memory: |
| 41 return self.memory[key].isoformat() | 56 return self.memory[key].isoformat() |
| 42 else: | 57 else: |
| 43 return datetime.min.isoformat() | 58 return dt_min.isoformat() |
| 44 | 59 |
| 45 def set_tat_as_string(self, key, tat): | 60 def set_tat_as_string(self, key, tat): |
| 46 # Take value as string and unmarshall: | 61 # Take value as string and unmarshall: |
| 47 # YYYY-MM-DDTHH:MM:SS.mmmmmm | 62 # YYYY-MM-DDTHH:MM:SS.mmmmmm |
| 48 # to datetime | 63 # to datetime |
| 49 self.memory[key] = datetime.strptime(tat, "%Y-%m-%dT%H:%M:%S.%f") | 64 self.memory[key] = fromisoformat(tat) |
| 50 | 65 |
| 51 def update(self, key, limit, testonly=False): | 66 def update(self, key, limit, testonly=False): |
| 52 '''Determine if the item associated with the key should be | 67 '''Determine if the item associated with the key should be |
| 53 rejected given the RateLimit limit. | 68 rejected given the RateLimit limit. |
| 54 ''' | 69 ''' |
| 98 | 113 |
| 99 # tat_in_epochsec = (tat - datetime(1970, 1, 1)).total_seconds() | 114 # tat_in_epochsec = (tat - datetime(1970, 1, 1)).total_seconds() |
| 100 seconds_to_tat = (tat - now).total_seconds() | 115 seconds_to_tat = (tat - now).total_seconds() |
| 101 ret['X-RateLimit-Reset'] = str(max(seconds_to_tat, 0)) | 116 ret['X-RateLimit-Reset'] = str(max(seconds_to_tat, 0)) |
| 102 ret['X-RateLimit-Reset-date'] = "%s" % tat | 117 ret['X-RateLimit-Reset-date'] = "%s" % tat |
| 103 ret['Now'] = str((now - datetime(1970, 1, 1)).total_seconds()) | 118 ret['Now'] = str((now - dt_epoch).total_seconds()) |
| 104 ret['Now-date'] = "%s" % now | 119 ret['Now-date'] = "%s" % now |
| 105 | 120 |
| 106 if self.update(key, limit, testonly=True): | 121 if self.update(key, limit, testonly=True): |
| 107 # A new request would be rejected if it was processes. | 122 # A new request would be rejected if it was processes. |
| 108 # The user has to wait until an item is dequeued. | 123 # The user has to wait until an item is dequeued. |
