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