Mercurial > hg > webcalc
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/webcalc/webcalc.py Mon Sep 07 15:09:03 2009 -0400 @@ -0,0 +1,144 @@ +""" +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