[Zope-dev] ZPublisher XMLRPC extension for user exceptions (II)

Illarramendi Amilibia, Aitor aillarramendi@indra.es
Fri, 28 Feb 2003 09:01:21 +0100


Hello everybody:

    I hope I've send it in the proper format this time :) I apologize =
for the first post I made, that was the corporative mail tool that =
automated all the e-mail...
=20
    I'm making some kind of development related to invoke externally =
from a Java Applet some ZOPE product methods via XML-RPC.
=20
    I use ZOPE as the XMLRPC server, as it can 'listen' for XMLRPC =
requests, find the method requested using URL and traversal, invoke the =
method and receive the return value of it and then encapsulate the =
result in a XMLRPC response.
=20
    Anyways, I want to report some exceptions from my ZOPE product =
python methods through XML-RPC to the applet. As my methods don't work =
directly with XMLRPC, all is embedded inside ZOPE, all the XMLRPC works =
are transparent for my python methods, so I didn't realize how I could =
do it.
=20
    After looking for the ZOPE code responsible of the XMLRPC request =
process and XMLRPC response generation I found that some of the work was =
being done in ZPublisher xmlrpc.py code (Response stuff).
=20
    Then when I started to read the comments of the code I found this in =
the Response class of the code:
=20
            """ It's probably possible to improve the 'exception' method =
quite a bit. The current implementation, however, should suffice for =
now. """
=20
    But as you will see is not enough, at least for my needs.
=20
    I want to define my own exceptions in my product, this exceptions =
could be defined as follows:
=20
        class MyOwnException:
            __init__(self, faultCode, faultString):
                self.faultCode =3D faultCode
                self.faultString =3D faultString
=20
        Obviously I want to map XMLRPC-like fault format.
=20
        Then, I could raise this exception from my method, and I will =
want that the class responsible of making the XMLRPC Response for my =
XMLRPC client will use it for composing the XML for XMLRPC using my =
fault code and fault string.
=20
        But I found that xmlrpc.py doesn't take into account that (i'm =
talking of ZOPE 2.6.0) so i had to make some changes in the code of =
ZPublisher/xmlrpc.py:
=20
            def exception(self, fatal=3D0, info=3DNone,
                  absuri_match=3DNone, tag_search=3DNone):
                  # Fetch our exception info. t is type, v is value and =
tb is the
                  # traceback object.
                  if type(info) is type(()) and len(info)=3D=3D3: t,v,tb =
=3D info
                  else:=20
                      t,v,tb =3D sys.exc_info()
 =20
                  # Don't mask 404 respnses, as some XML-RPC libraries =
rely on the HTTP
                  # mechanisms for detecting when authentication is =
required. Fixes Zope
                  # Collector issue 525.
                  if t =3D=3D 'Unauthorized' or (isinstance(t, =
types.ClassType)
                                   and issubclass(t, Unauthorized)):
                    return self._real.exception(fatal=3Dfatal, =
info=3Dinfo)
=20
                  # Create an appropriate Fault object. Containing error =
information
                  Fault=3Dxmlrpclib.Fault
                  f=3DNone
                  try:
                    # Strip HTML tags from the error value
                    v =3D str(v)
                    remove =3D [r"<[^<>]*>", r"&[A-Za-z]+;"]
                    for pat in remove:
                        v =3D re.sub(pat, " ", v)
                        from Globals import DevelopmentMode
                        if DevelopmentMode:
                            from traceback import format_exception
                            value =3D '\n' + ''.join(format_exception(t, =
v, tb))
                        else:
                            value =3D '%s - %s' % (t, v)
               =20
                        ######  my own extension for catching user =
exceptions START #####
                        try:
                          faultCode =3D =
getattr(sys.exc_info()[1],'faultCode')
                          faultString =3D =
getattr(sys.exc_info()[1],'faultString')
                        except:
                          print "no according exception type"
                        ######  my own extension for catching user =
exceptions FINISH #####
                        if isinstance(v, Fault):
                            f=3Dv=20
                        ###### my own extension for catching user =
exceptions START #####
                        elif (faultCode and faultString) :
                            f =3D xmlrpclib.Fault(faultCode,faultString)
                        ###### my own extension for catching user =
exceptions FINISH ######
                        elif isinstance(v, Exception):
                            f=3DFault(-1, 'Unexpected Zope exception: =
%s' % value)
                        else:
                            f=3DFault(-2, 'Unexpected Zope error value: =
%s' % value)
                  except:
                      f=3DFault(-3, "Unknown Zope fault type")
=20
                  # Do the damage.
                  self.setBody(f)
                  self._real.setStatus(200)
=20
                  return tb
=20
        By that way, I could send my own fault code and fault =
descriptions via XML-RPC.
=20
        But as you can see, I have to extend ZOPE code, and I don't want =
to do it, I have to work with standard releases of ZOPE.
=20
        Do you think that something like that would be improved in an =
early future for next ZOPE releases?
=20
        Any opinion will be really appreciated.
=20
        Thanks for advance.
=20
Regards.

Aitor Illarramendi Amilibia
 Ingeniero de software
Mando y Control=20
=20
 Carretera de Loeches, 9
28850 - Torrej=F3n de Ardoz, Madrid (ESPA=D1A)
Tel: +34-91-626.80.60
Fax: +34-91-626.81.14
aillarramendi@indra.es
www.indra.es