[Twisted-Python] Trouble with pb.CopyableFailure

I am trying to get pb.CopyableFailure to work, but am getting unexpected results. The following module is imported by both client and server. --------------------- #!/usr/local/bin/python """ errors.py """ from twisted.spread import pb, jelly class Error(pb.Error): """Base class for exceptions in this module.""" pass class WebViewOnDifferentServer(Error, pb.CopyableFailure, pb.RemoteCopy): def __init__(self, viewTag, server): Error.__init__(self) pb.CopyableFailure.__init__(self) self.viewTag = viewTag self.server = server def __str__(self): return "WebViewOnDifferentServer: viewTag=%s, server=%s" % (self.viewTag, self.server) --------------------- The client and server both contain the following 2 lines of code. from ratcontrol import errors pb.setUnjellyableForClass(errors.WebViewOnDifferentServer, errors.WebViewOnDifferentServer) The server raises an exception as follows. ---------------- if view.serverHost != config.thisServer: ## We can't remove web views unless we're local, since they don't ## have a global path. log.msg("Web view '%s' cannot be removed because it isn't on this server." % tag) raise errors.WebViewOnDifferentServer(view.tag, view.serverHost) ----------------- The server displays the following to the log. 2004/11/10 15:54 Eastern Standard Time [Broker,0,10.113.53.10] User justin logged in 2004/11/10 15:54 Eastern Standard Time [Broker,0,10.113.53.10] rmview(testview1, False) 2004/11/10 15:54 Eastern Standard Time [-] Web view 'testview1' cann ot be removed because it isn't on this server. 2004/11/10 15:54 Eastern Standard Time [-] Peer will receive following PB traceback: 2004/11/10 15:54 Eastern Standard Time [-] Failure: None: None The failure that the client gets is None. Does anyone know what I'm doing wrong here? I've searched through the docs but don't see specific examples of how to use CopyableFailure, so I made the assumption that I could raise a CopyableFailure instead of specifically writing code to send the failure back to the client. Any help is appreciated. Thanks. -Justin

Justin Johnson <justinjohnson@gmail.com> writes:
Does anyone know what I'm doing wrong here? I've searched through the docs but don't see specific examples of how to use CopyableFailure, so I made the assumption that I could raise a CopyableFailure instead of specifically writing code to send the failure back to the client. Any help is appreciated.
I don't think CopyableFailure is supported in that manner. The support for returning information on remote exceptions is in pb.py in the _recvMessage function of the Broker class. In general: * If the exception is a subclass of pb.Error then it is wrapped in a CopyableFailure (using the exception information) and without any local logging of the exception. * For any other exception a CopyableFailure is created using the current exception information (sys.exc_info()) and that is sent back along with local logging of the exception. The use of CopyableFailure is pretty much an internal implementation detail in order to get the Failure instance across to the remote client, and doesn't appear to be designed to be subclassed. So it depends on what you're trying to do. If you just want to get the failure indication back to your client, you should just be able to raise any old exception (subclass pb.Error if you don't want a local log about the exception), and it will get passed over automatically, and show up as a Failure object suitable for use with errbacks, failure.trap() and so on. If however you specifically want to get across your custom exception with additional information, you'll have some issues with or without CopyableFailure, since the eventual CopyableFailure that such remote transmissions get wrapped in transmits the actual exception instance turned into a string name and without any local exception instance data. It still works fine with twisted code for errbacks and failure.trap() since that code knows how to match up a failure by class name, but it bit us when we specifically wanted the remote side to have access to a functioning custom exception object with additional attributes. While we haven't done it yet, the only way we anticipate to handle this is with some local modifications to how the exceptions are transmitted through the CopyableFailure process (either simply pickling the exception in our case since we understand our security environment, or reusing existing jelly registration for the underlying exception class). -- David

Thanks for the reply. Yes, I am trying to pass back my custom failure with its attributes. I had a feeling this might be the case, so for now I did pattern matching on the string representation of the failure once passed back and extracted the attributes that way, since the attributes I need are just strings anyway. Pretty hacky, but it'll have to do for now. -Justin On 11 Nov 2004 14:38:30 -0500, David Bolen <db3l@fitlinxx.com> wrote:
Justin Johnson <justinjohnson@gmail.com> writes:
Does anyone know what I'm doing wrong here? I've searched through the docs but don't see specific examples of how to use CopyableFailure, so I made the assumption that I could raise a CopyableFailure instead of specifically writing code to send the failure back to the client. Any help is appreciated.
I don't think CopyableFailure is supported in that manner. The support for returning information on remote exceptions is in pb.py in the _recvMessage function of the Broker class. In general:
* If the exception is a subclass of pb.Error then it is wrapped in a CopyableFailure (using the exception information) and without any local logging of the exception. * For any other exception a CopyableFailure is created using the current exception information (sys.exc_info()) and that is sent back along with local logging of the exception.
The use of CopyableFailure is pretty much an internal implementation detail in order to get the Failure instance across to the remote client, and doesn't appear to be designed to be subclassed.
So it depends on what you're trying to do. If you just want to get the failure indication back to your client, you should just be able to raise any old exception (subclass pb.Error if you don't want a local log about the exception), and it will get passed over automatically, and show up as a Failure object suitable for use with errbacks, failure.trap() and so on.
If however you specifically want to get across your custom exception with additional information, you'll have some issues with or without CopyableFailure, since the eventual CopyableFailure that such remote transmissions get wrapped in transmits the actual exception instance turned into a string name and without any local exception instance data. It still works fine with twisted code for errbacks and failure.trap() since that code knows how to match up a failure by class name, but it bit us when we specifically wanted the remote side to have access to a functioning custom exception object with additional attributes. While we haven't done it yet, the only way we anticipate to handle this is with some local modifications to how the exceptions are transmitted through the CopyableFailure process (either simply pickling the exception in our case since we understand our security environment, or reusing existing jelly registration for the underlying exception class).
-- David
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
participants (2)
-
David Bolen
-
Justin Johnson