diff --git a/wsme/api.py b/wsme/api.py index 9cadd28..da44f0f 100644 --- a/wsme/api.py +++ b/wsme/api.py @@ -1,5 +1,11 @@ +import traceback import functools import inspect +import logging + +import wsme.exc + +log = logging.getLogger(__name__) def iswsmefunction(f): @@ -130,3 +136,27 @@ class signature(object): return func sig = signature + + +def format_exception(excinfo, debug=False): + """Extract informations that can be sent to the client.""" + error = excinfo[1] + if isinstance(error, wsme.exc.ClientSideError): + r = dict(faultcode="Client", + faultstring=error.faultstring) + log.warning("Client-side error: %s" % r['faultstring']) + r['debuginfo'] = None + return r + else: + faultstring = str(error) + debuginfo = "\n".join(traceback.format_exception(*excinfo)) + + log.error('Server-side error: "%s". Detail: \n%s' % ( + faultstring, debuginfo)) + + r = dict(faultcode="Server", faultstring=faultstring) + if debug: + r['debuginfo'] = debuginfo + else: + r['debuginfo'] = None + return r diff --git a/wsme/pecan.py b/wsme/pecan.py index 3e70c54..7a478a8 100644 --- a/wsme/pecan.py +++ b/wsme/pecan.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import inspect import sys @@ -6,7 +8,7 @@ import wsme.rest.args import wsme.rest.json import wsme.rest.xml -pecan = sys.modules['pecan'] +import pecan class JSonRenderer(object): @@ -14,6 +16,8 @@ class JSonRenderer(object): pass def render(self, template_path, namespace): + if 'faultcode' in namespace: + return wsme.rest.json.encode_error(None, namespace) return wsme.rest.json.encode_result( namespace['result'], namespace['datatype'] @@ -25,6 +29,8 @@ class XMLRenderer(object): pass def render(self, template_path, namespace): + if 'faultcode' in namespace: + return wsme.rest.xml.encode_error(None, namespace) return wsme.rest.xml.encode_result( namespace['result'], namespace['datatype'] @@ -52,11 +58,20 @@ def wsexpose(*args, **kwargs): funcdef.resolve_types(wsme.types.registry) def callfunction(self, *args, **kwargs): - args, kwargs = wsme.rest.args.get_args( - funcdef, args, kwargs, - pecan.request.body, pecan.request.content_type - ) - result = f(self, *args, **kwargs) + try: + args, kwargs = wsme.rest.args.get_args( + funcdef, args, kwargs, + pecan.request.body, pecan.request.content_type + ) + result = f(self, *args, **kwargs) + except: + data = wsme.api.format_exception(sys.exc_info()) + if data['faultcode'] == 'Client': + pecan.response.status = 400 + else: + pecan.response.status = 500 + return data + return dict( datatype=funcdef.return_type, result=result diff --git a/wsme/root.py b/wsme/root.py index e19d7c0..e7de08c 100644 --- a/wsme/root.py +++ b/wsme/root.py @@ -1,6 +1,5 @@ import logging import sys -import traceback import weakref from six import u, b @@ -12,6 +11,7 @@ from wsme.exc import ClientSideError, MissingArgument, UnknownFunction from wsme.protocol import getprotocol from wsme.rest import scan_api from wsme import spore +import wsme.api import wsme.types log = logging.getLogger(__name__) @@ -200,7 +200,7 @@ class WSRoot(object): except Exception: e = sys.exc_info()[1] - infos = self._format_exception(sys.exc_info()) + infos = wsme.api.format_exception(sys.exc_info(), self._debug) if isinstance(e, ClientSideError): request.client_errorcount += 1 else: @@ -292,7 +292,7 @@ class WSRoot(object): res.status = protocol.get_response_status(request) res_content_type = protocol.get_response_contenttype(request) except Exception: - infos = self._format_exception(sys.exc_info()) + infos = wsme.api.format_exception(sys.exc_info(), self._debug) request.server_errorcount += 1 res.text = protocol.encode_error(context, infos) res.status = 500 @@ -325,29 +325,6 @@ class WSRoot(object): return f, fdef, args raise UnknownFunction('/'.join(path)) - def _format_exception(self, excinfo): - """Extract informations that can be sent to the client.""" - error = excinfo[1] - if isinstance(error, ClientSideError): - r = dict(faultcode="Client", - faultstring=error.faultstring) - log.warning("Client-side error: %s" % r['faultstring']) - r['debuginfo'] = None - return r - else: - faultstring = str(error) - debuginfo = "\n".join(traceback.format_exception(*excinfo)) - - log.error('Server-side error: "%s". Detail: \n%s' % ( - faultstring, debuginfo)) - - r = dict(faultcode="Server", faultstring=faultstring) - if self._debug: - r['debuginfo'] = debuginfo - else: - r['debuginfo'] = None - return r - def _html_format(self, content, content_types): try: from pygments import highlight