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.

Roundup Issue Tracker: http://roundup-tracker.org/