Tuesday 21 February 2012

Creating standalone windows application with python

Here in this post we will see how to convert a python application into a standalone windows executable. So that, windows users can run them without installing windows binaries of python and its related libraries separately.

In this we will write a small python code which uses the pubsub and pygtk libraries. And we shall see, how to write the setup script for it using py2exe and cx_Freeze in order to produce a standalone windows application.

Introduction

The job of a packaging/distribution tool is to build a list of dependent modules that are needed for the python application and include those modules for packaging. The list of dependent modules are specified via packaging options provided in the conventional setup.py file and/or by recursively finding the modules from the import statements used in the code.

There are certain limitations when a packaging tool tries to find the dependent modules from the import statements. If the python code imports modules using the  __import__ statement or if the python code modifies the sys.path at runtime in order to import certain modules, then those modules will not be found successfully by the packaging tool.

Python pubsub package

The pubsub module supports two different messaging protocols namely args1 and kwargs. Choosing and switching between these protocols are done by modifying the module path dynamically. This can result in import error like this during runtime.

      from listenerimpl import Listener, ListenerValidator
      ImportError: No module named listenerimpl

This is the main reason I choose pubsub for my example. In the following sections we shall see how to package them successfully for windows.

Sample code

Lets consider a sample application consisting of a single file named say testpubsub.py with the following code

from pubsub import pub
import gtk

def listener1(msg):
    ms = gtk.MessageDialog(None, 0, gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE,
                           "The listener received the message : %s" % (msg, ))
    ms.run()
    ms.destroy()

pub.subscribe(listener1, 'test.pubsub')

def sender():
    pub.sendMessage('test.pubsub', msg="Hola! this is a test message")

if __name__ == "__main__":
    sender()

In the above application, the listener displays the message received from the sender using gtk's message dialog popup. Now, we shall see, how to write the conventional setup.py file for it, using py2exe and cx_Freeze.

Setup file using py2exe

The setup.py using py2exe would look something like this

from distutils.core import setup

try:
    import py2exe
except:
    pass

setup (
    name='TestPubSub',
    description="Script to test pubsub for packaging",
    version="0.1",
    windows=[{'script': 'testpubsub.py'}],
    platforms=["any"],
    options={ 'py2exe': {
            'packages': 'encodings, pubsub',
            'includes': 'cairo, pango, pangocairo, atk, gobject, gio'}
              },
    )

Here we can see the packages option specified for py2exe, to include the encodings and pubsub packages explicitly. This will include the entire pubsub (and encodings) modules from the installation location for packaging.

As the final package has the entire pubsub module, the windows executable will have no trouble in finding the dynamic protocol libraries during runtime.

To generate exe file, run the following in the build machine (i.e. a windows machine with python and necessary library dependencies installed)

   $ python setup.py py2exe

this will produce a standalone windows executable file named testpubsub.exe

Setup file using cx_Freeze

The setup.py using cx_Freeze would look something like this

from cx_Freeze import setup, Executable
import platform

if platform.system() == 'Windows':
    bse = 'Win32GUI'
else:
    bse = None

opts = { 'compressed' : True,
         'create_shared_zip' : False,
         'packages' : ['pubsub.core.kwargs', 'pubsub.core.arg1'],
         }

WIN_Target = Executable(
    script='testpubsub.py',
    base=bse,
    targetName='testpubsub.exe',
    compress=True,
    appendScriptToLibrary=False,
    appendScriptToExe=True
    )

setup(
    name='TestPubSub',
    description="Script to test pubsub for packaging",
    version='0.1',
    options={'build_exe' : opts},
    executables=[WIN_Target]
    )

The packages option slightly differs for cx_Freeze. Here we have to explicitly include the sub packages of pubsub library namely, pubsub.core.kwargs and pubsub.core.arg1 so that, all the modules under them gets included for packaging.

Run the following in the build machine to generate the exe file

   $ python setup.py build

We can safely ignore the missing modules warning in the build log

   Missing modules:
   ? core.publisher imported from pubsub.pub
   ? listenerimpl imported from pubsub.core.listener
   ? publishermixin imported from pubsub.core.topicobj
   ? topicargspecimpl imported from pubsub.core.topicargspec
   ? topicmgrimpl imported from pubsub.core.topicmgr

The above listed missing modules are under pubsub.core.kwargs and pubsub.core.arg1. In cx_Freeze, the list of dependent modules are gathered from the import statements used in the code. While constructing this list, cx_Freeze reports missing modules, when a particular module has been imported in the code but not found in sys.path. But, as we have included those modules directly via the packages option, these modules will get safely included in the package. So, there won't be any runtime error.

Voila! We have created a standalone windows application from a python script. :)

Saturday 18 February 2012

Quick fix for Linux power regression problem

Linux Power Regression is yet another flame topic within the open source community. Where one group says that the sky isn't falling. Whereas the other group claims that, starting from kernel versions 2.6.38 the battery's backup time is reduced by 50% and the CPU temperature runs all time high. But, no one mentions the optimal temperature range.

To check this on my T420 thinkpad which has the sandy bridge processor, I ran the sensors command, which reported the processor temperature as 73° in spite of, CPU being idle. This was very alarming.

On further digging, we can find that this is an issue partly related to BIOS, where it indicates erroneously to the kernel that the PCI Express Active State Power Management (ASPM) isn't supported for the board which has that feature.

Moreover, it seems that, in the intel graphics driver i915, RC6 feature (which allows the GPU to enter a lower power state when it is idling) is not enabled by default.

So, here is the quick fix
  1. Open the /etc/default/grub file
  2. Add these parameters to the variable GRUB_CMDLINE_LINUX_DEFAULT "quiet splash i915.i915_enable_rc6=1 pcie_aspm=force"
  3. Then run the command update-grub as super user 
  4. Reboot the system and see the difference.
After this, my CPU temperature fell in the range of 40 to 50+

Satisfied :)

Friday 17 February 2012

Clearing recent documents history in GNOME 3

If you are using GNOME 3, have you ever wondered how to clear the history of recently used documents without fiddling around with ~/.local/share/recently-used.xbel file. Ok. Here is the solution for you.

  1. Open the GNOME shell's integrated inspector tool and JavaScript console called Looking Glass by typing the command lg in the prompt invoked by Alt+F2
  2. Then enter the following imports.gi.Gtk.RecentManager.get_default().purge_items()
  3. Press Esc to exit from the looking glass console.
I hope that the GNOME guys will provide an easier way for this in the near future.

Have fun :)

random surge

Well, having a I won't blog resolution for a long time. Today I decided to break it, not because I have some cool information that the world needs to know. But, just to record stuffs that I do in my day to day life (and forget them as the time passes by). I hope this will save my time and effort when I come across the same issue later.

I'll be glad if that helps someone having a similar scenario. I tend to keep this blog more technical. Lets see how it goes :)