0

I've been toying with Quickly (the Canonical created program for rapid development of Python + GTK applications), and I'd like this particular app I'm starting to develop to wait until at least one interface is "up" and has a default route allocated to it by DHCP.

Here's my code thus far:

import gettext
import subprocess
import time
from multiprocessing import Process, Queue, current_process
from gettext import gettext as _
gettext.textdomain('launcher')

import gtk
import logging
logger = logging.getLogger('launcher')

from launcher_lib import Window
from launcher.AboutLauncherDialog import AboutLauncherDialog
from launcher.PreferencesLauncherDialog import PreferencesLauncherDialog

# See launcher_lib.Window.py for more details about how this class works
class LauncherWindow(Window):
    __gtype_name__ = "LauncherWindow"

    def finish_initializing(self, builder): # pylint: disable=E1002
        """Set up the main window"""
        super(LauncherWindow, self).finish_initializing(builder)

        self.AboutDialog = AboutLauncherDialog
        self.PreferencesDialog = PreferencesLauncherDialog

        self.ui.status_label.set_text("Waiting for the interface to come up")
        while True:
            if subprocess.call(["/sbin/ifconfig | grep Bcast"], shell=True) == 0 and subprocess.call(["netstat -rn | grep UG | grep 0.0.0.0"], shell=True) == 0:
                break
        self.ui.status_label.set_text("Loaded")

# There is more code after this, but this should be all that I 
# need to get the GUI to show a status line saying the interface
# is up... right???

Now, this is all well and good, but it's blocking the startup of the application, so it looks like it's just hung until the process returns true.

What I'd like to do is push this into a separate process, however, I'm a bit ^h^w^h lot of a novice with Python, and while I've found the multiprocessing library, I don't seem to be able to push the self.ui.status_label into anything I can re-use from the spawned processes.

For example, do I define a variable like this:

# after line:
logger = logging.getLogger('launcher')
# add this
status_label = None

And then refer to it like this:

# after line:
self.PreferencesDialog = PreferencesLauncherDialog
# add this
status_label = self.ui.status_label
# Then set it like this:
status_label.set_text("Waiting for the interface to come up")

Or, should I create a new class which only handles updating the status window (and if so, how should I do this), or... should I just throw the self.ui.status_label around whenever I want to set it? I've tried doing this:

def update_status(me):
    me.ui.status_label.set_text("Update me!")
    return True

# And then in the finish_initializing() code
update_status(self)

But that just said

NameError: global name 'self' is not defined

I'm trying my hardest, but I'm very confused right now, and, as I mentioned, Python isn't a language I'm at all familiar with, but I'm giving it a shot :)

P.S., I think this should have the tag "quickly", however, I don't have the reputation yet to create that tag.

Charles
  • 50,943
  • 13
  • 104
  • 142
JonTheNiceGuy
  • 601
  • 8
  • 23
  • Created the tag for you. I hope it won't get abused by the "g1ve m3 teh codez" folks. – Fred Foo Nov 16 '11 at 22:30
  • It's totally gonna be abused by people that don't understand the tagging system. As it's a product, how about `canonical-quickly`? – Charles Nov 16 '11 at 23:37

1 Answers1

2

I would use the threading module rather than the multiprocessing one: http://docs.python.org/library/threading.html

The reason for this is that a new thread will execute in the same context as the main program so it will be a lot easier to exchange data while a sub-process will have a different context. The way to do this would be to create a small class that provide a run() method (say InterfaceListener). Then in the constructor of your InterfaceListener class, make sure you pass the label and store it. Then in the run method, wait for the interface to come up and when it's up, update the label. Something like:

class InterfaceListener(object):
    def __init__(self, label):
        self.__label = label

    def run(self):
        while True:
            if  subprocess.call(["/sbin/ifconfig | grep Bcast"], shell=True) == 0 and
                subprocess.call(["netstat -rn | grep UG | grep 0.0.0.0"], shell=True) == 0:
                break
        self.__label.set_text("Loaded")

Then in your finish_initializing method above, just after the first self.ui.status_label.set_text, add something like this:

t = threading.Thread(target=InterfaceListener(self.ui.status_label))
t.start()

I haven't tested this so you may have to adapt. The other option is to use a Timer object to check the interface at regular intervals rather that using a while True loop.

Bruno Girin
  • 175
  • 2
  • 10
  • This didn't quite work, and for the life of me I couldn't figure out why not. Sadly, I've been distracted by another project and I need to fix that before I can come back to this. I may edit my original post with the current code based on this sample later. Thanks for now though Bruno! – JonTheNiceGuy Nov 23 '11 at 22:41