diff options
Diffstat (limited to 'utils.py')
-rw-r--r-- | utils.py | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..0416a90 --- /dev/null +++ b/utils.py @@ -0,0 +1,150 @@ +import time +import threading +from loggers import debuglog + + +def log_method(fun): + def wrapper(self, *args, **kwargs): + s_args = s_kwargs = '' + if args: s_args = ','.join(str(a) for a in args) + if kwargs: s_kwargs = ','.join('{}={}'.format(k, v) + for k, v in kwargs.items()) + debuglog.debug('CALL: {}.{}({},{})'.format(self.__class__.__name__, + fun.__name__, + s_args, s_kwargs)) + result = fun(self, *args, **kwargs) + return result + return wrapper + + +def log_function(fun): + def wrapper(*args, **kwargs): + s_args = s_kwargs = '' + if args: s_args = ','.join(str(a) for a in args) + if kwargs: s_kwargs = ','.join('{}={}'.format(k, v) + for k, v in kwargs.items()) + debuglog.debug('CALL: {}({},{})'.format(fun.__name__, + s_args, s_kwargs)) + result = fun(*args, **kwargs) + return result + return wrapper + + +class Schedule: + """Class to schedule repeatable events""" + def __init__(self, start, delay, func, *args, **kwargs): + self._active = True + self._next_event = time.time() + start + self._delay = delay + self._func = func + self._thread = threading.Thread(target=self._threadfunc, + args=args, kwargs=kwargs) + self._thread.start() + + def _threadfunc(self, *args, **kwargs): + while self._active: + now = time.time() + if now >= self._next_event: + self._func(*args, **kwargs) + self._next_event += self._delay + if self._delay <= 0: + return + time.sleep(0.1) + + def cancel(self): + if self._active: + self._active = False + if self._thread is not threading.current_thread(): + self._thread.join() + + +# The following group of functions is to provide a way to extend +# a module's functions by decorating them with @extendable + +_extensions = {} + + +def register_extension(name, func): + if name in _extensions: + if func not in _extensions[name]: + _extensions[name].append(func) + else: + _extensions[name] = [func] + + +def extendable(func): + """ + Decorator function. If a function is decorated with + @extendable, each call of it will be followed by calls of + _extentions[fun.__name__](*args, **kwargs) with same args + """ + + def wrapper(*args, **kwargs): + name = func.__name__ + func(*args, **kwargs) + if name in _extensions: + for f in _extensions[name]: + f(*args, **kwargs) + + wrapper.__name__ = func.__name__ + return wrapper + + +def extends(func_name): + """ + Return a decorator that registers the wrapped function + as an extention to func_name call. + See @extendable. + """ + + def decorator(func): + + def wrapper(*args, **kwargs): + return func(*args, **kwargs) + + register_extension(func_name, func) + return wrapper + + return decorator + + +def preprocess_argument(pp_fun, arg=0): + """ + Make a decorator that modifies 1 argument of a given function + before calling it. + pp_fun accepts this argument and returns the modified. + arg can be either int, then args[arg] is modified, or it + can be str, then kwargs[arg] is modified + """ + + def decorator(fun): + + def wrapper(*args, **kwargs): + if isinstance(arg, int): + if arg < len(args): + args = list(args) + args[arg] = pp_fun(args[arg]) + elif isinstance(arg, str): + if arg in kwargs: + kwargs[arg] = pp_fun(kwargs[arg]) + + return fun(*args, **kwargs) + + return wrapper + + return decorator + + +# Encode string - used with 4144 shop compatibility. +def encode_str(value, size): + output = '' + base = 94 + start = 33 + while value: + output += chr(value % base + start) + value /= base + + while len(output) < size: + output += chr(start) + + return output |