2be7780c1c85ec02808abea8eb55fbd00fdbea57
[kiosk.git] / renderer.py
1 import time
2 from datetime import datetime
3 from decorators import invokation_logged
4
5
6 class renderer(object):
7     """Base class for something that can render."""
8
9     @invokation_logged
10     def render(self):
11         pass
12
13     def get_name(self):
14         return self.__class__.__name__
15
16
17 class abstaining_renderer(renderer):
18     """A renderer that doesn't do it all the time."""
19
20     def __init__(self, name_to_timeout_dict):
21         self.name_to_timeout_dict = name_to_timeout_dict
22         self.last_runs = {}
23         for key in name_to_timeout_dict:
24             self.last_runs[key] = 0
25
26     def should_render(self, keys_to_skip):
27         now = time.time()
28         for key in self.name_to_timeout_dict:
29             if (
30                 (now - self.last_runs[key]) > self.name_to_timeout_dict[key]
31             ) and key not in keys_to_skip:
32                 return key
33         return None
34
35     def render(self):
36         tries_per_key = {}
37         keys_to_skip = set()
38         while True:
39             key = self.should_render(keys_to_skip)
40             if key == None:
41                 break
42
43             if key in tries_per_key:
44                 tries_per_key[key] += 1
45             else:
46                 tries_per_key[key] = 0
47
48             if tries_per_key[key] >= 3:
49                 print(
50                     'renderer: Too many failures for "%s.%s", giving up'
51                     % (self.get_name(), key)
52                 )
53                 keys_to_skip.add(key)
54             else:
55                 msg = 'renderer: executing "%s.%s"' % (self.get_name(), key)
56                 if tries_per_key[key] > 1:
57                     msg = msg + " (retry #%d)" % tries_per_key[key]
58                 print(msg)
59                 if self.periodic_render(key):
60                     self.last_runs[key] = time.time()
61
62     @invokation_logged
63     def periodic_render(self, key):
64         pass
65
66
67 class debuggable_abstaining_renderer(abstaining_renderer):
68     def __init__(self, name_to_timeout_dict, debug):
69         super(debuggable_abstaining_renderer, self).__init__(name_to_timeout_dict)
70         self.debug = debug
71
72     def debug_prefix(self):
73         return self.get_name()
74
75     def being_debugged(self):
76         return self.debug
77
78     def debug_print(self, template, *args):
79         try:
80             if self.being_debugged():
81                 if args:
82                     msg = template.format(args)
83                 else:
84                     msg = template
85
86                 # current date and time
87                 now = datetime.now()
88                 timestamp = now.strftime("%d-%b-%Y (%H:%M:%S.%f)")
89                 print("%s(%s): %s" % (self.debug_prefix(), timestamp, msg))
90         except Exception as e:
91             print("Exception in debug_print!")
92             print(e)