A LoopStatus object tests true according to geometric progression or time intervals. This enables rapid time estimates for long running codes, typically in a loop, without producing copious highly repetitive output.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | '''
import logging
from LoopStatus import LoopStatus
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s %(levelname)-8s L%(lineno)d %(message)s',
datefmt='%H:%M:%S',
)
status = LoopStatus()
...
if status():
logging.info('%dnth occurence',status.Value)
'''
import signal
class LoopStatus(object):
def __init__(self,base=2,seconds=5*60,target=1):
self.i = 0
self.base = base
self.target = target
self.nonzero = True
self.timesup = False
self.interval = seconds
if 0 < seconds:
self.reset_timer()
signal.signal(signal.SIGALRM,self.trap_alarm)
def trap_alarm(self,*args,**kwargs):
self.timesup = True
def reset_timer(self,interval=None):
if interval is None:
interval = self.interval
if 0 < interval:
self.timesup = False
signal.alarm(interval)
def __call__(self):
self.i += 1
self.nonzero = self.timesup or (self.target <= self.i)
if self:
self.target *= self.base
self.reset_timer()
return self.nonzero
@property
def Value(self):
return self.i
def __nonzero__(self):
return self.nonzero
def __str__(self):
return str(self.Value)
|
I'd include LoopStatusTest.py, except that I'd also have to post my testing framework. Tests are important. Here is an annotated sample use case terminated by keyboard interrupt:
>>> import LoopStatus
>>> status = LoopStatus.LoopStatus(seconds=4)
>>> while True:
... if status():
... print s.Value
...
1
2
4
8
16
32
64
128
256
512
1024
2048
4096
8192
16384
32768
65536
131072
262144
524288
1048576
2097152
3592136 # the 4 second timer caused this event
5106735
6616367
8126450
^C
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "ls.py", line 44, in __call__
if self.timesup or (self.target <= self.i):
KeyboardInterrupt
>>>
CONTROL
To closer pack the geometric sequence---set base to a float between 1 and 2.
For decade counting---set base to 10. I don't understand the fuss regardinging the usual number of fingers, hence the binary default.
For more frequent initial true tests---set target between 0 and 1
0 < target < 1
To test true less often initially---increase target.
To disable truth by time---choose 0 for seconds. The default is 5*60 seconds == 5 minutes.
To disable truth by count---use a large value of target.
METHODS
Call the LoopStatus object to increment its count, set the object's truth, and manage internals. It returns its truth value.
LoopStatus defines __nonzero__ which does not alter the object's truth.
LSObject.Value returns the LSObject() call count.
sample:
from WriteNumber import WriteNumber
unfinished = True
status = LoopStatus.LoopStatus()
while unfinished:
if status(): # Call updates truth state
info('measure %s.',WriteNumber(status.Value)) # progress
unfinished = symphony(
verbose = not not status) # safely use boolean state
correct! The first example in the discussion should read
where it says "s.Value".
base = 0 causes aways True.
the reset_timer method encourages changing the time interval.
I didn't find the "preview" option. These are the corrections I see. I'm sure you will find others. Happy programming!