Avalanche Python Web Framework with a focus on testability and reusability

Project links



Source code for avalanche.params

import inspect


# name of the variable added to context_builders to hold
# list of AvalancheParam
_PARAM_VAR = '_a_params'


class AddListItemDecorator(object):
    """decorator that adds an item to a list variable in the decorated function

    @return the original function

    @ivar list_var: (str) name of variable to store the list of items
    @ivar item: item to be added
    """
    def __init__(self, list_var, item):
        self.list_var = list_var
        self.item = item
    def __call__(self, func):
        if not hasattr(func, self.list_var):
            setattr(func, self.list_var, [])
        getattr(func, self.list_var).append(self.item)
        return func



[docs]class AvalancheParam(object): """A parameter converter - (Abstract base class) This is used to convert parameters (i.e. from the URL) from string to its real type. :param obj_name: name of param to be passed to context_builders :type obj_name: str :param str_name: name of param on the source if not provided use same as obj_name :type str_name: str :param str2obj: callable that converts param string to an object if not provided obj it just returns the str_value there are 2 acceptable signatures for the callable: * take a single param with the str_value * first param takes str_value, second is named 'handler' and receives a reference to the RequestHandler """ def __init__(self, obj_name, str_name=None, str2obj=None): self.obj_name = obj_name self.str_name = str_name or obj_name self.str2obj = str2obj
[docs] def get_str_value(self, request): #pragma: nocover """intermediate value that will be passed to str2obj""" raise NotImplementedError
def get_obj_value(self, str_value, handler): """return object value @param handler: reference to a RequestHandler """ if self.str2obj: # XXX remove this shit. if needs handler call it a 'get_obj' if inspect.isfunction(self.str2obj): args = inspect.getargspec(self.str2obj)[0] if len(args) > 1 and args[1] == 'handler': return self.str2obj(str_value, handler) return self.str2obj(str_value) else: return str_value def __repr__(self): return "<%s:%s-%s>" % (self.__class__.__name__, self.obj_name, self.str_name) ###### Param sources
[docs]class UrlPathParam(AvalancheParam): """get parameter from URL path (given by route)""" def get_str_value(self, request): return request.route_kwargs.get(self.str_name)
[docs]def url_path_param(obj_name, str_name=None, str2obj=None): """decorator to add a UrlPathParam to a context-builder""" a_param = UrlPathParam(obj_name, str_name, str2obj) return AddListItemDecorator(_PARAM_VAR, a_param)
[docs]class UrlQueryParam(AvalancheParam): """get parameter from the URL query string""" def get_str_value(self, request): #XXX no difference between not present and ''. really want this? return request.GET.get(self.str_name, '')
[docs]def url_query_param(obj_name, str_name=None, str2obj=None): """decorator to add a UrlQueryParam to a context-builder""" converter = UrlQueryParam(obj_name, str_name, str2obj) return AddListItemDecorator(_PARAM_VAR, converter)
[docs]class PostGroupParam(AvalancheParam): """get a dictionary with all paramaters which name starts with "<str_name>-" """ def __init__(self, obj_name, str_name=None): def str2obj(str_value, handler): data = {} prefix = '%s-' % str_value prefix_len = len(prefix) request = handler.request for arg in request.POST.iterkeys(): if arg.startswith(prefix): name = arg[prefix_len:] data[name] = request.POST.get(arg) return data AvalancheParam.__init__(self, obj_name, str_name, str2obj) def get_str_value(self, request): return self.str_name
[docs]def post_group_param(obj_name, str_name=None): """decorator to add a PostGroupParam to a context-builder""" converter = PostGroupParam(obj_name, str_name) return AddListItemDecorator(_PARAM_VAR, converter)
[docs]class ContextParam(AvalancheParam): """get param from request-handler context""" def __init__(self, obj_name, str_name=None): def convert(str_value, handler): return handler.context[str_value] AvalancheParam.__init__(self, obj_name, str_name) self.str2obj = convert def get_str_value(self, request): return self.str_name
[docs]def context_param(obj_name, str_name=None): converter = ContextParam(obj_name, str_name) return AddListItemDecorator(_PARAM_VAR, converter)