comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:1eea6356d2e5
1 """
2 webcalc: a view with webob
3 """
4
5 import math
6 from pkg_resources import iter_entry_points
7 from pkg_resources import resource_filename
8 from webob import Request, Response, exc
9
10 class WebcalcView(object):
11
12 ### class level variables
13 defaults = { 'formatter': 'text/plain' }
14
15 def __init__(self, **kw):
16 for key in self.defaults:
17 setattr(self, key, kw.get(key, self.defaults[key]))
18 self.formatters = {}
19 for entry_point in iter_entry_points('webcalc.formatters'):
20 try:
21 formatter = entry_point.load()
22 except:
23 continue
24 self.formatters[entry_point.name] = formatter
25
26 assert self.formatter in self.formatters
27
28 self.response_functions = { 'GET': self.get,
29 'POST': self.get,
30 }
31
32 ### methods dealing with HTTP
33 def __call__(self, environ, start_response):
34 request = Request(environ)
35 res = self.make_response(request)
36 return res(environ, start_response)
37
38 def make_response(self, request):
39 return self.response_functions.get(request.method, self.error)(request)
40
41 def get_response(self, text, content_type='text/html'):
42 res = Response(content_type=content_type, body=text)
43 return res
44
45 def get(self, request):
46 """
47 return response to a GET requst
48 """
49
50
51 equation = request.path_info.strip('/').strip()
52 if not equation:
53 return self.get_response('<html><body><form method="post"><input type="text" name="equation"/></form></body></html>')
54
55
56 # limit scope of execution
57 forbidden = set([';', '=', 'import', 'from', 'with'])
58 forbidden.update(dir(__builtins__))
59 assert not [ i for i in forbidden
60 if i in equation ]
61 math_globals = dict([(i, getattr(math, i))
62 for i in dir(math)
63 if not i.startswith('_')])
64
65 # get the range of variables
66 variables = []
67 assert 'result' not in request.GET
68 for name, value in request.GET.items():
69 if name == 'format':
70 continue
71 values = self.values(value)
72 if variables:
73 if len(values) == 1:
74 for var in variables:
75 var[name] = values[0]
76 else:
77 old_variables = [ i.copy() for i in variables[:] ]
78 variables = []
79 for val in values:
80 row = [ i.copy() for i in old_variables ]
81 for item in row:
82 item[name] = val
83 variables.extend(row)
84 else:
85 variables = [ { name: val }
86 for val in values ]
87
88 # evaluate the equation
89 if variables:
90 for var in variables:
91 result = float(eval(equation, math_globals, var))
92 var['result'] = result
93 else:
94 result = float(eval(equation, math_globals, {}))
95 variables = [{'result': result}]
96
97 # format the result
98 format = request.params.get('format') or request.content_type or self.formatter
99 formatter = self.formatters.get(format, self.formatters[self.formatter])
100 return self.get_response(formatter(variables), format)
101
102 def post(self, request):
103 """
104 return response to a POST request
105 """
106 import pdb; pdb.set_trace()
107
108 return exc.HTTPOk("Ok")
109
110 def error(self, request):
111 """deal with non-supported methods"""
112 return exc.HTTPMethodNotAllowed("Only %r operations are allowed" % self.response_functions.keys())
113
114
115 def values(self, string):
116 """
117 >>> values('1,2,3,4')
118 [1,2,3,4]
119 >>> values('1..0.2..2')
120 [1,1.2,1.4,1.6,1.8,2]
121 """
122 retval = []
123 tokens = [i.strip() for i in string.split(',')
124 if i.strip()]
125 for token in tokens:
126 try:
127 value = float(token)
128 retval.append(value)
129 continue
130 except ValueError:
131 pass
132 start, step, end = token.split('..')
133 start = float(start)
134 step = float(step)
135 end = float(end)
136
137 values = [ start ]
138 npoints = (end - start)/step
139 npoints = int(npoints)
140 values.extend([i*step + start
141 for i in range(1, npoints)])
142 values.append(end)
143 retval.extend(values)
144 return retval