summaryrefslogblamecommitdiff
path: root/utils.py
blob: 0416a9003eaf77e84fcd8ad6796bddf73bc65600 (plain) (tree)





















































































































































                                                                           
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