Py2exe + Django is a bad idea.

A client asked me to build a program to track and store their production record. He didn’t want a web app and it had to run on Windows. Well, I first thought “Most of the stack I use is multiPlattaform and I have Py2exe to do the dirty job”. I was wrong.

I choose to use the Django ORM to store the information and a sqlite as a backend, so I didn’t have to set up anything client-side. It was the most logical solution because as I concern the Django ORM + some South is a kick-ass. It turned out that it is very hard to tell Py2exe to packege everything Django needs to work.

After a bit of try-error workflow I got a couple of windos being able to store some data. Now, it was time to think about the schema migrations, as the client ask for further and more advanced features in the future.

After hours of trying to get all off this in a  .exe fil,  I got nothing better than a “Unknown command: syncdb” from Django’s manage.py. I could only found this article talking about it and it is from 2008(!), which made it more frustrating.

I ended up calling SQKalchemy for help!

it made me remember why I like the “web plattaform” so much, because I use the stack I want, and I only switch if somethings is faster, cheaper or has a better documentation, no only because my clients use it. Sadly, you can’t change your client’s stack. Unless you are Steve Jobs.

 

Twisted + PyGTK

A few weeks ago I starded interresting about Twisted and asynchronous programming. I realy liked the way that Twisted handles events and callbacks.

I’ve been working in a program with a graphical interface built in PyGTK that uses threads for every single taks and I wondered if I can had this program running in just one thread asynchronously. It’s realy simple implement twisted code in a PyGTK applicacion since both are event-based and Twisted has a native API to do so.

Let’s build a simple PyGTK example:

import gtk
 
class Gui:
    def __init__(self):
        self.window = gtk.Window()
        self.window.set_default_size(200,200)
        self.window.set_title("Simple PyGTK program")
 
        self.vbox = gtk.VBox()
 
        self.button = gtk.Button("I'm a button!")
        self.label = gtk.Label("Nothing here")
 
        self.vbox.pack_start(self.button)
        self.vbox.pack_start(self.label)
 
        self.window.add(self.vbox)
 
        self.button.connect("clicked", self.on_clicked)
        self.window.connect("destroy", lambda x: gtk.main_quit())
        self.window.show_all()
        self.window.show()
 
    def on_clicked(self, widget):
       self.label.set_text("You clicked the button!") 
 
if __name__ == "__main__":
    app = Gui()
    #starts the GTK loop
    gtk.main()

So, this example is using the Gtk loop. Twisted applications use the Twisted reactor, and we need the Twisted reactor to “understend” Gtk signals.
This is what you have to do:

from twisted.internet import gtk2reactor # for gtk-2.0
gtk2reactor.install()
 
#Your code
#...
 
from twisted.internet import reactor
#this starts the reactor
reactor.run()

Now we can re-implement our first example and it would look like this:

import gtk
from twisted.internet import gtk2reactor # for gtk-2.0
gtk2reactor.install() #this installs the gtk reactor
#NOTE: This have to be at top always, before importing the reactor
 
class Gui:
    def __init__(self):
        self.window = gtk.Window()
        self.window.set_default_size(200,200)
        self.window.set_title("Simple PyGTK program")
 
        self.vbox = gtk.VBox()
 
        self.button = gtk.Button("I'm a button!")
        self.label = gtk.Label("Nothing here")
 
        self.vbox.pack_start(self.button)
        self.vbox.pack_start(self.label)
 
        self.window.add(self.vbox)
 
        self.button.connect("clicked", self.on_clicked)
        self.window.connect("destroy", lambda x: gtk.main_quit())
        self.window.show_all()
        self.window.show()
 
    def on_clicked(self, widget):
       self.label.set_text("You clicked the button!") 
 
if __name__ == "__main__":
    app = Gui()
    #No Gtk anymore!
    #gtk.main()
    from twisted.internet import reactor
    #let's start the loop
    reactor.run()

Now you can enjoy the Twisted power in your graphical apps, here is a (very)simple example using Twisted-way callbacks.

import gtk
import time
from twisted.internet import gtk2reactor # for gtk-2.0
gtk2reactor.install() #this installs the gtk reactor
#NOTE: This have to be at top always, before starting the reactor
 
class Gui:
    def __init__(self):
        self.window = gtk.Window()
        self.window.set_default_size(200,200)
        self.window.set_title("Simple PyGTK program")
 
        self.vbox = gtk.VBox()
 
        self.button = gtk.Button("I'm a button!")
 
        self.time = time.time()
 
        self.label = gtk.Label("0")
 
        self.vbox.pack_start(self.button)
        self.vbox.pack_start(self.label)
 
        self.window.add(self.vbox)
 
        self.button.connect("clicked", self.on_clicked)
        self.window.connect("destroy", lambda x: gtk.main_quit())
        self.window.show_all()
        self.window.show()
        self.time = time.time()
 
    def on_clicked(self, widget=None):
        self.label_text = time.time() - self.time
        self.label.set_text("%.2fs" % self.label_text)
        #Twisted will call the sefl.on_clicked function every 100ms
        reactor.callLater(.1, self.on_clicked)
 
 
if __name__ == "__main__":
    app = Gui()
    #No Gtk anymore!
    #gtk.main()
    from twisted.internet import reactor
    #let's start the loop
    reactor.run()

Twisted also has APIS for others toolkits such as Tkinter, wxPython, Win32(Windows) and PyUI.
For more information you can visit the official documentation.