Python: Can't pop from an empty list
Question: I am creating a python program to detect and enable usb to usb data transfer
between usb storage drives. However I am having an issue with updating the
`dev_label` (device name of the drive) and passing it to `Exchange`. Here is
the code :

    
    
    serial_list=[]
    context = Context()
    monitor = Monitor.from_netlink(context)
    monitor.filter_by(subsystem='block',device_type='partition')
    observer = GUDevMonitorObserver(monitor)
    
    
    def device_connected(observer, device):
        Welcome.device_count+=1
    
        flag =False
        for iden in serial_list :
            if iden == device.__getitem__('ID_SERIAL_SHORT'):
                flag=True
    
        if flag ==False:
            serial_list.append(device.__getitem__('ID_SERIAL_SHORT'))
            Welcome.dev_label.append(str(device.__getitem__('ID_FS_LABEL')))
            size = len(Welcome.dev_label)
            label = gtk.Label('Device connected :: {0!r}'.format(Welcome.dev_label[size-1]))
            Welcome.vbox.pack_start(label)
            Welcome.window.show_all()
    
        if Welcome.device_count<2:
            label = gtk.Label('Connect the second device')
            Welcome.vbox.pack_start(label)
            Welcome.window.show_all()
    
    
        else :
            Exchange()
    
    observer.connect("device-added",device_connected)
    monitor.start()
    
    class Welcome:
        device_count = 0    
        window = gtk.Window()
        vbox= gtk.VBox(False, 5)
        dev_label = []
    
        def __init__(self):
    
            self.window.set_default_size(300, 300)
            self.window.set_title("Welcome")
    
            label = gtk.Label("Connect the desired device")
    
            self.vbox.pack_start(label)
            self.window.add(self.vbox)
    
            self.window.connect("destroy", lambda q: gtk.main_quit())
            self.window.show_all()
    
    class Exchange:
        window1 = gtk.Window(Welcome.dev_label.pop())
        window2 = gtk.Window(Welcome.dev_label.pop())
        def __init__(self):
    
            width = gtk.gdk.screen_get_default().get_width()
            height = gtk.gdk.screen_get_default().get_height()
    
            self.window1.resize(width/2,height)
            self.window2.resize(width/2,height)
    
            self.window2.move(self.window1.get_position()[0]+width/2, self.window1.get_position()[1])
    
            label = gtk.Label("Hello")
            self.window1.add(label)
    
            self.window1.connect("destroy" , lambda q : gtk.main_quit())
            self.window1.show_all()
    
            label = gtk.Label("World")
            self.window2.add(label)
    
            self.window2.connect("destroy",lambda q : gtk.main_quit())
            self.window2.show_all()        
    
    
    
    
    Welcome()
    gtk.main()
    

The error shown in the trace back is :

    
    
    Traceback (most recent call last):
      File "project.py", line 70, in <module>
        class Exchange:
      File "project.py", line 71, in Exchange
        window1 = gtk.Window(Welcome.dev_label.pop())
    IndexError: pop from empty list
    

I can't figure out how to synchronize all these event so that the compiler
doesn't throw an error. Values are being popped from `Welcome.dev_label` only
after they've been updated in `device_connected` so why does the compiler have
a problem? I am a python newbie so please be gentle.


Answer: This is not the compiler givin errors but the program.

You can change your class to this:

    
    
    import time
    class Exchange:
        while not Welcome.dev_label: time.sleep(0.001)
        window1 = gtk.Window(Welcome.dev_label.pop()) # line 4
        while not Welcome.dev_label: time.sleep(0.001)
        window2 = gtk.Window(Welcome.dev_label.pop())
    

This would be kind of a synchronization primitive given that only line 4 and 6
remove content. In general you would use a queue for this.

    
    
    import queue # Python3 # import Queue Python 2
    Welcome.dev_label # = queue.Queue()
    Welcome.dev_label.put(...) # instead of append
    Welcome.dev_label.get(...) # instead of pop
    

But I do not know wether your code uses threads and runs in parallel. If the
`time.sleep` example works then you can switch to a queue.

