Volpe's Blog

My points of view, travels and code

Python

on Programming, Python

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 multiplatform and I have Py2exe to do the dirty job”. I was wrong.

I chose 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 package everything Django needs to work.

After a bit of try-error workflow I got a couple of windows 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 of this in a .exe file, I got nothing better than a “Unknown command: syncdb” from Django’s manage.py. I could only find this article talking about it and it is from 2008(!), which made it more frustrating.

I ended up calling SQLAlchemy for help!

it made me remember why I like the “web platform” so much, because I use the stack I want, and I only switch if something 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.

Continue reading →
on Programming, PyGTK, Python, Twisted

Twisted + PyGTK

A few weeks ago I started getting interested in Twisted and asynchronous programming. I really liked the way that Twisted handles events and callbacks.

I’ve been working on a program with a graphical interface built in PyGTK that uses threads for every single task and I wondered if I could have this program running in just one thread asynchronously. It’s really simple to implement twisted code in a PyGTK application 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 “understand” 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 self.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.

Continue reading →