[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):
|
class Warning(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -32,5 +40,19 @@ class AccessDenied(Exception):
|
||||||
class AccessError(Exception):
|
class AccessError(Exception):
|
||||||
""" Access rights error. """
|
""" 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:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -370,11 +370,6 @@ class Server:
|
||||||
def _close_socket(self):
|
def _close_socket(self):
|
||||||
close_socket(self.socket)
|
close_socket(self.socket)
|
||||||
|
|
||||||
class OpenERPDispatcherException(Exception):
|
|
||||||
def __init__(self, exception, traceback):
|
|
||||||
self.exception = exception
|
|
||||||
self.traceback = traceback
|
|
||||||
|
|
||||||
def replace_request_password(args):
|
def replace_request_password(args):
|
||||||
# password is always 3rd argument in a request, we replace it in RPC logs
|
# 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...
|
# so it's easier to forward logs for diagnostics/debugging purposes...
|
||||||
|
@ -421,13 +416,18 @@ def dispatch_rpc(service_name, method, params):
|
||||||
raise
|
raise
|
||||||
except openerp.exceptions.Warning:
|
except openerp.exceptions.Warning:
|
||||||
raise
|
raise
|
||||||
|
except openerp.exceptions.DeferredException, e:
|
||||||
|
_log('exception', tools.exception_to_unicode(e))
|
||||||
|
post_mortem(e.traceback)
|
||||||
|
raise
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
_log('exception', tools.exception_to_unicode(e))
|
_log('exception', tools.exception_to_unicode(e))
|
||||||
tb = getattr(e, 'traceback', sys.exc_info())
|
post_mortem(sys.exc_info())
|
||||||
tb_s = "".join(traceback.format_exception(*tb))
|
raise
|
||||||
if tools.config['debug_mode'] and isinstance(tb[2], types.TracebackType):
|
|
||||||
import pdb
|
def post_mortem(info):
|
||||||
pdb.post_mortem(tb[2])
|
if tools.config['debug_mode'] and isinstance(info[2], types.TracebackType):
|
||||||
raise OpenERPDispatcherException(e, tb_s)
|
import pdb
|
||||||
|
pdb.post_mortem(info[2])
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -65,21 +65,13 @@ class TinySocketClientThread(threading.Thread):
|
||||||
except socket.timeout:
|
except socket.timeout:
|
||||||
#terminate this channel because other endpoint is gone
|
#terminate this channel because other endpoint is gone
|
||||||
break
|
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:
|
except Exception, e:
|
||||||
try:
|
try:
|
||||||
|
new_e = Exception(tools.exception_to_unicode(e)) # avoid problems of pickeling
|
||||||
tb = getattr(e, 'traceback', sys.exc_info())
|
tb = getattr(e, 'traceback', sys.exc_info())
|
||||||
tb_s = "".join(traceback.format_exception(*tb))
|
tb_s = "".join(traceback.format_exception(*tb))
|
||||||
logging.getLogger('web-services').debug("netrpc: communication-level exception", exc_info=True)
|
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
|
break
|
||||||
except Exception, ex:
|
except Exception, ex:
|
||||||
#terminate this channel if we can't properly send back the error
|
#terminate this channel if we can't properly send back the error
|
||||||
|
|
|
@ -162,7 +162,7 @@ class db(netsvc.ExportService):
|
||||||
self.actions.pop(id)
|
self.actions.pop(id)
|
||||||
return (1.0, users)
|
return (1.0, users)
|
||||||
else:
|
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)
|
self.actions.pop(id)
|
||||||
raise Exception, e
|
raise Exception, e
|
||||||
|
|
||||||
|
@ -634,12 +634,6 @@ class wizard(netsvc.ExportService):
|
||||||
# False -> True
|
# 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):
|
class report_spool(netsvc.ExportService):
|
||||||
def __init__(self, name='report'):
|
def __init__(self, name='report'):
|
||||||
netsvc.ExportService.__init__(self, name)
|
netsvc.ExportService.__init__(self, name)
|
||||||
|
@ -678,7 +672,7 @@ class report_spool(netsvc.ExportService):
|
||||||
(result, format) = obj.create(cr, uid, ids, datas, context)
|
(result, format) = obj.create(cr, uid, ids, datas, context)
|
||||||
if not result:
|
if not result:
|
||||||
tb = sys.exc_info()
|
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]['result'] = result
|
||||||
self._reports[id]['format'] = format
|
self._reports[id]['format'] = format
|
||||||
self._reports[id]['state'] = True
|
self._reports[id]['state'] = True
|
||||||
|
@ -690,9 +684,9 @@ class report_spool(netsvc.ExportService):
|
||||||
logger.notifyChannel('web-services', netsvc.LOG_ERROR,
|
logger.notifyChannel('web-services', netsvc.LOG_ERROR,
|
||||||
'Exception: %s\n%s' % (str(exception), tb_s))
|
'Exception: %s\n%s' % (str(exception), tb_s))
|
||||||
if hasattr(exception, 'name') and hasattr(exception, 'value'):
|
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:
|
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
|
self._reports[id]['state'] = True
|
||||||
cr.commit()
|
cr.commit()
|
||||||
cr.close()
|
cr.close()
|
||||||
|
@ -721,7 +715,7 @@ class report_spool(netsvc.ExportService):
|
||||||
(result, format) = obj.create(cr, uid, ids, datas, context)
|
(result, format) = obj.create(cr, uid, ids, datas, context)
|
||||||
if not result:
|
if not result:
|
||||||
tb = sys.exc_info()
|
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]['result'] = result
|
||||||
self._reports[id]['format'] = format
|
self._reports[id]['format'] = format
|
||||||
self._reports[id]['state'] = True
|
self._reports[id]['state'] = True
|
||||||
|
@ -733,9 +727,9 @@ class report_spool(netsvc.ExportService):
|
||||||
logger.notifyChannel('web-services', netsvc.LOG_ERROR,
|
logger.notifyChannel('web-services', netsvc.LOG_ERROR,
|
||||||
'Exception: %s\n%s' % (str(exception), tb_s))
|
'Exception: %s\n%s' % (str(exception), tb_s))
|
||||||
if hasattr(exception, 'name') and hasattr(exception, 'value'):
|
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:
|
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
|
self._reports[id]['state'] = True
|
||||||
cr.commit()
|
cr.commit()
|
||||||
cr.close()
|
cr.close()
|
||||||
|
|
|
@ -36,6 +36,7 @@ import signal
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
import traceback
|
||||||
|
|
||||||
import openerp
|
import openerp
|
||||||
import openerp.modules
|
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.
|
# constants are also defined client-side and must remain in sync.
|
||||||
# User code must use the exceptions defined in ``openerp.exceptions`` (not
|
# User code must use the exceptions defined in ``openerp.exceptions`` (not
|
||||||
# create directly ``xmlrpclib.Fault`` objects).
|
# 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_ACCESS_DENIED = 3
|
||||||
XML_RPC_FAULT_CODE_WARNING = 4
|
XML_RPC_FAULT_CODE_WARNING = 4
|
||||||
XML_RPC_FAULT_CODE_ACCESS_ERROR = 5
|
XML_RPC_FAULT_CODE_ACCESS_ERROR = 5
|
||||||
|
@ -77,13 +79,19 @@ def xmlrpc_return(start_response, service, method, params):
|
||||||
except openerp.exceptions.AccessDenied, e:
|
except openerp.exceptions.AccessDenied, e:
|
||||||
fault = xmlrpclib.Fault(XML_RPC_FAULT_CODE_ACCESS_DENIED, str(e))
|
fault = xmlrpclib.Fault(XML_RPC_FAULT_CODE_ACCESS_DENIED, str(e))
|
||||||
response = xmlrpclib.dumps(fault, allow_none=False, encoding=None)
|
response = xmlrpclib.dumps(fault, allow_none=False, encoding=None)
|
||||||
except openerp.netsvc.OpenERPDispatcherException, e:
|
except openerp.exceptions.DeferredException, e:
|
||||||
# TODO collapse this case with the next one.
|
info = e.traceback
|
||||||
fault = xmlrpclib.Fault(2, openerp.tools.exception_to_unicode(e.exception) + '\n' + 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)
|
response = xmlrpclib.dumps(fault, allow_none=False, encoding=None)
|
||||||
except:
|
except Exception, e:
|
||||||
exc_type, exc_value, exc_tb = sys.exc_info()
|
info = sys.exc_info()
|
||||||
fault = xmlrpclib.Fault(1, "%s:%s" % (exc_type, exc_value))
|
# 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)
|
response = xmlrpclib.dumps(fault, allow_none=None, encoding=None)
|
||||||
start_response("200 OK", [('Content-Type','text/xml'), ('Content-Length', str(len(response)))])
|
start_response("200 OK", [('Content-Type','text/xml'), ('Content-Length', str(len(response)))])
|
||||||
return [response]
|
return [response]
|
||||||
|
|
Loading…
Reference in New Issue