view webcalc/webcalc.py @ 0:1eea6356d2e5

initial import of webcalc
author k0s <k0scist@gmail.com>
date Mon, 07 Sep 2009 15:09:03 -0400
parents
children 12ac99c240ca
line wrap: on
line source

"""
webcalc: a view with webob
"""

import math
from pkg_resources import iter_entry_points
from pkg_resources import resource_filename
from webob import Request, Response, exc

class WebcalcView(object):

    ### class level variables
    defaults = { 'formatter': 'text/plain' }

    def __init__(self, **kw):
        for key in self.defaults:
            setattr(self, key, kw.get(key, self.defaults[key]))
        self.formatters = {}
        for entry_point in iter_entry_points('webcalc.formatters'):
            try:
                formatter = entry_point.load()
            except:
                continue
            self.formatters[entry_point.name] = formatter

        assert self.formatter in self.formatters

        self.response_functions = { 'GET': self.get,
                                    'POST': self.get,
                                    }

    ### methods dealing with HTTP
    def __call__(self, environ, start_response):
        request = Request(environ)
        res = self.make_response(request)
        return res(environ, start_response)
                                
    def make_response(self, request):
        return self.response_functions.get(request.method, self.error)(request)

    def get_response(self, text, content_type='text/html'):
        res = Response(content_type=content_type, body=text)
        return res

    def get(self, request):
        """
        return response to a GET requst
        """

        
        equation = request.path_info.strip('/').strip()
        if not equation:
            return self.get_response('<html><body><form method="post"><input type="text" name="equation"/></form></body></html>')


        # limit scope of execution
        forbidden = set([';', '=', 'import', 'from', 'with'])
        forbidden.update(dir(__builtins__))
        assert not [ i for i in forbidden
                     if i in equation ]
        math_globals = dict([(i, getattr(math, i))
                             for i in dir(math)
                             if not i.startswith('_')])
        
        # get the range of variables
        variables = []
        assert 'result' not in request.GET
        for name, value in request.GET.items():
            if name == 'format':
                continue
            values = self.values(value)
            if variables:
                if len(values) == 1:
                    for var in variables:
                        var[name] = values[0]
                else:
                    old_variables = [ i.copy() for i in variables[:] ]
                    variables = []
                    for val in values:
                        row = [ i.copy() for i in old_variables ]
                        for item in row:
                            item[name] = val
                        variables.extend(row)
            else:
                variables = [ { name: val } 
                              for val in values ]

        # evaluate the equation
        if variables:
            for var in variables:
                result = float(eval(equation, math_globals, var))
                var['result'] = result
        else:
            result = float(eval(equation, math_globals, {}))
            variables = [{'result': result}]

        # format the result
        format = request.params.get('format') or request.content_type or self.formatter
        formatter = self.formatters.get(format, self.formatters[self.formatter])
        return self.get_response(formatter(variables), format)

    def post(self, request):
        """
        return response to a POST request
        """
        import pdb;  pdb.set_trace()
        
        return exc.HTTPOk("Ok")

    def error(self, request):
        """deal with non-supported methods"""
        return exc.HTTPMethodNotAllowed("Only %r operations are allowed" % self.response_functions.keys())
        

    def values(self, string):
        """
        >>> values('1,2,3,4')
        [1,2,3,4]
        >>> values('1..0.2..2')
        [1,1.2,1.4,1.6,1.8,2]
        """
        retval = []
        tokens = [i.strip() for i in string.split(',')
                  if i.strip()]
        for token in tokens:
            try: 
                value = float(token)
                retval.append(value)
                continue
            except ValueError:
                pass
            start, step, end = token.split('..')
            start = float(start)
            step = float(step)
            end = float(end)
            
            values = [ start ]
            npoints = (end - start)/step
            npoints = int(npoints)
            values.extend([i*step + start 
                           for i in range(1, npoints)])
            values.append(end)
            retval.extend(values)
        return retval