Mercurial > hg > webcalc
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 |