comparison py/utils.py @ 294:6bacd8ca9f8f

merge
author Matt Johnston <matt@ucc.asn.au>
date Sat, 06 Jul 2019 18:30:25 +0800
parents af924d27140f
children 02aff9ff8d24
comparison
equal deleted inserted replaced
293:d15dda1b1f76 294:6bacd8ca9f8f
1 import os 1 import os
2 import sys 2 import sys
3 #import ctypes 3 import ctypes
4 import time 4 import time
5 import select 5 import select
6 import logging 6 import logging
7 import binascii 7 import binascii
8 import json 8 import json
9 import datetime
10 import collections
9 11
10 D = logging.debug 12 D = logging.debug
11 L = logging.info 13 L = logging.info
12 W = logging.warning 14 W = logging.warning
13 E = logging.error 15 E = logging.error
136 return -1 138 return -1
137 139
138 140
139 def json_load_round_float(s, **args): 141 def json_load_round_float(s, **args):
140 return json.loads(s,parse_float = lambda f: round(float(f), 2), **args) 142 return json.loads(s,parse_float = lambda f: round(float(f), 2), **args)
143
144 class NotTooOften(object):
145 """ prevents things happening more than once per limit.
146 Isn't monotonic, good enough for logging. eg
147 self.logfailure = NotTooOften(180) # 3 minutes
148 ...
149 if self.logfailure():
150 L("blah")
151 """
152 def __init__(self, limit):
153 """ limit is a delay in seconds or TimeDelta """
154 if type(limit) is datetime.timedelta:
155 self.limit = limit
156 else:
157 self.limit = datetime.timedelta(seconds=limit)
158
159 # must be positive
160 assert self.limit > datetime.timedelta(0)
161 self.last = datetime.datetime(10, 1, 1)
162
163 def __call__(self):
164 if datetime.datetime.now() - self.last > self.limit:
165 self.last = datetime.datetime.now()
166 return True
167
168 def log(self, msg):
169 """ calls L(msg) if it isn't too often, otherwise D(msg)
170 """
171 if self():
172 L(msg + " (log interval %s)" % str(self.limit))
173 else:
174 D(msg)
175
176 Period = collections.namedtuple('Period', 'start end')
177 class StepIntegrator(object):
178 """
179 Takes on/off events and a monotonically increasing timefn. Returns the integral
180 of (now-limittime, now) over those events.
181
182 >>> s = StepIntegrator(lambda: t, 40)
183 >>> t = 1
184 >>> s.turn(1)
185 >>> t = 10
186 >>> s.turn(0)
187 >>> t = 20
188 >>> s.turn(1)
189 >>> t = 30
190 >>> print(s.integrate())
191 19
192 >>> s.turn(0)
193 >>> print(s.integrate())
194 19
195 >>> t = 35
196 >>> print(s.integrate())
197 19
198 >>> t = 42
199 >>> print(s.integrate())
200 18
201 >>> t = 52
202 >>> print(s.integrate())
203 10
204 >>> t = 69
205 >>> print(s.integrate())
206 1
207 >>> t = 70
208 >>> print(s.integrate())
209 0
210 >>> t = 170
211 >>> print(s.integrate())
212 0
213 """
214 def __init__(self, timefn, limittime):
215 # _on_periods is a list of [period]. End is None if still on
216 self._on_periods = []
217 self._timefn = timefn
218 self._limittime = limittime
219
220 def set_limit(self, limittime):
221 if self._limittime == limittime:
222 return
223 self._limittime = limittime
224 self._trim()
225
226 def turn(self, value):
227 if not self._on_periods:
228 if value:
229 self._on_periods.append(Period(self._timefn(), None))
230 return
231
232 # state hasn't changed
233 on_now = (self._on_periods[-1].end is None)
234 if value == on_now:
235 return
236
237 if value:
238 self._on_periods.append(Period(self._timefn(), None))
239 else:
240 self._on_periods[-1] = self._on_periods[-1]._replace(end = self._timefn())
241
242 def _trim(self):
243 begin = self._timefn() - self._limittime
244 # shortcut, first start is after begin
245 if not self._on_periods or self._on_periods[0].start >= begin:
246 return
247
248 new_periods = []
249 for s, e in self._on_periods:
250 if s == e:
251 continue
252 elif s >= begin:
253 new_periods.append(Period(s,e))
254 elif e is not None and e < begin:
255 continue
256 else:
257 new_periods.append(Period(begin, e))
258 self._on_periods = new_periods
259
260 def integrate(self):
261 self._trim()
262 tot = 0
263 for s, e in self._on_periods:
264 if e is None:
265 e = self._timefn()
266 tot += (e-s)
267 return tot
268
269
270
271
272
273
274