Source code for imap_storage.tools.timer

"""@timer decorator"""
import sys
import logging
__all__ = ('timer')


[docs]def timer(func): """@timer decorator :TODO: option to shorten args at output """ from functools import wraps from time import time @wraps(func) # sets return meta to func meta def wrapper(*args, **kwargs): start = time() result = func(*args, **kwargs) duration = format((time() - start) * 1000, ".2f") log = LogEntry(func, duration, result, *args, **kwargs) mode = log.choose_mode() if mode == 'test': logging.info(log.long(with_result=True)) elif mode == 'wsgi': logging.info(log.short(with_result=False)) elif mode in ('django', 'main'): print(log.long(with_result=True)) return result return wrapper
[docs]class LogEntry: """Class that represents a Log entry""" MODES = ('test', 'wsgi', 'main', 'django') def __init__(self, func, duration, result, *args, **kwargs): self._func = func self._duration = duration self.result = result self._args = args self._kwargs = kwargs
[docs] def short(self, with_result=False): """short version of the log message Args: with_result(bool, optional): append function result to log Returns: str: log entry """ return self.to_string(short=True, with_result=with_result)
[docs] def long(self, with_result=False): """long version of the log message Args: with_result(bool, optional): append function result to log Returns: str: log entry """ return self.to_string(short=False, with_result=with_result)
@property def args(self): """parse args :returns: args as list of strings """ return [str(arg) for arg in self._args] @property def kwargs_long(self): """kwargs as long version""" return self.kwargs_list() @property def kwargs_short(self): """kwargs as short version""" return self.kwargs_list(short=True)
[docs] def kwargs_list(self, short=False): """parse kwargs :param truncate: should the output of values be shortened? :returns: kwargs as list of strings """ if short: return ['{}={}'.format(str(key), self.shorten_string(str(value))) for key, value in self._kwargs.items()] return ['{}={}'.format(str(key), str(value)) for key, value in self._kwargs.items()]
[docs] def to_string(self, short=False, with_result=False): """creates the string to enter in logs Args: short(bool, optional): use short version with_result(bool, optional): append result of function call to log Returns: str: log entry as string """ args_and_kwargs_str = ', '.join( self.args + self.kwargs_short if short else self.kwargs_long, ) result_string = '{}({}) -> {}ms.'.format( self._func.__name__, args_and_kwargs_str, self._duration ) if with_result: result_string += ' >>> {} <<<'.format( self.shorten_string(str(self.result)) if short else self.result ) return result_string
[docs] @staticmethod def choose_mode(): """possible_modes 'test', 'wsgi', 'main', 'django' :returns: mode as string """ mode = None if sys.argv[0] == 'mod_wsgi': mode = 'wsgi' elif sys.argv[0] == 'main.py': mode = 'main' elif sys.argv[0] == 'run_tests.py' or 'unittest' in sys.argv[0]: mode = 'test' elif len(sys.argv) >= 2: if sys.argv[1] == 'test': # needed? mode = 'test' elif sys.argv[1] == 'runserver': mode = 'django' if not mode: raise AttributeError('No mode found') return mode
[docs] @staticmethod def shorten_string(text_str, max_chars=50, replace=' <...> '): """shorten a text string to maximal ammount of chars :param text_str: string to shorten :param max_chars: (optional) limit text_str to these ammount of chars :param replace: (optional) replace cutted with this string """ if not isinstance(text_str, str): raise AttributeError(str(text_str) + ' is not a string') if len(text_str) > max_chars + len(replace): text_str = '{}{}{}'.format( text_str[:int(max_chars / 2 + 1.5)-1], replace, text_str[-int(max_chars / 2):], ) return text_str
def __str__(self): return self.long