Saturday, January 30, 2010

Named tuple

I recently read a post on planet python and the author mentioned something about named tuple which made my curious.

So what's a named tuple?
The namedtuple was introduced in Python 2.6. A named tuple is created using a factory function from the collections module and it extends the basic tuple by assigning a name to each position in a tuple but can still be used as a regular tuple. This makes it possible to access fields by name instead of an index. The named tuple should not require more memory, according to the documentation, than regular tuples since they don't have a per instance dictionary.

The factory function signature is:
collections.namedtuple(typename, field_names[, verbose])
The first argument specifies the name of the new type, the second argument is a string (space or comma separated) containing the field names and finally if verbose is true the factory function will also print the class generated.

Enough theory, I'll show you an example.

Example
Say you have a tuple containing username and password. To access the username you get the item at position zero and the password is accessed at position one:
credential = ('mario', 'secret')
print 'Username:', credential[0]
print 'Password:', credential[1]
There's nothing wrong with this code but the tuple isn't self-documented. You have to find and read the documentation about the positioning of the fields in the tuple. This is where named tuple can enter the scene. We can rewrite the previous example as following:
import collections
# Create a new sub-tuple named Credential
Credential = collections.namedtuple('Credential', 'username, password')

credential = Credential(username='mario', password='secret')

print 'Username:', credential.username
print 'Password:', credential.password
Nice, don't you agree?

If you are interested of what the code looks like for the newly created Credential-type you can add verbose=True to the argument list when creating the type, in this particular case we get the following output:
import collections
Credential = collections.namedtuple('Credential', 'username, password', verbose=True)

class Credential(tuple):                                     
        'Credential(username, password)'                     

        __slots__ = () 

        _fields = ('username', 'password') 

        def __new__(_cls, username, password):
            return _tuple.__new__(_cls, (username, password)) 

        @classmethod
        def _make(cls, iterable, new=tuple.__new__, len=len):
            'Make a new Credential object from a sequence or iterable'
            result = new(cls, iterable)                               
            if len(result) != 2:                                      
                raise TypeError('Expected 2 arguments, got %d' % len(result))
            return result

        def __repr__(self):
            return 'Credential(username=%r, password=%r)' % self

        def _asdict(t):
            'Return a new dict which maps field names to their values'
            return {'username': t[0], 'password': t[1]}

        def _replace(_self, **kwds):
            'Return a new Credential object replacing specified fields with new values'
            result = _self._make(map(kwds.pop, ('username', 'password'), _self))
            if kwds:
                raise ValueError('Got unexpected field names: %r' % kwds.keys())
            return result

        def __getnewargs__(self):
            return tuple(self)

        username = _property(_itemgetter(0))
        password = _property(_itemgetter(1))
The named tuple doesn't only provide access to fields by name but also contains helper functions such as the _make() function which helps creating an Credential instance from a sequence or iterable. For example:
cred_tuple = ('mario', 'secret')
credential = Credential._make(cred_tuple)
There are more interesting use-cases and examples in the documentation, so I suggest that you take a peek.

Comments
I think the named tuple is useful. They remove the error-prone indexing in tuples by providing access to fields by name without adding any memory overhead. They are also regular Python classes which means you can do anything you can do with classes.

Wednesday, January 20, 2010

More fun with QWebKit

In the previous post I wrote about calling python methods and accessing properties from JavaScript executed in QWebKit. In this post I'll show you how to do the other way around, calling a JavaScript function from Python.

I would like to thank Rich Moore for commenting on the previous post and pointing out that you should re-add your python object  every time the javaScriptWindowObjectCleared() signal is emitted.

Actually, I think this is almost to simple to do a post about so I'll try doing something fun/useful with it.

QWebFrame contains a public slot:
QVariant evaluateJavaScript(const QString & scriptSource)
You simply pass the JavaScript-snippet to the function. The snippet will be evaluated using the frame as context and returns the result of the last executed statement. This makes it possible to 'click' submit buttons, fill form fields and other interesting stuff in the currently loaded frame. I'll give you an example on how you can create an auto-login GMail widget. The widget will automatically login the user by populating the login form with the user's credentials and 'click' the login button.
#!/usr/bin/env python
from PyQt4 import QtCore
from PyQt4 import QtGui
from PyQt4 import QtWebKit

javaScriptLogin = """
document.getElementsByName('Email').item(0).value='{email}';
document.getElementsByName('Passwd').item(0).value='{password}';
document.getElementsByName('signIn').item(0).click(); void(0);
"""

class GmailWebView(QtWebKit.QWebView):
    def __init__(self, parent=None):
        super(GmailWebView, self).__init__(parent)
        self.loggedIn = False

    def login(self, url, email, password):
        """Login to gmail."""
        self.url = QtCore.QUrl(url)
        self.email = email
        self.password = password  
        self.loadFinished.connect(self._loadFinished)
        self.load(self.url)

    def createWindow(self, windowType):
        """Load links in the same web-view."""
        return self

    def _loadFinished(self):
        if self.loggedIn:
            self.loadFinished.disconnect(self._loadFinished)

        self.loggedIn = True
        jscript = javaScriptLogin.format(email=self.email, password=self.password)
        self.page().mainFrame().evaluateJavaScript(jscript)

    def contextMenuEvent(self, event):
        """Add a 'Back to GMail' entry."""
        menu = self.page().createStandardContextMenu()
        menu.addSeparator()
        action = menu.addAction('Back to GMail')
        @action.triggered.connect
        def backToGMail():
            self.load(self.url)
        menu.exec_(QtGui.QCursor.pos())

def main():
    import sys
    qApp = QtGui.QApplication(sys.argv)

    # Prevents me from posting my password on the blog :)
    password, ok = QtGui.QInputDialog.getText(None, "Password request", "Enter password", QtGui.QLineEdit.Password)
    if not ok:
        return

    gmailWebView = GmailWebView()
    gmailWebView.login('https://mail.google.com/mail',
                       'mario.boikov',
                       password)
    gmailWebView.show()

    sys.exit(qApp.exec_())

if __name__ == "__main__":
    main()
This is just a quick hack, it lacks a bunch of checkings...

Maybe it's time to wipe the dust off my GMonitor-plasmoid and add support for opening my account in a new window based on the GMail widget above.

Saturday, January 16, 2010

Calling Python from JavaScript in PyQt's QWebkit

QtWebKit makes it very easy to expose methods and properties implemented in Python to JavaScript. Qt will automatically expose Qt-slots and Qt-properties to a JavaScript when a QObject is made available in the frame's JavaScript context.

I think the code speaks for itself
import sys
from PyQt4 import QtCore, QtGui, QtWebKit

"""Html snippet."""
html = """
<html><body>
  <center>
  <script language="JavaScript">
    document.write('<p>Python ' + pyObj.pyVersion + '</p>')
  </script>
  <button onClick="pyObj.showMessage('Hello from WebKit')">Press me</button>
  </center>
</body></html>
"""

class StupidClass(QtCore.QObject):
    """Simple class with one slot and one read-only property."""

    @QtCore.pyqtSlot(str)
    def showMessage(self, msg):
        """Open a message box and display the specified message."""
        QtGui.QMessageBox.information(None, "Info", msg)

    def _pyVersion(self):
        """Return the Python version."""
        return sys.version

    """Python interpreter version property."""
    pyVersion = QtCore.pyqtProperty(str, fget=_pyVersion)

def main():
    app = QtGui.QApplication(sys.argv)

    myObj = StupidClass()

    webView = QtWebKit.QWebView()
    # Make myObj exposed as JavaScript object named 'pyObj'
    webView.page().mainFrame().addToJavaScriptWindowObject("pyObj", myObj)
    webView.setHtml(html)

    window = QtGui.QMainWindow()
    window.setCentralWidget(webView)
    window.show()

    sys.exit(app.exec_())

if __name__ == "__main__":
    main()
Some references:

Thursday, January 14, 2010

New-style PyQt Signals and Slots

I was to lazy to take a look at the new-style signal and slot support which was introduced in PyQt 4.5 until yesterday. I did know that there were something called new-style signals and slots but that was the end of the story. Now I have taken the time and I think it's a cleaner solution than the old-style.

I'll just give you a short intro to whet your appetite, find all details here yourself.
import sys
from PyQt4 import QtCore
from PyQt4 import QtGui

def clicked():
    print "Button Clicked"

qApp = QtGui.QApplication(sys.argv)

button = QtGui.QPushButton("Click Me")
QtCore.QObject.connect(button, QtCore.SIGNAL('clicked()'), clicked)
button.show()

sys.exit(qApp.exec_())
This is the old way of connecting a signal to a slot. To use the new-style support just replace line 11 with following code
button.clicked.connect(clicked)
The new-style support introduces an attribute with the same name as the signal, in this case clicked.

If you need to define your own signal you'll do something like this (off the top of my head):
class X(QtCore.QObject):
    mySignal = QtCore.pyqtSignal(int)

    def emitMySignal(self):
        self.mySignal.emit(100)
And the old way:
class X(QtCore.QObject):
    def emitMySignal(self):
        self.emit(QtCore.SIGNAL('mySignal'), 100)

IMHO the new-style support is more pythonic and you don't have to specify your signals as strings when connecting. If you use pydev (eclipse) you'll also have completion support for signals.

Friday, January 8, 2010

Digikam - Light table

This post is somewhat related to the post about ctypes and gphoto.

Background
I consider myself a pre-amateur photographer and that means I'm taking a lot of shots just to learn how the camera works. I own a Canon EOS 1000D and have recently moved from the fully automatic exposure modes to the advanced exposure modes, and to be more specific, the programmed auto exposure mode.

So, I needed an application that could load a couple of pictures, showing two pictures side-by-side for visual comparison and at the same time presenting the more important meta-data attributes such as focal length, exposure time, ISO and aperture. I considered doing such application myself and that's why I came across and started to explore gphoto. But luckily, I managed to stop myself and took yet another look at what Digikam offers. I'm a die-hard KDE-fan and have been using digikam, which is a KDE photo manager application, for quite some time to organize my photos but never actually used any other features except removing red-eyes.

To my surprise digikam included exactly the feature I was looking for! It's called the Light Table.

The Light Table
Digikam allows you to select a couple of pictures which can be placed onto the light table, as shown in the screenshot below.



By choosing Place onto Light Table a new window is opened with, in this case, the three pictures loaded and two of them shown side-by-side.



The light table also displays the meta-data for the respective picture (sorry about that some of the attributes are in Swedish) that are currently shown. You can synchronize operations like zooming and panning. When you zoom, both pictures will be zoomed to the same level and when panning, both pictures will be panned to the same area, really nice.

This was exactly what I was looking for. Now I can take a couple of shots with different settings, for example, changing the white balance, ISO and/or other parameters and compare the result rather easily. I get both a visual and a meta-data diff in the same view.

I just wanted to share my findings and hope this post was to some use for others that are looking for something similar.

Tuesday, January 5, 2010

Let's timeit!

Every now and then you might want to time snippets just to make sure that you choose the more efficient solution. In those cases you can use the timeit module to measure execution time for snippets.

Introduction
It's very easy to setup and measure the execution time for a snippet with timeit. The module contains a class, Timer, which is used to perform the measurement. The class has one constructor and three methods:
  • Timer([stmt='pass'[, setup='pass'[, timer=<timer function>]]]) - stmt is the statement to be timed and setup is called once before executing the main statement. A timer function can be specified and default is time.time() for all platforms but windows which is set to time.clock() instead (according to my timeit.py)
  • timeit([number=1000000]) - Executes the main statement passed to the constructor number of times and returns the result in seconds as a float.
  • repeat([repeat=3[, number=1000000]]) - Convenience function that calls timeit(number) repeat times. Returns a list with the results.
  • print_exc([file=None]) - Helper to print a traceback from the timed snippet.
Starting with Python 2.6 the timeit module also defines two convenience functions, timeit.timeit() and timeit.repeat(). They are basically wrappers around the Timer class.

Example
Suppose that I would like to create a list containing 100 'c':s like this ['c', 'c', ...]. There are at least two ways of doing this:
lst = ['c'] * 100
# or
lst = ['c' for i in xrange(100)]
Which one should I choose? Well, let's execute both statements with timeit and measure the execution time.
>>> import timeit
>>> t = timeit.Timer(stmt="lst = ['c'] * 100")
>>> print t.timeit()
1.10580182076
>>> t = timeit.Timer(stmt="lst = ['c' for x in xrange(100)]")
>>> print t.timeit()
7.66900897026
Ok, I think I'll stick with the first snippet :)

The result returned is the total execution time in seconds. In this particular case when we are executing the snippet 1000000 times the result is also the execution time in microseconds for one single pass (1000000*exe_time/1000000 == exe_time).

Normally, the timeit module doesn't have access to things that you have defined in your module. If you would like to measure a function that you have defined in your module you can specify the import statement in the setup parameter:
>>> def create_lst(size):
...    return ['c'] * size
...
>>> t = timeit.Timer(stmt="create_lst(100)", setup="from __main__ import create_lst")
>>> print t.timeit()
1.21339488029
This will introduce a little overhead since the create_lst() function is called in the measurement loop instead of just executing an inlined snippet.

Note: Timer.timeit() will by default disable garbage collection during timing. To enable GC you can pass 'gc.enable()' as a setup statement.

I find the timeit module as a simple and convenient way to measure execution time for small snippets.