Source code for Hellas.Delphi

"""This module contains classes and functions useful for pretty/color printing to console or logs
it is named after `Delphi <http://en.wikipedia.org/wiki/Delphi>`_ the famous city where
ancient `Oracle of Delphi <https://en.wikipedia.org/wiki/Pythia>`_ was located.
"""


import sys
import logging
from logging import handlers  # in python 3 not in logging.hendlers
import time
from Hellas.Sparta import DotDot
from Hellas import _IS_PY2
try:
    import simplejson as anyjson
except ImportError as e:
    import json as anyjson


[docs]class Color(object): """some basic color handling for printing in color .. Warning:: This class will **NOT** work in windows OS unless complemented by library `colorama <https://pypi.python.org/pypi/colorama>`_ :Example: >>> cl = Color() >>> cl.printc("this is red", "red") """ colors = DotDot({ 'black': (0, 30), 'gray_br': (0, 37), 'blue': (0, 34), 'white': (1, 37), 'green': (0, 32), 'blue_br': (1, 34), 'cyan': (0, 36), 'green_br': (1, 32), 'red': (0, 31), 'cyan_br': (1, 36), 'purple': (0, 35), 'red_br': (1, 31), 'yellow': (0, 33), 'purple_br': (1, 35), 'gray_dk': (1, 30), 'yellow_br': (1, 33), 'normal': (0,) }) @classmethod
[docs] def help(cls): """prints named colors""" print("for named colors use :") for c in sorted(list(cls.colors.items())): print("{:10} {}".format(*c))
@classmethod
[docs] def color_code(cls, color): """ returns code for color :param tuple_or_code color: either a tuple as in colors.values or a string key to colors dictionary """ if not isinstance(color, tuple): color = cls.colors[color] return "{:d};{}".format(color[0], str(color[1]) if len(color) == 2 else "")
@classmethod
[docs] def color_switch_txt(cls, color=colors.red): return "\033[{}m".format(cls.color_code(color))
@classmethod
[docs] def color_txt(cls, txt="", color=None): if _IS_PY2 and isinstance(txt, unicode): txt = txt.encode("utf-8") return "{}{}\033[0m".format(cls.color_switch_txt(color), txt)
@classmethod
[docs] def printc(cls, txt, color=colors.red): """Print in color.""" print(cls.color_txt(txt, color))
@classmethod
[docs] def color_switch_print(cls, color): print(cls.color_switch_txt(color))
[docs]class ColoredFormatter(logging.Formatter): """a logging formatter for printing in color works only in linux on an non linux system it returns plain text """ if sys.platform.startswith('linux'): color = Color() clr_name = color.colors def format(self, record): levelno = record.levelno if(levelno >= 50): clr = self.clr_name.red_br # CRITICAL / FATAL elif(levelno >= 40): clr = self.clr_name.red # ERROR elif(levelno >= 30): clr = self.clr_name.yellow # WARNING elif(levelno >= 20): clr = self.clr_name.green # INFO elif(levelno >= 10): clr = self.clr_name.purple_br # DEBUG else: clr = self.cls_name.normal # NOTSET etc return self.color.color_txt(logging.Formatter.format(self, record), clr) else:
[docs] def format(self, record): return logging.Formatter.format(self, record)
[docs]def logging_format(verbose=2, style='txt'): """returns a format :parameter: - str style: defines style of output format (defaults to txt) - txt plain text - dict like text which can be casted to dict """ frmt = "'dt':'%(asctime)s', 'lv':'%(levelname)-7s', 'ln':'%(name)s'" if verbose > 1: frmt += ",\t'Func': '%(funcName)-12s','line':%(lineno)5d, 'module':'%(module)s'" if verbose > 2: frmt += ",\n\t'file':'%(filename)s',\t'Process':['%(processName)s', %(process)d], \ 'thread':['%(threadName)s', %(thread)d], 'ms':%(relativeCreated)d" frmt += ",\n\t'msg':'%(message)s'" if style == "dict": frmt = "{" + frmt + "}" frmt = frmt.replace(" ", "").replace("\n", "").replace("\t", "") if style == "txt": frmt = frmt.replace("'", "").replace(",", "") return frmt
[docs]class LoggingColorHandler(logging.StreamHandler):
[docs] def __init__(self, level=logging.NOTSET, verbose=2): super(LoggingColorHandler, self).__init__() self.setLevel(level) formatterC = ColoredFormatter(logging_format(verbose, 'str')) formatterC.converter = time.gmtime self.setFormatter(formatterC)
[docs]def logger_multi( loggerName="", # top level_consol=logging.DEBUG, level_file=logging.DEBUG, filename=None, verbose=1, when='midnight', interval=1, backupCount=7): """a logger that logs to file as well as as screen see http://pythonhosted.org//logutils/ http://plumberjack.blogspot.gr/2010/10/supporting-alternative-formatting.html :Todo: - use new style formating for python > v3 i.e formatter = logging.Formatter(frmt.replace(" ", ""), style='{') #frmtC = frmt.translate(dict((ord(c), '') for c in "'{},")) :Parameters: `see <https://docs.python.org/2/library/logging.html#module-logging>`_ :Example: >>> LOG = logger_double('', level_consol=logging.DEBUG, level_file=logging.DEBUG, verbose=3, filename="~\f.log") """ logger = logging.getLogger(loggerName) logger.setLevel(min(level_consol if level_consol else 100, level_file if level_file else 100)) # logger.disable_existing_loggers = False if level_file: if filename is None: filename = "~\py.log" formatter = logging.Formatter(logging_format(verbose, 'str')) formatter.converter = time.gmtime hf = handlers.TimedRotatingFileHandler( filename, when=when, interval=interval, backupCount=backupCount, encoding='utf-8', delay=False, utc=True) hf.setFormatter(formatter) hf.setLevel(level_file) logger.addHandler(hf) if level_consol: logger.addHandler(LoggingColorHandler(level=level_consol, verbose=verbose)) return logger
[docs]def auto_retry(exception_t, retries=3, sleepSeconds=1, back_of_factor=1, logger_fun=None): """a generic auto-retry function @wrapper :param Exception exception_t: exception (or tuple of exceptions) to auto retry :param int retries: max retries before it raises the Exception (defaults to 3) :param int_or_float sleepSeconds: base sleep seconds between retries (defaults to 1) :param int back_of_factor: factor to back off on each retry (defaults to 1) :param int logger_fun: loggerFun i.e. logger.info to log on each retry (defaults to None) """ def wrapper(func): def fun_call(*args, **kwargs): tries = 0 while tries < retries: try: return func(*args, **kwargs) except exception_t as e: tries += 1 if logger_fun: logger_fun("exception [%s] e=[%s] handled tries :%d sleeping[%f]" % (exception_t, e, tries, sleepSeconds * tries * back_of_factor)) time.sleep(sleepSeconds * tries * back_of_factor) raise return fun_call return wrapper
[docs]def pp_obj(obj, indent=4, sort_keys=False, prn=True, default=None): """pretty prints a (list tuple or dict) object """ assert isinstance(obj, (list, tuple, dict)) rt = anyjson.dumps(obj, sort_keys=sort_keys, indent=indent, separators=(',', ': '), default=default, namedtuple_as_object=False) if prn: print(rt) else: return rt