Friday, September 25, 2009

Importing your Thunderbird contacts to GMail.

I found myself needing to import my Thunderbird contacts to GMail. After asking the internets Thunderbird provides an option to export contacts as a CSV file and GMail provides an option to import contacts from a CSV file. Cool I thought and proceeded to something that should take me a couple of minutes to complete.
Of course surprise, surprise the CSV format outputted from Thunderbird does not produce the expected results when imported to GMail. So I quickly hacked up the following Python script to generate a GMail friendly csv file from a csv file exported from Thunderbird. Note that in order to use it you must have Python installed in your PC.
import sys
import csv

def transform(filename_in, filename_out):
  output_list = []
  try:
      file_input = open(filename_in)

      csv_input = csv.reader(file_input)
    
      for row in csv_input:
          entry_list = []
          entry_list.append(row[0])
          entry_list.append(row[1])
          if(output_list):
              entry_list.append(row[4])
          else:
              entry_list.append('Email Address')
            
          output_list.append(entry_list)

      file_input.close()
        
  except IOError:
      print 'Could not open file %s. '\
            'Make sure that the file exists.' % filename_in
      sys.exit(1)
        
  try:  
      file_output  = open(filename_out, "wb")
      csv_output = csv.writer(file_output)

      for row in output_list:
          csv_output.writerow(row)
        
      file_output.close()

  except IOError:
      print 'Could not open file %s. '\
            'Make sure that the file can be written.' % filename_out  
      sys.exit(1)
        

if __name__ == '__main__':
  if len(sys.argv) != 3:
      print "Usage: %s [input csv file] [output csv file]" % sys.argv[0]
      sys.exit(1)

  transform(sys.argv[1],sys.argv[2])
So to actually import your contacts from your Thunderbird email client to GMail:
  • In Thunderbird select Address Book -> Tools -> Export
  • In the export dialog select "Comma separated values" as the output type and save it somewhere (i.e. /home/foo/export.csv)
  • Grab the script above and save it somewhere with a name of your choice (i.e. converter.py)
  • Run the script with arguments the name of the file exported from Thunderbird and the name of the output file (i.e. python converter.py /home/foo/export.csv /home/foo/gmail_import.csv)
  • Open up GMail contacts and select "Import"
  • Choose the file outputted by the script (i.e. /home/foo/gmail_import.csv) and proceed to importing.
  • Enjoy

Monday, June 1, 2009

Starting a Django project in Eclipse with PyDev

Assuming python and Django installed plus eclipse with PyDev. The django project we ‘ll create is called mysite and the respective eclipse project will be named mysite-project.

  • In eclipse New –> PyDev Project
  • Project name: mysite-project
  • Deselect “Create default “src” folder and add it to the pythonpath” and press OK
  • Navigate to the Workspace folder of eclipse.
  • Navigate to the folder mysite-project from the command line.
  • Execute django-admin.py startproject mysite
  • Press F5 on the project
  • Right click on the project name in the Pydev Package Explorer from Eclipse and select "Properties".
  • Select PyDev - PYTHONPATH
  • In the "Source Folders" tab press "Add source folder" and select the folder "mysite" created from django-admin.
Now you are ready to start coding. The approach of creating the top level django project folder as a sub directory of the eclipse project's top level folder allows us to have correct auto completion from PyDev by using it's supported folder structure (a source folder inside the eclipse project). I will continue posting on my eclipse setup for django projects but this should get you started.

Sunday, May 17, 2009

Researching techniques on unit testing Qt GUI applications

I have been struggling for a while on how to make desktop applications I am working on with Qt unit testable. In general there are many techniques presented that achieve the goal of making the UI part of an application so thin that it doesn’t need to be be unit tested while the business logic behind the UI is separated and can be easily unit tested. Most of these techniques work beautifully in implementations that use languages with a big arsenal of tools targeted to unit testing and dependency injection like Python and Java that I have experience with.

In Qt and C++ the whole process of making an UI testable has it’s quirks (Qt views need to have a parent – child relation, there is no garbage collection etc.). I have found that the approach of “Humble Dialog” is the one that gives me most benefits:

  • The view is the front-man (what is exported from a model – view – presenter (controller) triad is the view) so it plays well with Qt that also has this approach and is more comprehensible from an audience that is not exposed to the pattern.
  • All the wiring of  the triad happens in the view, so all parts that are not supposed to be unit tested are in the same place and I can in most places avoid setting up factories for wiring up and instantiating the triads.
  • The messages between triads are easily delivered since the whole setup resembles a lot the typical mixed UI/business logic that seems to be the convenient way of creating applications with a UI and is the one that most GUI toolkits support.

An example implementation of something as simple as a messagebox presenting some text could be (from a question I posted on Stack Overflow):

class IView {
public:
    IView(){}
    virtual ~IView(){}

    virtual void showResult(const QString &text)=0;
};

class Presenter {
public:
    Presenter(IView *view){
        m_View = view;
    }
    ~Presenter(){}

    void buttonPressed(){
        QString text;
        // Evaluate text
        m_View->showResult(text);        
    }

private:
    IView *m_View;
}

class MyView : public IView , public QDialog {
public:
    MyView(){
        m_Presenter = new Presenter(this);
        m_Button = new QPushbutton(this);
        m_Label = new QLabel(this);

        // Ui event handled inside view but then directly
        // propagated to the Presenter
        connect(m_Button,SIGNAL(clicked()),this,SLOT(buttonPressed()));
    }
    ~MyView(){
        delete m_Presenter;
        // Qt will automatically delete m_Button and m_Label;
    }

    void showResult(const QString &text){
        m_Label->setText(text);
    }

protected slots:
    void buttonPressed(){
        m_Presenter->buttonPressed();
    }

private:
    Presenter *m_Presenter;
    QPushbutton *m_Button;
    QLabel *m_Label;
}

class TestView : public IView {
public:
    TestView(){}
    ~TestView(){}

    void showResult(const QString &text){
        m_LabelText = text;
    }
    QString getResult(){
        return m_LabelText;
    }

private:
    QString m_LabelText;
}

// Test code
TestView view;
Presenter presenter(&view);
presenter.buttonPressed();
EXPECT_EQ(view.getResult(),"Expected Result");

// Production code
MyView view;
view.show();

The main advantage I see from following this approach is that if I wanted to i.e. instantiate an new model – view – presenter triad after some user action I could perform it inside the view instantiating it easily without the need for a factory and secondly from the “outside” the triad seems to be just a view and not a full blown MVP triad that makes it play well with Qt.

I ‘d like others to share their thoughts on this, since for me settling with this approach has come after a lot of trial and error.

Monday, April 6, 2009

Twitter client for fun

I was checking the twitter APIs now that I 'm also using it and they are all quite clean (most probably because the underlying API is also clean and complete). I thought I 'd give it a try and got python-twitter http://code.google.com/p/python-twitter/
A client that just receives my latest tweets using PyQt4 was quite easy to build:
import sys
import twitter
from PyQt4.QtGui import QApplication, QMainWindow, QTabWidget, QListView
from PyQt4.QtCore import QAbstractListModel, Qt, QVariant

class TweetsModel(QAbstractListModel):
    def __init__(self, tweets = set()):
        QAbstractListModel.__init__(self)
        self.tweets = tweets

    def rowCount(self, parent):
        return len(self.tweets)

    def data(self, index, role):
        ret = QVariant()
        if ( index.isValid() and index.row() < len(self.tweets)
            and role == Qt.DisplayRole ):
            ret = QVariant(self.tweets[index.row()])
        return ret

class TweetsListView(QListView):
    def __init__(self, parent):
        QListView.__init__(self, parent)

class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        
        api = twitter.Api()
        statuses = api.GetUserTimeline("pagles")
        tweets = [s.text for s in statuses]

        self.tabs = QTabWidget(self)
        self.tweetsModel = TweetsModel(tweets)
        self.tweetsList = TweetsListView(self)
        self.tweetsList.setModel(self.tweetsModel)
        self.tabs.addTab(self.tweetsList,self.tr("Tweets"))

        self.setCentralWidget(self.tabs)

class QweetApplication(QApplication):
    def __init__(self):
        QApplication.__init__(self, sys.argv)

if __name__ == "__main__":
    app = QweetApplication()
    mainwindow = MainWindow()
    mainwindow.show()
    exit(app.exec_())
Yes, my username in twitter is pagles in case you followed the code closely :-)

Wednesday, February 11, 2009

Get the version of gcc with python.

I needed to get the version of gcc in a python script (Ubuntu Linux). And here it is:
commands.getoutput("gcc -v").split(' ')[-4:-3][0]
Python is fun...

Tuesday, June 5, 2007

Releasing open source is hard

I have just published another release of my little QtWorkbench project that I seems to have finally reached to a state of being stable and usable. This project is actually a small one with very few features, dedicated in doing one thing (hopefully) good, that is providing an open source IDE with support for Qt. It's nothing fancy and anyone could say that this is of the things that you can write in a week or so and make an excellent work. That's what I also thought when I started up with it. But guess what? Releasing open source these days is hard! No one will take a product that is of inferior quality seriously and people that will actually try it out will judge with high standards. If you don't get it right then you are in trouble, people will judge you. It is a good thing that the expectations out of open source projects are so high, but still if you are a newcomer (as I still am I guess) then you have to remember that open source is not just a play ground but there are actually people who will count on your product to get their work done. That means that you have to provide everything: easy installation, documentation, everything... I guess I learned my lesson this time.

Monday, February 5, 2007

And darcs it is

At work we use cvs. There is a lot of traveling involved and there is no access to the central repository from outside the company. I never had to develop anything while I was abroad and didn't have the immediate need to search how I would keep in sync with the main repository while I was abroad. Well this time has arrived and I searched for possible solutions to the above problems. After digging and messing around; bazaar, mercurial and darcs seemed like the most appropriate solutions. My final choice was darcs after all, as it seems to be the best documented. Switching to a decentralized versioning system after years of working with centralized ones is a big change. The challenge becomes greater if you have to use both the repositories in parallel. Here is what I did:
  • Checked out a fresh copy of my project from cvs. I did not touch anything on it, not build it nothing. It just serves as an intermediate between the darcs repository and the cvs repository. This folder is created in a pc that has access to the cvs repository (like duh!). A colleague of mine has access to this pc (well it's his own :-)). Let's call this folder "hybrid".
  • Using this config file with tailor (tailor --configfile=tailor.config cvs-to-darcs), I switch the cvs working copy to a darcs repository.
  • Now I create a directory named master and pull the changes from the hybrid directory. The master directory is then packed and given to the developer that will not have access to the cvs repository (yeap that would be me).
  • On the pc that does not have access to the cvs repository the archive containing the master repo as described above is unarchived and a working copy is generated with darcs put.
  • Changes happen in the working repository. When everything is finished, the changes are pushed to the master repository and the whole repository is sent back to the pc that has access to the cvs server. The new master repository replaces the old one and:
cvs update -A tailor --configfile=tailor.config darcs-to-cvs tailor --configfile=tailor.config cvs-to-darcs cd ../master darcs pull ../hybrid
  • The new master repo is then sent back to the remote developer.
This for now has worked just fine. All the above were based on this ticket from the tailor trac.