Fixed python_path problem.
[smonitor.git] / lib / cherrypy / test / test_dynamicobjectmapping.py
blob1e04d08933d1010960e1dba9decb2c48fc65cfa4
1 import cherrypy
2 from cherrypy._cptree import Application
3 from cherrypy.test import helper
5 script_names = ["", "/foo", "/users/fred/blog", "/corp/blog"]
9 def setup_server():
10 class SubSubRoot:
11 def index(self):
12 return "SubSubRoot index"
13 index.exposed = True
15 def default(self, *args):
16 return "SubSubRoot default"
17 default.exposed = True
19 def handler(self):
20 return "SubSubRoot handler"
21 handler.exposed = True
23 def dispatch(self):
24 return "SubSubRoot dispatch"
25 dispatch.exposed = True
27 subsubnodes = {
28 '1': SubSubRoot(),
29 '2': SubSubRoot(),
32 class SubRoot:
33 def index(self):
34 return "SubRoot index"
35 index.exposed = True
37 def default(self, *args):
38 return "SubRoot %s" % (args,)
39 default.exposed = True
41 def handler(self):
42 return "SubRoot handler"
43 handler.exposed = True
45 def _cp_dispatch(self, vpath):
46 return subsubnodes.get(vpath[0], None)
48 subnodes = {
49 '1': SubRoot(),
50 '2': SubRoot(),
52 class Root:
53 def index(self):
54 return "index"
55 index.exposed = True
57 def default(self, *args):
58 return "default %s" % (args,)
59 default.exposed = True
61 def handler(self):
62 return "handler"
63 handler.exposed = True
65 def _cp_dispatch(self, vpath):
66 return subnodes.get(vpath[0])
68 #--------------------------------------------------------------------------
69 # DynamicNodeAndMethodDispatcher example.
70 # This example exposes a fairly naive HTTP api
71 class User(object):
72 def __init__(self, id, name):
73 self.id = id
74 self.name = name
76 def __unicode__(self):
77 return unicode(self.name)
79 user_lookup = {
80 1: User(1, 'foo'),
81 2: User(2, 'bar'),
84 def make_user(name, id=None):
85 if not id:
86 id = max(*user_lookup.keys()) + 1
87 user_lookup[id] = User(id, name)
88 return id
90 class UserContainerNode(object):
91 exposed = True
93 def POST(self, name):
94 """
95 Allow the creation of a new Object
96 """
97 return "POST %d" % make_user(name)
99 def GET(self):
100 keys = user_lookup.keys()
101 keys.sort()
102 return unicode(keys)
104 def dynamic_dispatch(self, vpath):
105 try:
106 id = int(vpath[0])
107 except (ValueError, IndexError):
108 return None
109 return UserInstanceNode(id)
111 class UserInstanceNode(object):
112 exposed = True
113 def __init__(self, id):
114 self.id = id
115 self.user = user_lookup.get(id, None)
117 # For all but PUT methods there MUST be a valid user identified
118 # by self.id
119 if not self.user and cherrypy.request.method != 'PUT':
120 raise cherrypy.HTTPError(404)
122 def GET(self, *args, **kwargs):
124 Return the appropriate representation of the instance.
126 return unicode(self.user)
128 def POST(self, name):
130 Update the fields of the user instance.
132 self.user.name = name
133 return "POST %d" % self.user.id
135 def PUT(self, name):
137 Create a new user with the specified id, or edit it if it already exists
139 if self.user:
140 # Edit the current user
141 self.user.name = name
142 return "PUT %d" % self.user.id
143 else:
144 # Make a new user with said attributes.
145 return "PUT %d" % make_user(name, self.id)
147 def DELETE(self):
149 Delete the user specified at the id.
151 id = self.user.id
152 del user_lookup[self.user.id]
153 del self.user
154 return "DELETE %d" % id
157 class ABHandler:
158 class CustomDispatch:
159 def index(self, a, b):
160 return "custom"
161 index.exposed = True
163 def _cp_dispatch(self, vpath):
164 """Make sure that if we don't pop anything from vpath,
165 processing still works.
167 return self.CustomDispatch()
169 def index(self, a, b=None):
170 body = [ 'a:' + str(a) ]
171 if b is not None:
172 body.append(',b:' + str(b))
173 return ''.join(body)
174 index.exposed = True
176 def delete(self, a, b):
177 return 'deleting ' + str(a) + ' and ' + str(b)
178 delete.exposed = True
180 class IndexOnly:
181 def _cp_dispatch(self, vpath):
182 """Make sure that popping ALL of vpath still shows the index
183 handler.
185 while vpath:
186 vpath.pop()
187 return self
189 def index(self):
190 return "IndexOnly index"
191 index.exposed = True
193 class DecoratedPopArgs:
194 """Test _cp_dispatch with @cherrypy.popargs."""
195 def index(self):
196 return "no params"
197 index.exposed = True
199 def hi(self):
200 return "hi was not interpreted as 'a' param"
201 hi.exposed = True
202 DecoratedPopArgs = cherrypy.popargs('a', 'b', handler=ABHandler())(DecoratedPopArgs)
204 class NonDecoratedPopArgs:
205 """Test _cp_dispatch = cherrypy.popargs()"""
207 _cp_dispatch = cherrypy.popargs('a')
209 def index(self, a):
210 return "index: " + str(a)
211 index.exposed = True
213 class ParameterizedHandler:
214 """Special handler created for each request"""
216 def __init__(self, a):
217 self.a = a
219 def index(self):
220 if 'a' in cherrypy.request.params:
221 raise Exception("Parameterized handler argument ended up in request.params")
222 return self.a
223 index.exposed = True
225 class ParameterizedPopArgs:
226 """Test cherrypy.popargs() with a function call handler"""
227 ParameterizedPopArgs = cherrypy.popargs('a', handler=ParameterizedHandler)(ParameterizedPopArgs)
229 Root.decorated = DecoratedPopArgs()
230 Root.undecorated = NonDecoratedPopArgs()
231 Root.index_only = IndexOnly()
232 Root.parameter_test = ParameterizedPopArgs()
234 Root.users = UserContainerNode()
236 md = cherrypy.dispatch.MethodDispatcher('dynamic_dispatch')
237 for url in script_names:
238 conf = {'/': {
239 'user': (url or "/").split("/")[-2],
241 '/users': {
242 'request.dispatch': md
245 cherrypy.tree.mount(Root(), url, conf)
247 class DynamicObjectMappingTest(helper.CPWebCase):
248 setup_server = staticmethod(setup_server)
250 def testObjectMapping(self):
251 for url in script_names:
252 prefix = self.script_name = url
254 self.getPage('/')
255 self.assertBody('index')
257 self.getPage('/handler')
258 self.assertBody('handler')
260 # Dynamic dispatch will succeed here for the subnodes
261 # so the subroot gets called
262 self.getPage('/1/')
263 self.assertBody('SubRoot index')
265 self.getPage('/2/')
266 self.assertBody('SubRoot index')
268 self.getPage('/1/handler')
269 self.assertBody('SubRoot handler')
271 self.getPage('/2/handler')
272 self.assertBody('SubRoot handler')
274 # Dynamic dispatch will fail here for the subnodes
275 # so the default gets called
276 self.getPage('/asdf/')
277 self.assertBody("default ('asdf',)")
279 self.getPage('/asdf/asdf')
280 self.assertBody("default ('asdf', 'asdf')")
282 self.getPage('/asdf/handler')
283 self.assertBody("default ('asdf', 'handler')")
285 # Dynamic dispatch will succeed here for the subsubnodes
286 # so the subsubroot gets called
287 self.getPage('/1/1/')
288 self.assertBody('SubSubRoot index')
290 self.getPage('/2/2/')
291 self.assertBody('SubSubRoot index')
293 self.getPage('/1/1/handler')
294 self.assertBody('SubSubRoot handler')
296 self.getPage('/2/2/handler')
297 self.assertBody('SubSubRoot handler')
299 self.getPage('/2/2/dispatch')
300 self.assertBody('SubSubRoot dispatch')
302 # The exposed dispatch will not be called as a dispatch
303 # method.
304 self.getPage('/2/2/foo/foo')
305 self.assertBody("SubSubRoot default")
307 # Dynamic dispatch will fail here for the subsubnodes
308 # so the SubRoot gets called
309 self.getPage('/1/asdf/')
310 self.assertBody("SubRoot ('asdf',)")
312 self.getPage('/1/asdf/asdf')
313 self.assertBody("SubRoot ('asdf', 'asdf')")
315 self.getPage('/1/asdf/handler')
316 self.assertBody("SubRoot ('asdf', 'handler')")
318 def testMethodDispatch(self):
319 # GET acts like a container
320 self.getPage("/users")
321 self.assertBody("[1, 2]")
322 self.assertHeader('Allow', 'GET, HEAD, POST')
324 # POST to the container URI allows creation
325 self.getPage("/users", method="POST", body="name=baz")
326 self.assertBody("POST 3")
327 self.assertHeader('Allow', 'GET, HEAD, POST')
329 # POST to a specific instanct URI results in a 404
330 # as the resource does not exit.
331 self.getPage("/users/5", method="POST", body="name=baz")
332 self.assertStatus(404)
334 # PUT to a specific instanct URI results in creation
335 self.getPage("/users/5", method="PUT", body="name=boris")
336 self.assertBody("PUT 5")
337 self.assertHeader('Allow', 'DELETE, GET, HEAD, POST, PUT')
339 # GET acts like a container
340 self.getPage("/users")
341 self.assertBody("[1, 2, 3, 5]")
342 self.assertHeader('Allow', 'GET, HEAD, POST')
344 test_cases = (
345 (1, 'foo', 'fooupdated', 'DELETE, GET, HEAD, POST, PUT'),
346 (2, 'bar', 'barupdated', 'DELETE, GET, HEAD, POST, PUT'),
347 (3, 'baz', 'bazupdated', 'DELETE, GET, HEAD, POST, PUT'),
348 (5, 'boris', 'borisupdated', 'DELETE, GET, HEAD, POST, PUT'),
350 for id, name, updatedname, headers in test_cases:
351 self.getPage("/users/%d" % id)
352 self.assertBody(name)
353 self.assertHeader('Allow', headers)
355 # Make sure POSTs update already existings resources
356 self.getPage("/users/%d" % id, method='POST', body="name=%s" % updatedname)
357 self.assertBody("POST %d" % id)
358 self.assertHeader('Allow', headers)
360 # Make sure PUTs Update already existing resources.
361 self.getPage("/users/%d" % id, method='PUT', body="name=%s" % updatedname)
362 self.assertBody("PUT %d" % id)
363 self.assertHeader('Allow', headers)
365 # Make sure DELETES Remove already existing resources.
366 self.getPage("/users/%d" % id, method='DELETE')
367 self.assertBody("DELETE %d" % id)
368 self.assertHeader('Allow', headers)
371 # GET acts like a container
372 self.getPage("/users")
373 self.assertBody("[]")
374 self.assertHeader('Allow', 'GET, HEAD, POST')
376 def testVpathDispatch(self):
377 self.getPage("/decorated/")
378 self.assertBody("no params")
380 self.getPage("/decorated/hi")
381 self.assertBody("hi was not interpreted as 'a' param")
383 self.getPage("/decorated/yo/")
384 self.assertBody("a:yo")
386 self.getPage("/decorated/yo/there/")
387 self.assertBody("a:yo,b:there")
389 self.getPage("/decorated/yo/there/delete")
390 self.assertBody("deleting yo and there")
392 self.getPage("/decorated/yo/there/handled_by_dispatch/")
393 self.assertBody("custom")
395 self.getPage("/undecorated/blah/")
396 self.assertBody("index: blah")
398 self.getPage("/index_only/a/b/c/d/e/f/g/")
399 self.assertBody("IndexOnly index")
401 self.getPage("/parameter_test/argument2/")
402 self.assertBody("argument2")