X-Git-Url: https://wannabe.guru.org/gitweb/?a=blobdiff_plain;f=renderer.py;h=2f835b98f07c6f42b6b03f8813e49941668fec12;hb=2b7583ad79a2adb41b08a1086a9a780da83b776c;hp=491d34d52f9b32a9090294b40c21358e42f892fd;hpb=e932e65d4847a4777ddae297f9e52349285221ed;p=kiosk.git diff --git a/renderer.py b/renderer.py index 491d34d..2f835b9 100644 --- a/renderer.py +++ b/renderer.py @@ -1,81 +1,84 @@ +#!/usr/bin/env python3 + +from abc import ABC, abstractmethod +import logging import time -from datetime import datetime +from typing import Dict, Optional, Set + +from pyutils.decorator_utils import invocation_logged + + +logger = logging.getLogger(__file__) + -class renderer(object): +class renderer(ABC): """Base class for something that can render.""" + + @abstractmethod def render(self): pass + @abstractmethod def get_name(self): - return self.__class__.__name__ + pass + class abstaining_renderer(renderer): """A renderer that doesn't do it all the time.""" - def __init__(self, name_to_timeout_dict): - self.name_to_timeout_dict = name_to_timeout_dict; + + def __init__(self, name_to_timeout_dict: Dict[str, int]) -> None: + self.name_to_timeout_dict = name_to_timeout_dict self.last_runs = {} for key in name_to_timeout_dict: - self.last_runs[key] = 0 + self.last_runs[key] = 0.0 - def should_render(self, keys_to_skip): + def should_render(self, keys_to_skip: Set[str]) -> Optional[str]: now = time.time() for key in self.name_to_timeout_dict: - if (((now - self.last_runs[key]) > self.name_to_timeout_dict[key]) and - key not in keys_to_skip): + if ( + (now - self.last_runs[key]) > self.name_to_timeout_dict[key] + ) and key not in keys_to_skip: return key return None - def render(self): - tries_per_key = {} - keys_to_skip = set() + @invocation_logged + def render(self) -> None: + tries_per_key: Dict[str, int] = {} + keys_to_skip: Set[str] = set() while True: key = self.should_render(keys_to_skip) - if key == None: + if key is None: + logger.info( + f'renderer: Found nothing to do in "{self.get_name()}"; returning.' + ) break if key in tries_per_key: tries_per_key[key] += 1 else: tries_per_key[key] = 0 + op = f'{self.get_name()}.{key}' if tries_per_key[key] >= 3: - print('renderer: Too many failures/retries for "%s.%s", ' + - ', giving up for now' % (self.get_name(), key)) + logger.warning( + f'renderer: Too many failures in "{op}"; giving up.' + ) keys_to_skip.add(key) else: - msg = 'renderer: executing "%s.%s"' % (self.get_name(), key) - if (tries_per_key[key] > 1): - msg = msg + " (retry %d)" % tries_per_key[key] - print(msg) - if (self.periodic_render(key)): + msg = f'renderer: executing "{op}"' + if tries_per_key[key] > 1: + msg = msg + f' (retry #{tries_per_key[key]})' + logger.info(msg) + if self.periodic_render(key): + logger.debug(f'renderer: {op} succeeded.') self.last_runs[key] = time.time() + else: + logger.warning(f'renderer: {op} failed; returned False.') - def periodic_render(self, key): + @invocation_logged + @abstractmethod + def periodic_render(self, key) -> bool: pass -class debuggable_abstaining_renderer(abstaining_renderer): - def __init__(self, name_to_timeout_dict, debug): - super(debuggable_abstaining_renderer, self).__init__(name_to_timeout_dict); - self.debug = debug - - def debug_prefix(self): - return self.get_name() - - def being_debugged(self): - return self.debug - - def debug_print(self, template, *args): - try: - if self.being_debugged(): - if args: - msg = template.format(args) - else: - msg = template - - # current date and time - now = datetime.now() - timestamp = now.strftime("%d-%b-%Y (%H:%M:%S.%f)") - print("%s(%s): %s" % (self.debug_prefix(), timestamp, msg)) - except Exception as e: - print("Exception in debug_print!") - print(e) + def get_name(self) -> str: + return self.__class__.__name__