return data
def get(self, key, *args, **kwargs):
+ if args:
+ return {'detail': (key, args)}
return FooResource.elems[int(key)]
def delete(self, key):
FooResource.elems[int(key)] = data
return dict(key=key, **data)
- @detail_route(methods=['get'])
- def detail(self, key):
- return {'detail': key}
-
class FooArgs(RESTController):
@RESTController.args_from_json
def test_not_implemented(self):
self._put("/foo")
self.assertStatus(405)
+ body = self.jsonBody()
+ self.assertIsInstance(body, dict)
+ assert body['detail'] == 'Method not implemented.'
+ assert '405' in body['status']
+ assert 'traceback' in body
def test_args_from_json(self):
self._put("/fooargs/hello", {'name': 'world'})
def test_detail_route(self):
self._get('/foo/1/detail')
- self.assertJsonBody({'detail': '1'})
+ self.assertJsonBody({'detail': ['1', ['detail']]})
self._post('/foo/1/detail', 'post-data')
self.assertStatus(405)
"""
- def _not_implemented(self, obj_key, detail_route_name):
- if detail_route_name:
- try:
- methods = getattr(getattr(self, detail_route_name), 'detail_route_methods')
- except AttributeError:
- raise cherrypy.NotFound()
- else:
- methods = [method
- for ((method, _is_element), (meth, _))
- in self._method_mapping.items()
- if _is_element == obj_key is not None and hasattr(self, meth)]
+ def _not_implemented(self, is_sub_path):
+ methods = [method
+ for ((method, _is_element), (meth, _))
+ in self._method_mapping.items()
+ if _is_element == is_sub_path is not None and hasattr(self, meth)]
cherrypy.response.headers['Allow'] = ','.join(methods)
raise cherrypy.HTTPError(405, 'Method not implemented.')
('DELETE', True): ('delete', 204),
}
- def _get_method(self, obj_key, detail_route_name):
- if detail_route_name:
- try:
- method = getattr(self, detail_route_name)
- if not getattr(method, 'detail_route'):
- self._not_implemented(obj_key, detail_route_name)
- if cherrypy.request.method not in getattr(method, 'detail_route_methods'):
- self._not_implemented(obj_key, detail_route_name)
- return method, 200
- except AttributeError:
- self._not_implemented(obj_key, detail_route_name)
- else:
+ def _get_method(self, vpath):
+ is_sub_path = bool(len(vpath))
+ try:
method_name, status_code = self._method_mapping[
- (cherrypy.request.method, obj_key is not None)]
- method = getattr(self, method_name, None)
- if not method:
- self._not_implemented(obj_key, detail_route_name)
- return method, status_code
+ (cherrypy.request.method, is_sub_path)]
+ except KeyError:
+ self._not_implemented(is_sub_path)
+ method = getattr(self, method_name, None)
+ if not method:
+ self._not_implemented(is_sub_path)
+ return method, status_code
@cherrypy.expose
def default(self, *vpath, **params):
- cherrypy.config.update({
- 'error_page.default': json_error_page})
- obj_key, detail_route_name = self.split_vpath(vpath)
- method, status_code = self._get_method(obj_key, detail_route_name)
+ method, status_code = self._get_method(vpath)
if cherrypy.request.method not in ['GET', 'DELETE']:
method = RESTController._takes_json(method)
cherrypy.response.status = status_code
- obj_key_args = [obj_key] if obj_key else []
- return method(*obj_key_args, **params)
+ return method(*vpath, **params)
@staticmethod
def args_from_json(func):
return vpath[0], vpath[1]
-def detail_route(methods):
- def decorator(func):
- func.detail_route = True
- func.detail_route_methods = [m.upper() for m in methods]
- return func
- return decorator
-
-
class Session(object):
"""
This class contains all relevant settings related to cherrypy.session.