[IMP] xmlrpc: somewhat streamlined the exception types/
exception handling code. OpenERPDispatcherException which was simply wrapping an exception together with an exc_info is removed. bzr revid: vmt@openerp.com-20110927102246-87ibftawukc2d8lc
This commit is contained in:
parent
e8dc0edbaa
commit
08cfadaff0
|
@ -19,6 +19,14 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
""" OpenERP core exceptions.
|
||||
|
||||
This module defines a few exception types. Those types are understood by the
|
||||
RPC layer. Any other exception type bubbling until the RPC layer will be
|
||||
treated as a 'Server error'.
|
||||
|
||||
"""
|
||||
|
||||
class Warning(Exception):
|
||||
pass
|
||||
|
||||
|
@ -32,5 +40,19 @@ class AccessDenied(Exception):
|
|||
class AccessError(Exception):
|
||||
""" Access rights error. """
|
||||
|
||||
class DeferredException(Exception):
|
||||
""" Exception object holding a traceback for asynchronous reporting.
|
||||
|
||||
Some RPC calls (database creation and report generation) happen with
|
||||
an initial request followed by multiple, polling requests. This class
|
||||
is used to store the possible exception occuring in the thread serving
|
||||
the first request, and is then sent to a polling request.
|
||||
|
||||
('Traceback' is misleading, this is really a exc_info() triple.)
|
||||
"""
|
||||
def __init__(self, msg, tb):
|
||||
self.message = msg
|
||||
self.traceback = tb
|
||||
self.args = (msg, tb)
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -370,11 +370,6 @@ class Server:
|
|||
def _close_socket(self):
|
||||
close_socket(self.socket)
|
||||
|
||||
class OpenERPDispatcherException(Exception):
|
||||
def __init__(self, exception, traceback):
|
||||
self.exception = exception
|
||||
self.traceback = traceback
|
||||
|
||||
def replace_request_password(args):
|
||||
# password is always 3rd argument in a request, we replace it in RPC logs
|
||||
# so it's easier to forward logs for diagnostics/debugging purposes...
|
||||
|
@ -421,13 +416,18 @@ def dispatch_rpc(service_name, method, params):
|
|||
raise
|
||||
except openerp.exceptions.Warning:
|
||||
raise
|
||||
except openerp.exceptions.DeferredException, e:
|
||||
_log('exception', tools.exception_to_unicode(e))
|
||||
post_mortem(e.traceback)
|
||||
raise
|
||||
except Exception, e:
|
||||
_log('exception', tools.exception_to_unicode(e))
|
||||
tb = getattr(e, 'traceback', sys.exc_info())
|
||||
tb_s = "".join(traceback.format_exception(*tb))
|
||||
if tools.config['debug_mode'] and isinstance(tb[2], types.TracebackType):
|
||||
import pdb
|
||||
pdb.post_mortem(tb[2])
|
||||
raise OpenERPDispatcherException(e, tb_s)
|
||||
post_mortem(sys.exc_info())
|
||||
raise
|
||||
|
||||
def post_mortem(info):
|
||||
if tools.config['debug_mode'] and isinstance(info[2], types.TracebackType):
|
||||
import pdb
|
||||
pdb.post_mortem(info[2])
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -65,21 +65,13 @@ class TinySocketClientThread(threading.Thread):
|
|||
except socket.timeout:
|
||||
#terminate this channel because other endpoint is gone
|
||||
break
|
||||
except netsvc.OpenERPDispatcherException, e:
|
||||
try:
|
||||
new_e = Exception(tools.exception_to_unicode(e.exception)) # avoid problems of pickeling
|
||||
logging.getLogger('web-services').debug("netrpc: rpc-dispatching exception", exc_info=True)
|
||||
ts.mysend(new_e, exception=True, traceback=e.traceback)
|
||||
except Exception:
|
||||
#terminate this channel if we can't properly send back the error
|
||||
logging.getLogger('web-services').exception("netrpc: cannot deliver exception message to client")
|
||||
break
|
||||
except Exception, e:
|
||||
try:
|
||||
new_e = Exception(tools.exception_to_unicode(e)) # avoid problems of pickeling
|
||||
tb = getattr(e, 'traceback', sys.exc_info())
|
||||
tb_s = "".join(traceback.format_exception(*tb))
|
||||
logging.getLogger('web-services').debug("netrpc: communication-level exception", exc_info=True)
|
||||
ts.mysend(e, exception=True, traceback=tb_s)
|
||||
ts.mysend(new_e, exception=True, traceback=tb_s)
|
||||
break
|
||||
except Exception, ex:
|
||||
#terminate this channel if we can't properly send back the error
|
||||
|
|
|
@ -162,7 +162,7 @@ class db(netsvc.ExportService):
|
|||
self.actions.pop(id)
|
||||
return (1.0, users)
|
||||
else:
|
||||
e = self.actions[id]['exception']
|
||||
e = self.actions[id]['exception'] # TODO this seems wrong: actions[id]['traceback'] is set, but not 'exception'.
|
||||
self.actions.pop(id)
|
||||
raise Exception, e
|
||||
|
||||
|
@ -634,12 +634,6 @@ class wizard(netsvc.ExportService):
|
|||
# False -> True
|
||||
#
|
||||
|
||||
class ExceptionWithTraceback(Exception):
|
||||
def __init__(self, msg, tb):
|
||||
self.message = msg
|
||||
self.traceback = tb
|
||||
self.args = (msg, tb)
|
||||
|
||||
class report_spool(netsvc.ExportService):
|
||||
def __init__(self, name='report'):
|
||||
netsvc.ExportService.__init__(self, name)
|
||||
|
@ -678,7 +672,7 @@ class report_spool(netsvc.ExportService):
|
|||
(result, format) = obj.create(cr, uid, ids, datas, context)
|
||||
if not result:
|
||||
tb = sys.exc_info()
|
||||
self._reports[id]['exception'] = ExceptionWithTraceback('RML is not available at specified location or not enough data to print!', tb)
|
||||
self._reports[id]['exception'] = openerp.exceptions.DeferredException('RML is not available at specified location or not enough data to print!', tb)
|
||||
self._reports[id]['result'] = result
|
||||
self._reports[id]['format'] = format
|
||||
self._reports[id]['state'] = True
|
||||
|
@ -690,9 +684,9 @@ class report_spool(netsvc.ExportService):
|
|||
logger.notifyChannel('web-services', netsvc.LOG_ERROR,
|
||||
'Exception: %s\n%s' % (str(exception), tb_s))
|
||||
if hasattr(exception, 'name') and hasattr(exception, 'value'):
|
||||
self._reports[id]['exception'] = ExceptionWithTraceback(tools.ustr(exception.name), tools.ustr(exception.value))
|
||||
self._reports[id]['exception'] = openerp.exceptions.DeferredException(tools.ustr(exception.name), tools.ustr(exception.value))
|
||||
else:
|
||||
self._reports[id]['exception'] = ExceptionWithTraceback(tools.exception_to_unicode(exception), tb)
|
||||
self._reports[id]['exception'] = openerp.exceptions.DeferredException(tools.exception_to_unicode(exception), tb)
|
||||
self._reports[id]['state'] = True
|
||||
cr.commit()
|
||||
cr.close()
|
||||
|
@ -721,7 +715,7 @@ class report_spool(netsvc.ExportService):
|
|||
(result, format) = obj.create(cr, uid, ids, datas, context)
|
||||
if not result:
|
||||
tb = sys.exc_info()
|
||||
self._reports[id]['exception'] = ExceptionWithTraceback('RML is not available at specified location or not enough data to print!', tb)
|
||||
self._reports[id]['exception'] = openerp.exceptions.DeferredException('RML is not available at specified location or not enough data to print!', tb)
|
||||
self._reports[id]['result'] = result
|
||||
self._reports[id]['format'] = format
|
||||
self._reports[id]['state'] = True
|
||||
|
@ -733,9 +727,9 @@ class report_spool(netsvc.ExportService):
|
|||
logger.notifyChannel('web-services', netsvc.LOG_ERROR,
|
||||
'Exception: %s\n%s' % (str(exception), tb_s))
|
||||
if hasattr(exception, 'name') and hasattr(exception, 'value'):
|
||||
self._reports[id]['exception'] = ExceptionWithTraceback(tools.ustr(exception.name), tools.ustr(exception.value))
|
||||
self._reports[id]['exception'] = openerp.exceptions.DeferredException(tools.ustr(exception.name), tools.ustr(exception.value))
|
||||
else:
|
||||
self._reports[id]['exception'] = ExceptionWithTraceback(tools.exception_to_unicode(exception), tb)
|
||||
self._reports[id]['exception'] = openerp.exceptions.DeferredException(tools.exception_to_unicode(exception), tb)
|
||||
self._reports[id]['state'] = True
|
||||
cr.commit()
|
||||
cr.close()
|
||||
|
|
|
@ -36,6 +36,7 @@ import signal
|
|||
import sys
|
||||
import threading
|
||||
import time
|
||||
import traceback
|
||||
|
||||
import openerp
|
||||
import openerp.modules
|
||||
|
@ -46,7 +47,8 @@ import service.websrv_lib as websrv_lib
|
|||
# constants are also defined client-side and must remain in sync.
|
||||
# User code must use the exceptions defined in ``openerp.exceptions`` (not
|
||||
# create directly ``xmlrpclib.Fault`` objects).
|
||||
XML_RPC_FAULT_CODE_APPLICATION_ERROR = 2
|
||||
XML_RPC_FAULT_CODE_APPLICATION_ERROR = 1
|
||||
XML_RPC_FAULT_CODE_DEFERRED_APPLICATION_ERROR = 2
|
||||
XML_RPC_FAULT_CODE_ACCESS_DENIED = 3
|
||||
XML_RPC_FAULT_CODE_WARNING = 4
|
||||
XML_RPC_FAULT_CODE_ACCESS_ERROR = 5
|
||||
|
@ -77,13 +79,19 @@ def xmlrpc_return(start_response, service, method, params):
|
|||
except openerp.exceptions.AccessDenied, e:
|
||||
fault = xmlrpclib.Fault(XML_RPC_FAULT_CODE_ACCESS_DENIED, str(e))
|
||||
response = xmlrpclib.dumps(fault, allow_none=False, encoding=None)
|
||||
except openerp.netsvc.OpenERPDispatcherException, e:
|
||||
# TODO collapse this case with the next one.
|
||||
fault = xmlrpclib.Fault(2, openerp.tools.exception_to_unicode(e.exception) + '\n' + e.traceback)
|
||||
except openerp.exceptions.DeferredException, e:
|
||||
info = e.traceback
|
||||
# Which one is the best ?
|
||||
formatted_info = "".join(traceback.format_exception(*info))
|
||||
#formatted_info = openerp.tools.exception_to_unicode(e) + '\n' + info
|
||||
fault = xmlrpclib.Fault(XML_RPC_FAULT_CODE_DEFERRED_APPLICATION_ERROR, formatted_info)
|
||||
response = xmlrpclib.dumps(fault, allow_none=False, encoding=None)
|
||||
except:
|
||||
exc_type, exc_value, exc_tb = sys.exc_info()
|
||||
fault = xmlrpclib.Fault(1, "%s:%s" % (exc_type, exc_value))
|
||||
except Exception, e:
|
||||
info = sys.exc_info()
|
||||
# Which one is the best ?
|
||||
formatted_info = "".join(traceback.format_exception(*info))
|
||||
#formatted_info = openerp.tools.exception_to_unicode(e) + '\n' + info
|
||||
fault = xmlrpclib.Fault(XML_RPC_FAULT_CODE_APPLICATION_ERROR, formatted_info)
|
||||
response = xmlrpclib.dumps(fault, allow_none=None, encoding=None)
|
||||
start_response("200 OK", [('Content-Type','text/xml'), ('Content-Length', str(len(response)))])
|
||||
return [response]
|
||||
|
|
Loading…
Reference in New Issue