Claudiu
Claudiu

Reputation: 229321

Unclean exist with twisted+wxPython

I'm using twistd. Here is the sole service in the application:

class GameClientService(internet.TCPClient):
    def __init__(self, serverHost, serverPort):
        self.wxApp = wx.App(False)
        reactor.registerWxApp(self.wxApp)
        self.lobbyFrame = gui.LobbyFrame()

        internet.TCPClient.__init__(self, serverHost, serverPort, LobbyProtocolFactory(self.lobbyFrame))

    def stopService(self):
        internet.TCPClient.stopService(self)
        print "Stop service!"
        destroyedD = defer.Deferred()
        self.lobbyFrame.CloseWithCallback(destroyedD.callback, True)
        print "close called!"
        def fired(result):
            print "'Destroyed' deferred has fired with %s" % (result,)
        destroyedD.addCallback(fired)
        return destroyedD

CloseWithCallback is defind on the wx.Frame as follows:

def CloseWithCallback(self, callback, *callbackArgs):
    def destroyed(event):
        event.Skip()
        callback(*callbackArgs)
    self.Bind(wx.EVT_WINDOW_DESTROY, destroyed)
    self.Close()

In the LobbyProtocol's factory, I stop the reactor if a connection fails:

def clientConnectionFailed(self, connector, reason):
    print "Client connection failed: %s" % reason.getErrorMessage()
    reactor.stop()

I run the client without a listening server, so the connection fails, yet some of the time (maybe more than half, but not always):

2012-11-12 18:43:29-0500 [-] Started connecting <twisted.internet.tcp.Connector instance at 0x030E3800>
2012-11-12 18:43:30-0500 [Uninitialized] Client connection failed: Connection was refused by other side: 10061: No connection could be made because the target machine actively refused it..
2012-11-12 18:43:30-0500 [Uninitialized] Stopping factory <network.LobbyProtocol.LobbyProtocolFactory instance at 0x030E3698>
2012-11-12 18:43:30-0500 [-] Stop service!
2012-11-12 18:43:30-0500 [-] 'Destroyed' deferred has fired with True
2012-11-12 18:43:30-0500 [-] Traceback (most recent call last):
2012-11-12 18:43:30-0500 [-]   File "C:\Python26\lib\site-packages\wx-2.8-msw-unicode\wx\_core.py", line 14669, in <lambda>
2012-11-12 18:43:30-0500 [-]     lambda event: event.callable(*event.args, **event.kw) )
2012-11-12 18:43:30-0500 [-]   File "C:\Python26\lib\site-packages\twisted\internet\_threadedselect.py", line 232, in _interleave
2012-11-12 18:43:30-0500 [-]     msg, args = self.toMainThread.get_nowait()
2012-11-12 18:43:30-0500 [-]   File "C:\Python26\lib\Queue.py", line 190, in get_nowait
2012-11-12 18:43:30-0500 [-]     return self.get(False)
2012-11-12 18:43:30-0500 [-]   File "C:\Python26\lib\Queue.py", line 165, in get
2012-11-12 18:43:30-0500 [-]     raise Empty
2012-11-12 18:43:30-0500 [-] Queue.Empty
2012-11-12 18:43:30-0500 [-] Server Shut Down.
2012-11-12 18:43:30-0500 [-] Server Shut Down.

This makes me uncomfortable. How can I make sure that traceback never runs? What have I done wrong?

Upvotes: 2

Views: 334

Answers (1)

Claudiu
Claudiu

Reputation: 229321

I have performed the appropriate ablutions and thus my code is now purified:

class CleanExitApp(wx.App):
    def __init__(self, *args, **kwargs):
        wx.App.__init__(self, *args, **kwargs)

        self.exitDeferreds = []

    def AddExitDeferred(self, exitDeferred):
        self.exitDeferreds.append(exitDeferred)

    def OnExit(self):
        print "OnExit"
        for exitDeferred in self.exitDeferreds:
            exitDeferred.callback(True)

class GameClientService(internet.TCPClient):
    def __init__(self, serverHost, serverPort):
        self.wxApp = CleanExitApp(False)
        reactor.registerWxApp(self.wxApp)
        self.lobbyFrame = gui.LobbyFrame() 

        internet.TCPClient.__init__(self, serverHost, serverPort, LobbyProtocolFactory(self.lobbyFrame))

    def stopService(self):
        internet.TCPClient.stopService(self)
        print "Stop service!"
        exitD = defer.Deferred()
        self.wxApp.AddExitDeferred(exitD)
        self.lobbyFrame.Close()
        print "close called!"
        def fired(result):
            print "'Destroyed' deferred has fired with %s" % (result,)
        exitD.addCallback(fired)
        return exitD

Which graces us with the output:

2012-11-12 18:56:15-0500 [-] Started connecting <twisted.internet.tcp.Connector instance at 0x032AB8C8>
2012-11-12 18:56:16-0500 [Uninitialized] Client connection failed: Connection was refused by other side: 10061: No connection could be made because the target machine actively refused it..
2012-11-12 18:56:16-0500 [Uninitialized] Stopping factory <network.LobbyProtocol.LobbyProtocolFactory instance at 0x032AB7B0>
2012-11-12 18:56:16-0500 [-] Stop service!
2012-11-12 18:56:16-0500 [-] close called!
2012-11-12 18:56:16-0500 [-] OnExit
2012-11-12 18:56:16-0500 [-] 'Destroyed' deferred has fired with True
2012-11-12 18:56:16-0500 [-] Server Shut Down.
2012-11-12 18:56:16-0500 [-] Server Shut Down.

Praise the lord!

One only wonders if the lord had a different message in mind... a more built-in one that would not require such tortured codes?

Upvotes: 2

Related Questions