[Twisted-Python] ClientFactory.connectionLost(connector, reason)

Tommi Virtanen tv at twistedmatrix.com
Sat Aug 3 04:58:40 EDT 2002


	Hi. I've been groaning about how Twisted loses
	the actual errors, and does not allow programs
	to accurately report them to the user. Here is
	some progress on fixing that..

	ClientFactory's connectionLost() method will get
	a new parameter "reason", which will be a 
	failure.Failure(SomeException()). There will be
	no backwards compatibility; I will fix atleast
	the code in the main tree that has tests (that
	succeeded before the patch!). If you want to ensure
	compatibility, start using "def connectionLost(connector,
	reason=None)" right now.

	At a later stage, Protocol's connectionLost will get
	an extra argument also, a reason as above. There
	will be backwards compatibility, but having a
	non-reason-taking Protocol will be deprecated from
	that moment on, with a warning message.


	Now, what I need from you guys is

	1) review the patch

	2) write TCP/Connector/ClientFactory/Protocol tests
	   about connectionLost (and ClientFactory.connectionFailed)

	3) fix cReactor

	4) fix win32eventreactor

	5) fix kqreactor

	6) test qtreactor

	7) test gtkreactor


	My current working patch is attached.

-- 
tv@{{hq.yok.utu,havoc,gaeshido}.fi,{debian,wanderer}.org,stonesoft.com}
double a,b=4,c;main(){for(;++a<2e6;c-=(b=-b)/a++);printf("%f\n",c);}
-------------- next part --------------
Index: doc/examples/echoclient_ssl.py
===================================================================
RCS file: /cvs/Twisted/doc/examples/echoclient_ssl.py,v
retrieving revision 1.1
diff -u -u -r1.1 echoclient_ssl.py
--- doc/examples/echoclient_ssl.py	31 Jul 2002 22:01:02 -0000	1.1
+++ doc/examples/echoclient_ssl.py	3 Aug 2002 08:40:44 -0000
@@ -68,8 +68,8 @@
         print 'connection failed:', reason.getErrorMessage()
         reactor.stop()
 
-    def connectionLost(self, connector):
-        print 'connection lost'
+    def connectionLost(self, connector, reason):
+        print 'connection lost:', reason.getErrorMessage()
         reactor.stop()
 
 factory = EchoClientFactory()
Index: doc/examples/ircLogBot.py
===================================================================
RCS file: /cvs/Twisted/doc/examples/ircLogBot.py,v
retrieving revision 1.7
diff -u -u -r1.7 ircLogBot.py
--- doc/examples/ircLogBot.py	24 Jul 2002 02:25:41 -0000	1.7
+++ doc/examples/ircLogBot.py	3 Aug 2002 08:40:44 -0000
@@ -91,7 +91,7 @@
         self.channel = channel
         self.filename = filename
 
-    def connectionLost(self, connector):
+    def connectionLost(self, connector, reason):
         connector.connect()
 
     def connectionFailed(self, connector, reason):
Index: twisted/internet/abstract.py
===================================================================
RCS file: /cvs/Twisted/twisted/internet/abstract.py,v
retrieving revision 1.25
diff -u -u -r1.25 abstract.py
--- twisted/internet/abstract.py	14 Jul 2002 03:19:49 -0000	1.25
+++ twisted/internet/abstract.py	3 Aug 2002 08:40:44 -0000
@@ -49,7 +49,7 @@
             from twisted.internet import reactor
         self.reactor = reactor
     
-    def connectionLost(self):
+    def connectionLost(self, reason):
         """The connection was lost.
 
         This is called when the connection on a selectable object has been
Index: twisted/internet/base.py
===================================================================
RCS file: /cvs/Twisted/twisted/internet/base.py,v
retrieving revision 1.13
diff -u -u -r1.13 base.py
--- twisted/internet/base.py	24 Jul 2002 05:22:58 -0000	1.13
+++ twisted/internet/base.py	3 Aug 2002 08:40:45 -0000
@@ -158,7 +158,7 @@
         for reader in selectables:
             try:
                 log.logOwner.own(reader)
-                reader.connectionLost()
+                reader.connectionLost(main.CONNECTION_LOST)
                 log.logOwner.disown(reader)
             except:
                 log.deferr()
Index: twisted/internet/default.py
===================================================================
RCS file: /cvs/Twisted/twisted/internet/default.py,v
retrieving revision 1.25
diff -u -u -r1.25 default.py
--- twisted/internet/default.py	29 Jul 2002 23:33:55 -0000	1.25
+++ twisted/internet/default.py	3 Aug 2002 08:40:45 -0000
@@ -25,6 +25,7 @@
 import os
 import socket
 import signal
+import sys
 
 from twisted.internet.interfaces import IReactorCore, IReactorTime, IReactorUNIX
 from twisted.internet.interfaces import IReactorTCP, IReactorUDP, IReactorSSL
@@ -32,7 +33,7 @@
 from twisted.internet import main, error, protocol, interfaces
 
 from twisted.internet import main, tcp, udp, task
-from twisted.python import log, threadable
+from twisted.python import log, threadable, failure
 from twisted.persisted import styles
 from twisted.python.runtime import platform
 
@@ -44,7 +45,7 @@
 except:
     sslEnabled = 0
 
-from main import CONNECTION_LOST, CONNECTION_DONE
+from main import CONNECTION_LOST
 
 if platform.getType() != 'java':
     import select
@@ -112,9 +113,9 @@
             # factory hasn't called our connect() method
             self.factory.doStop()
 
-    def connectionLost(self):
+    def connectionLost(self, reason):
         self.state = "disconnected"
-        self.factory.connectionLost(self)
+        self.factory.connectionLost(self, reason)
         if self.state == "disconnected":
             # factory hasn't called our connect() method
             self.factory.doStop()
@@ -527,16 +528,18 @@
                 try:
                     why = getattr(selectable, method)()
                     handfn = getattr(selectable, 'fileno', None)
-                    if not handfn or handfn() == -1:
-                        why = CONNECTION_LOST
+                    if not handfn:
+                        why = main.ConnectionFdescWentAway('Handler has no fileno method')
+                    elif handfn() == -1:
+                        why = main.ConnectionFdescWentAway('Filedescriptor went away')
                 except:
                     log.deferr()
-                    why = CONNECTION_LOST
+                    why = sys.exc_value
                 if why:
                     self.removeReader(selectable)
                     self.removeWriter(selectable)
                     try:
-                        selectable.connectionLost()
+                        selectable.connectionLost(failure.Failure(why))
                     except:
                         log.deferr()
                 log.logOwner.disown(selectable)
Index: twisted/internet/fdesc.py
===================================================================
RCS file: /cvs/Twisted/twisted/internet/fdesc.py,v
retrieving revision 1.1
diff -u -u -r1.1 fdesc.py
--- twisted/internet/fdesc.py	6 Jul 2002 15:17:30 -0000	1.1
+++ twisted/internet/fdesc.py	3 Aug 2002 08:40:45 -0000
@@ -26,7 +26,7 @@
     import FCNTL
 
 # twisted imports
-from main import CONNECTION_LOST, CONNECTION_DONE
+from main import CONNECTION_LOST
 
 
 def setNonBlocking(fd):
Index: twisted/internet/gtkreactor.py
===================================================================
RCS file: /cvs/Twisted/twisted/internet/gtkreactor.py,v
retrieving revision 1.4
diff -u -u -r1.4 gtkreactor.py
--- twisted/internet/gtkreactor.py	7 Jul 2002 05:34:34 -0000	1.4
+++ twisted/internet/gtkreactor.py	3 Aug 2002 08:40:45 -0000
@@ -114,12 +114,12 @@
                 method = getattr(source, cbName)
                 why = method()
             except:
-                why = main.CONNECTION_LOST
+                why = sys.exc_value
                 log.msg('Error In %s.%s' %(source,cbName))
                 log.deferr()
             if why:
                 try:
-                    source.connectionLost()
+                    source.connectionLost(why)
                 except:
                     log.deferr()
                 self.removeReader(source)
Index: twisted/internet/main.py
===================================================================
RCS file: /cvs/Twisted/twisted/internet/main.py,v
retrieving revision 1.78
diff -u -u -r1.78 main.py
--- twisted/internet/main.py	7 Jul 2002 03:58:07 -0000	1.78
+++ twisted/internet/main.py	3 Aug 2002 08:40:46 -0000
@@ -18,8 +18,14 @@
 
 # System Imports
 import socket
-CONNECTION_LOST = -1
-CONNECTION_DONE = -2
+class ConnectionLost(Exception):
+    pass
+CONNECTION_LOST = ConnectionLost('Connection lost')
+class ConnectionDone(Exception):
+    pass
+CONNECTION_DONE = ConnectionDone('Connection done')
+class ConnectionFdescWentAway(Exception):
+    pass
 
 # Twisted Imports
 
Index: twisted/internet/pollreactor.py
===================================================================
RCS file: /cvs/Twisted/twisted/internet/pollreactor.py,v
retrieving revision 1.4
diff -u -u -r1.4 pollreactor.py
--- twisted/internet/pollreactor.py	7 Jul 2002 02:02:57 -0000	1.4
+++ twisted/internet/pollreactor.py	3 Aug 2002 08:40:46 -0000
@@ -25,10 +25,10 @@
 """
 
 # System imports
-import select, errno
+import select, errno, sys
 
 # Twisted imports
-from twisted.python import log, threadable
+from twisted.python import log, threadable, failure
 from twisted.internet import main, default
 
 # globals
@@ -139,16 +139,16 @@
                     if not why and event & POLLOUT:
                         why = selectable.doWrite()
                     if not selectable.fileno() == fd:
-                        why = main.CONNECTION_LOST
+                        why = main.ConnectionFdescWentAway('Filedescriptor went away')
                 except:
                     log.deferr()
-                    why = main.CONNECTION_LOST
+                    why = sys.exc_value
 
             if why:
                 self.removeReader(selectable)
                 self.removeWriter(selectable)
                 try:
-                    selectable.connectionLost()
+                    selectable.connectionLost(failure.Failure(why))
                 except:
                     log.deferr()
 
Index: twisted/internet/protocol.py
===================================================================
RCS file: /cvs/Twisted/twisted/internet/protocol.py,v
retrieving revision 1.11
diff -u -u -r1.11 protocol.py
--- twisted/internet/protocol.py	28 Jul 2002 18:43:54 -0000	1.11
+++ twisted/internet/protocol.py	3 Aug 2002 08:40:46 -0000
@@ -108,7 +108,7 @@
     def connectionFailed(self, connector, reason):
         """Called when a connection has failed."""
 
-    def connectionLost(self, connector):
+    def connectionLost(self, connector, reason):
         """Called when a connection is lost.
 
         It may be useful to call connector.connect() - this will reconnect.
Index: twisted/internet/ptypro.py
===================================================================
RCS file: /cvs/Twisted/twisted/internet/ptypro.py,v
retrieving revision 1.2
diff -u -u -r1.2 ptypro.py
--- twisted/internet/ptypro.py	15 Jul 2002 22:10:59 -0000	1.2
+++ twisted/internet/ptypro.py	3 Aug 2002 08:40:46 -0000
@@ -25,7 +25,7 @@
 
 # Sibling Imports
 import abstract, main, fdesc, process
-from main import CONNECTION_LOST, CONNECTION_DONE
+from main import CONNECTION_LOST
 
 
 class Process(abstract.FileDescriptor, styles.Ephemeral):
Index: twisted/internet/qtreactor.py
===================================================================
RCS file: /cvs/Twisted/twisted/internet/qtreactor.py,v
retrieving revision 1.4
diff -u -u -r1.4 qtreactor.py
--- twisted/internet/qtreactor.py	29 Jul 2002 19:54:19 -0000	1.4
+++ twisted/internet/qtreactor.py	3 Aug 2002 08:40:46 -0000
@@ -30,6 +30,7 @@
 
 # System Imports
 from qt import QSocketNotifier, QObject, SIGNAL, QTimer, QApplication
+import sys
 
 # Twisted Imports
 from twisted.python import log, threadable
@@ -68,12 +69,12 @@
         try:
             why = w.doRead()
         except:
-            why = main.CONNECTION_LOST
+            why = sys.exc_value
             log.msg('Error in %s.doRead()' % w)
             log.deferr()
         if why:
             try:
-                w.connectionLost()
+                w.connectionLost(why)
             except:
                 log.deferr()
             self.reactor.removeReader(w)
@@ -87,12 +88,12 @@
         try:
             why = w.doWrite()
         except:
-            why = main.CONNECTION_LOST
+            why = sys.exc_value
             log.msg('Error in %s.doWrite()' % w)
             log.deferr()
         if why:
             try:
-                w.connectionLost()
+                w.connectionLost(why)
             except:
                 log.deferr()
             self.reactor.removeReader(w)
Index: twisted/internet/tcp.py
===================================================================
RCS file: /cvs/Twisted/twisted/internet/tcp.py,v
retrieving revision 1.84
diff -u -u -r1.84 tcp.py
--- twisted/internet/tcp.py	30 Jul 2002 21:16:01 -0000	1.84
+++ twisted/internet/tcp.py	3 Aug 2002 08:40:47 -0000
@@ -127,10 +127,10 @@
         except socket.error:
             pass
     
-    def connectionLost(self):
+    def connectionLost(self, reason):
         """See abstract.FileDescriptor.connectionLost().
         """
-        abstract.FileDescriptor.connectionLost(self)
+        abstract.FileDescriptor.connectionLost(self, reason)
         self._closeSocket()
         protocol = self.protocol
         del self.protocol
@@ -241,12 +241,12 @@
         self.protocol.makeConnection(self)
         self.logstr = self.protocol.__class__.__name__+",client"
     
-    def connectionLost(self):
+    def connectionLost(self, reason):
         if not self.connected:
             self.failIfNotConnected(error.ConnectError())
         else:
-            Connection.connectionLost(self)
-            self.connector.connectionLost()
+            Connection.connectionLost(self, reason)
+            self.connector.connectionLost(reason)
 
     def getHost(self):
         """Returns a tuple of ('INET', hostname, port).
@@ -498,15 +498,16 @@
         self.disconnecting = 1
         self.stopReading()
         if self.connected:
-            self.reactor.callLater(0, self.connectionLost)
+            self.reactor.callLater(0, self.connectionLost,
+                                   main.CONNECTION_DONE)
 
     stopListening = loseConnection
 
-    def connectionLost(self):
+    def connectionLost(self, reason):
         """Cleans up my socket.
         """
         log.msg('(Port %s Closed)' % self.port)
-        abstract.FileDescriptor.connectionLost(self)
+        abstract.FileDescriptor.connectionLost(self, reason)
         self.connected = 0
         self.socket.close()
         if self.unixsocket:
Index: twisted/protocols/loopback.py
===================================================================
RCS file: /cvs/Twisted/twisted/protocols/loopback.py,v
retrieving revision 1.11
diff -u -u -r1.11 loopback.py
--- twisted/protocols/loopback.py	29 Jul 2002 17:42:36 -0000	1.11
+++ twisted/protocols/loopback.py	3 Aug 2002 08:40:47 -0000
@@ -89,7 +89,7 @@
     def buildProtocol(self, addr):
         return self.protocol
 
-    def connectionLost(self, connector):
+    def connectionLost(self, connector, reason):
         self.disconnected = 1
 
 


More information about the Twisted-Python mailing list