Source code for lcc.utils.commons

'''
There are common functions and decorators mainly for query classes
'''
from functools import wraps
import functools

from lcc.entities.exceptions import MandatoryKeyInQueryDictIsMissing,\
    ArgumentValidationError, InvalidArgumentNumberError, InvalidReturnType
import sys
import time
import threading


[docs]def check_attribute(attribute, cond, if_not=False): """ The class decorator checks if some class attributes has certain value Parameters ---------- attribute : str Name of the inspected class attribute cond : optional Condition to test for the inspected attribute id_not : optional Variable which will be returned if condition is not satisfied. If it is 'raise' exception will be raised Returns ------- Original output of the function if condition is satisfied """ def check_cond_deco(fu): @wraps(fu) def wrapper(*args, **kwargs): if getattr(args[0], attribute) == cond: return fu(*args, **kwargs) elif if_not == "raise": raise Exception( "Condition {0} is not {1}".format(attribute, cond)) return if_not return wrapper return check_cond_deco
[docs]def args_type(**decls): """ Decorator to check argument types Examples -------- @args_type(name="str",age=(int,float)) def func(...): """ def decorator(func): code = func.func_code fname = func.func_name names = code.co_varnames[:code.co_argcount] @wraps(func) def decorated(*args, **kwargs): dict_option = False if len(args) > 0 and isinstance(args[0], dict): kwargs = args[0] dict_option = True elif len(args) > 1 and isinstance(args[1], dict): kwargs = args[1] dict_option = True for argname, argtype in decls.iteritems(): try: argval = args[names.index(argname)] except (ValueError, IndexError): argval = kwargs.get(argname) if not argval and not isinstance(argval, argtype): raise TypeError("%s(...): arg '%s': type is %s, must be %s" % (fname, argname, type(argval), argtype)) if dict_option: return func(args[0], kwargs) return func(*args, **kwargs) return decorated return decorator
[docs]def default_values(**decls): """ Decorator to add default values to certain arguments if missing Example ------- @default_values(name="Unknown",age=0) def func(...): """ def decorator(func): @wraps(func) def decorated(*args, **kwargs): dict_option = False if len(args) > 0 and isinstance(args[0], dict): kwargs = args[0] dict_option = True elif len(args) > 1 and isinstance(args[1], dict): kwargs = args[1] dict_option = True for argname, arg_default_value in decls.iteritems(): if argname not in kwargs: kwargs[argname] = arg_default_value if dict_option: return func(args[0], kwargs) return func(*args, **kwargs) return decorated return decorator
[docs]def mandatory_args(*args_options): """ Decorator to check presence of mandatory arguments Examples -------- @default_values(("name","age"),("nick_name","sex")) def func(...): """ if not isinstance(args_options[0], tuple): args_options = tuple(args_options) def decorator(func): @wraps(func) def decorated(*args, **kwargs): missing_args = [] dict_option = False if len(args) > 0 and isinstance(args[0], dict): kwargs = args[0] dict_option = True elif len(args) > 1 and isinstance(args[1], dict): kwargs = args[1] dict_option = True for args_option in args_options: satisfied = True for key in args_option: if key not in kwargs: satisfied = False missing_args.append(key) break if satisfied: break if not satisfied: raise MandatoryKeyInQueryDictIsMissing(missing_args, kwargs) if dict_option: return func(args[0], kwargs) return func(*args, **kwargs) return decorated return decorator
[docs]def returns(*accepted_return_type_tuple): ''' Validates the return type. Since there's only ever one return type, this makes life simpler. Along with the accepts() decorator, this also only does a check for the top argument. For example you couldn't check (<type 'tuple'>, <type 'int'>, <type 'str'>). In that case you could only check if it was a tuple. ''' def return_decorator(validate_function): # No return type has been specified. if len(accepted_return_type_tuple) == 0: raise TypeError('You must specify a return type.') @functools.wraps(validate_function) def decorator_wrapper(*function_args): # More than one return type has been specified. if len(accepted_return_type_tuple) > 1: raise TypeError('You must specify one return type.') # Since the decorator receives a tuple of arguments # and the is only ever one object returned, we'll just # grab the first parameter. accepted_return_type = accepted_return_type_tuple[0] # We'll execute the function, and # take a look at the return type. return_value = validate_function(*function_args) return_value_type = type(return_value) if return_value_type is not accepted_return_type: raise InvalidReturnType(return_value_type, validate_function.__name__) return return_value return decorator_wrapper return return_decorator
[docs]def accepts(*accepted_arg_types): ''' A decorator to validate the parameter types of a given function. It is passed a tuple of types. eg. (<type 'tuple'>, <type 'int'>) Note ----- It doesn't do a deep check, for example checking through a tuple of types. The argument passed must only be types. ''' def accept_decorator(validate_function): # Check if the number of arguments to the validator # function is the same as the arguments provided # to the actual function to validate. We don't need # to check if the function to validate has the right # amount of arguments, as Python will do this # automatically (also with a TypeError). @functools.wraps(validate_function) def decorator_wrapper(*function_args, **function_args_dict): # Case of class function where first arg is 'self' if len(accepted_arg_types) == len(function_args) - 1: to_return_args = function_args function_args = function_args[1:] elif len(accepted_arg_types) is not len(function_args): raise InvalidArgumentNumberError( "Function: %s " % validate_function.__name__) # We're using enumerate to get the index, so we can pass the # argument number with the incorrect type to # ArgumentValidationError. for arg_num, (actual_arg, accepted_arg_type) in enumerate(zip(function_args, accepted_arg_types)): if not type(actual_arg) is accepted_arg_type: raise ArgumentValidationError("Wrong argument: %s" % actual_arg, "Name of the function: %s" % validate_function.__name__, "Accepted args: %s" % accepted_arg_type) return validate_function(*to_return_args) return decorator_wrapper return accept_decorator
[docs]class Spinner: busy = False delay = 0.1 @staticmethod
[docs] def spinning_cursor(): while 1: for cursor in '|/-\\': yield cursor
def __init__(self, txt="", delay=None): self.spinner_generator = self.spinning_cursor() if delay and float(delay): self.delay = delay self.txt = txt
[docs] def spinner_task(self): while self.busy: sys.stdout.write(self.txt + next(self.spinner_generator)) sys.stdout.flush() time.sleep(self.delay) sys.stdout.write('\b') sys.stdout.flush()
[docs] def start(self): self.busy = True threading.Thread(target=self.spinner_task).start()
[docs] def stop(self): self.busy = False time.sleep(self.delay)