views:

22

answers:

1

I'm using twisted with GTK, and the following code runs when a connection could not be established:

def connectionFailed(self, reason):
    #show a "connect failed" dialog
    dlg = gtk.MessageDialog(
        type=gtk.MESSAGE_ERROR,
        buttons=gtk.BUTTONS_CLOSE,
        message_format="Could not connect to server:\n%s" % (
            reason.getErrorMessage()))
    responseDF = defer.Deferred()
    dlg.set_title("Connection Error")
    def response(dialog, rid):
        dlg.hide_all()
        responseDF.callback(rid)
    dlg.connect("response", response)
    dlg.show_all()

    self.shutdownDeferreds.append(responseDF)

self.shutdownDeferreds is a list of deferreds that is set up so that the reactor does not stop until they are all called.

Now, I happened to press CTRL+C at the same time as the connection failed. The dialog did pop up, but when I press Close, I get:

Traceback (most recent call last):
  File "C:\Users\DrClaud\bumhunter\gui\controller.py", line 82, in response
    dlg.hide_all()
NameError: free variable 'dlg' referenced before assignment in enclosing scope
Traceback (most recent call last):
  File "C:\Users\DrClaud\bumhunter\gui\controller.py", line 82, in response
    dlg.hide_all()
NameError: free variable 'dlg' referenced before assignment in enclosing scope

Any ideas why that might happen?

+1  A: 

Shouldn't that be:

def response(dialog, rid):
    dialog.hide_all()
    responseDF.callback(rid)

or really, for clarity,

def response(self, rid):
    self.hide_all()
    responseDF.callback(rid)

(I might be wrong about this, I've done barely any GTK.) If so, the problem is that you are referencing dlg in the function, which makes it a closure (it captures dlg from its surrounding scope). The KeyboardInterrupt will cause weird and wonderful behaviour, because it could destroy that scope.

katrielalex
ah the latter sentence is what I'm curious about. how can `KeyboardInterrupt` destroy the scope, which is exactly what happened here? good tip about how to make that func not a closure though
Claudiu
Well, Python garbage-collects variables when they pass out of scope. If you raise an error, it will propagate up the stack, passing through various scopes; as each is left, its variables will be destroyed. I've never seen this particular behaviour before; maybe someone with more GTK experience than I will weigh in on it.
katrielalex
"Well, Python garbage-collects variables when they pass out of scope." No - it garbage collects *objects* (not variables) when they are no longer reachable from the root. The dialog here is still reachable, precisely because `dlg` is closed over. Something much weirder is happening in this example. :)
Jean-Paul Calderone
@Jean-Paul: Oops :$ -- thanks! I guess it's something to do with the GTK event loop being weird then...?
katrielalex