Codelog

foreach(Snippet aSnippet in CodeLog){ aSnippet.GetSolution(); }

Archive for the ‘Python’ Category

Mashing Twitter and FSO

without comments

I really love Twitter and it didn’t make any sense to me to shell out a rupee for every tweet sent through my Airtel Mobile. Moreover, I am on one of those monthly booster packs which allows you to send 22000 text messages for free. I simply had to exploit this by setting up my own little ‘OC’ twitter forwarder written in python. (I know of smstweet.in service but I am still charged 1.50 for every tweet I send)

Its insanely simple to write such a ‘forwarder’ in python using the services provided by the FSO (freesmartphone.org) Framework,

  1. Send messages to your old/unused number whose SIM is in the Freerunner (or any other device supported by the FSO framework)
  2. Handle the incoming messages and use python-twitter API (or) raw urllib2 to post updates. Of course, the device should be connected to the internet, you can tether this device to an old unused computer. Simply put, the Freerunner should be able to access the internet.

I know this is dumb given cheap GPRS and all, but what the heck; Sundays _are_ reserved for dumb things and I wanted to show off how easy it is to develop and conjure up simple but powerful scripts using open hackable hardware like the Freerunner. So take off your pedantic hats ;)

Here is the actual python code,

#!/usr/bin/env python
# Written By Sudharshan S, http://sudharsh.wordpress.com
 
import dbus
import time
import logging
import twitter
 
import gobject
from gobject import MainLoop
 
from dbus.mainloop.glib import DBusGMainLoop
DBusGMainLoop (set_as_default = True)
 
# Use OAUTH?
USERNAME = "username"
PASSWORD = "password"
 
log = logging.getLogger("TweetForwarder")
 
class TweetForwarder:
 
   """Process Incoming messages and update twitter status
      if the message startswith 'tweet'
   """
 
   def __init__(self, username, password):
       log.warning("Starting up....")
       self.twitter_api = twitter.Api(username=username, password=password)
 
       # Get proxies and add signal handlers
       bus = dbus.SystemBus()
       _usage = bus.get_object("org.freesmartphone.ousaged",
                               "/org/freesmartphone/Usage")
       _proxy = bus.get_object("org.freesmartphone.ogsmd", \
                               "/org/freesmartphone/GSM/Device")
       self.usage_iface = dbus.Interface(_usage, "org.freesmartphone.Usage")
       self.usage_iface.RequestResource('GSM')
       self.sms_iface = dbus.Interface (_proxy, "org.freesmartphone.GSM.SMS")
       self.sms_iface.connect_to_signal ("IncomingMessage", self.onIncomingMessage)
 
   def onIncomingMessage(self, sender, message, kwargs):
       log.warning("Received SMS from %s:%s" % (sender, message))
       # We don't ALL messages to this number to be tweeted
       if message.strip().startswith("tweet "):
           log.warning("Trying to update status : %s" % message[6:].strip())
           self.twitter_api.PostUpdate(message[6:])
           log.warning("Updated Status")
 
   def run(self):
       loop = MainLoop()
       loop.run()
 
if __name__ == "__main__":
    logging.basicConfig()
    server = TweetForwarder(USERNAME, PASSWORD)
    server.run()
--

Make sure you have python-netclient and python-json installed on your Freerunner. These can be installed using the ‘opkg install’ command.

The script and the accompanying dependency can be downloaded from here. Just change the USERNAME and PASSWORD accordingly after scp’ing the tarball to your device.

Some useful links,

[1]: The FSO API reference

[2]: DBus Tutorial

Written by sup3rkiddo

December 6th, 2009 at 8:16 pm

Give your boss the illusion of managing you… with pidgin and dbus

with 2 comments

Dilbert.com

Oh yeah!. With the power of DBus and libpurple APIs it is possible to give your boss the illusion of managing you. Just run the following script (under WTFPL). Tested with jabber accounts in a live office environment :P.

#!/usr/bin/env python
# By Sudharshan S, released under WTFPL
 
import dbus
import gobject
import time
 
class PointyHairedBoss:
 
    def __init__(self, boss_id, source, frequency=30):
        self.boss_id = boss_id
        self.source = source
        self.frequency = frequency
        bus = dbus.SessionBus()
        _pidgin_proxy = bus.get_object("im.pidgin.purple.PurpleService", \
                                                       "/im/pidgin/purple/PurpleObject")
        self.purple = dbus.Interface (_pidgin_proxy, "im.pidgin.purple.PurpleService")
        # FIXME:
        account_id = self.purple.PurpleAccountsGetAllActive()[0]
        self.boss_conversation = self.purple.PurpleConversationNew(1, account_id, self.boss_id)
        self.boss_im = self.purple.PurpleConvIm(self.boss_conversation)
        print self.boss_im
 
    def start_nonsense(self):
        question_list = open(self.source)
        for q in question_list:
            self.purple.PurpleConvImSend(self.boss_im, q)
            time.sleep(self.frequency)
 
if __name__ == "__main__":
   # Change the jabber id and the path to your questions, with an optional frequency
   o = PointyHairedBoss("foo@gmail.com", "questions")
   o.start_nonsense()

Written by sup3rkiddo

July 5th, 2009 at 11:37 am

import this

without comments

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

PEP 20

Written by cnu

January 20th, 2009 at 1:44 pm

Posted in Python

Tagged with

virtualenv - Sandboxed python environments

without comments

This problem has haunted me many times when I want to work on two frameworks (Turbogears and Pylons) and there are some packages which interfere with each other. Having both installed in /usr/lib/python-2.5/site-packages is a nightmare. You won’t know what causes your nosetests to fail, you will have to comment out the other dirty package and try again. Also some packages may be upgraded which will cause some problem in some place in your application.

All this can be easily solved by using the virtualenv package in python. What it does is - create isolated python working environments. So that packages you install in one environment doesn’t interfere with the other. Also if you can’t install packages in the global site-packages, this will be really helpful.

You just have to easy_install virtualenv and it gets installed as a executable. If you can’t easy_install, there is a single python script (virtualenv.py) which can be used instead.

You can create your sandbox with the command $ virtualenv --no-site-packages env. The –no-site-packages option make sure that the global site-packages doesn’t inherit any packages from the global site-packages.

It will create a directory ‘env’ in your current directory. The bin folder inside this has its own python executable and a seperate site-packages in the lib directory. It also has easy_install installed in the bin.

Now you can install whatever package you want by typing $ env/bin/easy_install packagename

All your commands need to be prefixed with the env/bin/ path else it will use the wrong python version. But you can avoid typing the long commands by using the activate script bundled with the bin folder.

On *nix systems, you have to $ source bin/activate and on a windows machine > \path\to\env\bin\activate.bat. After you are finished with it, you just have to type deactivate and you get back to the old shell.

Most of the times, it would work perfectly, but sometimes the shell will cache the path of the commands. So, it is always advisable to check whether the path is set correctly by typing which python.

Now this solves my problem of mismatched and wrong packages and can start working in Pylons.

Written by cnu

August 28th, 2008 at 6:25 pm

Posted in Python

Tagged with ,

Python linkdump - 24 Aug 2008

without comments

Here is a linkdump of resources related to python which I had in my bookmarks. These are some advanced topics which would really help you to better understand the internals and write better code.

Written by cnu

August 24th, 2008 at 10:46 pm

Posted in Linkdump, Python

Tagged with ,

Doctests in Python

without comments

This post is due for a long time since my post on Singular form of a word program and here it is - Doctests in Python. From the python library reference,

The doctest module searches for pieces of text that look like interactive Python sessions, and then executes those sessions to verify that they work exactly as shown.

Doctests are an easy way to test small functions by specifying the output of the function in docstrings. In python you can (should) write docstrings for classes and methods which can be used to generate the documentation for the module. In those docstrings, you just specify calls to the function with the return string specified. The doctest module automatically asserts the output and verifies whether the test passes or fails.

Lets see an example of doctest and how to run them. Lets create a function which adds two numbers.

def add(x, y):
    """Adds two numbers/strings together

    >>> add(1,2)
    3
    >>> add('foo','bar')
    'foobar'
    """
    return x+y

Here we have written the docstrings and have four lines which look like the python shell. There we call the function with various arguments and also specify how the function will return.

So, how do we run the test? Just include these lines in the module and run the file directly. This is the usual way we run doctest (in the __main__ part of the file).

def _test():
    import doctest
    doctest.testmod()

if __name__ == "__main__":
    _test()

You just have to call the doctest.testmod() function and it will search for all such tests in the docstrings and outputs nothing if the tests pass. If you want to get more verbose output, run the file as python filename.py -v

There are many advantages of doctests (wikipedia has a lot more):

  • Easy to understand what a function is going to do if called
  • Tests and code together - easy to update the test if code changes
  • Most of the times I execute my functions on the shell - so I just have to copy-paste the output from the shell to the code

Once you start using doctests, you would find yourself trying to use it in all possible places. For more elaborate testing, you should probably use pyunit.

Is there any other programming language which has tests written directly in the documentations? If you were to design such a testing module for you favourite language, how would you do it (especially if it doesn’t have a interactive shell)? Do explain your views on it below.

Written by cnu

August 9th, 2008 at 8:08 am

Posted in Documentation, Python, Testing

Tagged with , ,

Sections in Turbogears Config file

with one comment

In turbogears you have three important config files. One is the dev.cfg file used during development, another is prod.cfg used during deploying your code. The last one is app.cfg file which has parameters which are common to both dev and prod.

When you store the parameters in the app.cfg file, it is good to group related parameters together under a section. A new section can be created by enclosing a word with [ and ], eg: [API]

All this is fine till we come to the point of reading back the values from the config file. We faced this same problem and whenever we tried to read it back, it used to give some error about no such variable present.

After looking through the code of the configparser.py for cherrypy, we saw that there was one more additional parameter called path. The path parameter takes in the section name and the variable inside the section is taken in by the parameter key.

So instead of doing a tg.config.get('url'), you would need to do a tg.config.get('url', path='API').

Though this was slightly different than the usual config parser module, it solved the problem of properly categorizing the config file.

Written by cnu

August 1st, 2008 at 12:37 pm

Posted in Python

Tagged with , ,

if-else conditions in lambda functions

with 2 comments

On reading my last post singular form of a word, a friend of mine (Sathya) didn’t understand what I had done in the lambda functions. It was of the form lambda w: w[-3:] == ‘ies’ and w[:-3] + ‘y’. I had forgotten to explain about that in that post.

There is one small restriction in lambdas - you can’t use if-else constructs in them. If you want to use a condition check in your lambda, then it has to be of this form

lambda : <condition> and <if block> or <else block>

This is easy to understand when you compare it with conditional or ternary operators in C (?:) - condition?if block:else block.

Written by cnu

July 28th, 2008 at 3:53 pm

Posted in Python

Tagged with ,

Singular form of a word in python

with 5 comments

Last post I talked about using list comprehensions and promised to post a simple method to find the singular form of a word. When I wanted to write such a function, I initially thought of using a chain of if-elif-else constructs. But I didn’t like it that way. So I used lambda functions and list comprehensions to do the same job.

def singularize(word):
    """Return the singular form of a word
 
    &gt;&gt;&gt; singularize('rabbits')
    'rabbit'
    &gt;&gt;&gt; singularize('potatoes')
    'potato'
    &gt;&gt;&gt; singularize('leaves')
    'leaf'
    &gt;&gt;&gt; singularize('knives')
    'knife'
    &gt;&gt;&gt; singularize('spies')
    'spy'
    """
    sing_rules = [lambda w: w[-3:] == 'ies' and w[:-3] + 'y',
                  lambda w: w[-4:] == 'ives' and w[:-4] + 'ife',
                  lambda w: w[-3:] == 'ves' and w[:-3] + 'f',
                  lambda w: w[-2:] == 'es' and w[:-2],
                  lambda w: w[-1:] == 's' and w[:-1],
                  lambda w: w,
                  ]
    word = word.strip()
    singleword = [f(word) for f in sing_rules if f(word) is not False][0]
    return singleword
 
def _test():
    import doctest
    doctest.testmod()
 
if __name__ == '__main__':
    _test()

This method is simple if you know the rules of plurals in the english language. I have converted each rule into a lambda function which returns the corresponding singular word depending on the word ending. The order of the rules are important, for eg., i should first check for -es before checking for -s. I haven’t taken care of the special plurals like men-man, people-person, children-child.

I then use list comprehensions to apply each function on the input word and pick the 0th element. Now you get the singular for of the word.

If you notice in the function, I have used something called doctests which is a very easy way to test your functions. You can download the source code and run it to run the doctest. Wow, now I got another topic to write about in the next post - doctests in python.

Written by cnu

July 27th, 2008 at 1:48 pm

Posted in Python

Tagged with ,

List comprehensions in python

with one comment

In the last post about Map-Filter-Reduce before finishing the post, I told about slight changes to those functions and how you can do the same job using list comprehensions. I would be talking about it here today.

Three years back Guido van Rossum, the BFDL made a blog post about the fate of reduce() in Python 3000. He stated that map and filter confusing to many people and that list comprehensions were simple to read and understand. Guido wanted reduce() to be totally removed from the language as there weren’t any good uses of it except + and *.

List Comprehensions
So, what is this list comprehensions that Guido was talking about. It is just a concise way to create lists from another list (just like map() and filter()). It is easy on the eyes and clearer to understand.

It consists of an expression followed by a for clause and more for/if clauses. The result of this is a list gotten by evaluating the expression in the context of the for and if clauses.

>>> words = ['FOO', 'BAR', 'BAZ']
>>> [word.lower() for word in words]
['foo', 'bar', 'baz']
>>> nums = [1,2,3,4]
>>> [(x, x*x) for x in nums]
[(1, 1), (2, 4), (3, 9), (4, 16)]

This looks just like the map function. Now just add an if clause after the for, and you get the filter equivalent.

>>> nums = [1,2,3,4,5,6]
>>> [i for i in nums if i%2 == 0]
[2, 4, 6]

List comprehensions are easier to understand by just reading it as words - create a list of is for every i in nums if i%2 is equal to 0. Also list comprehensions are faster than map and filter as it doesn’t have to make function calls.

So, even though Guido wanted all the four functions to be removed from the standard library, he has announced that lambda, map and filter would stay - with the latter two having small changes - returning iterators instead of a list. Unfortunately reduce() is moved over to functools module.

So my next post is going to be a small example of using list comprehensions to find the singular form of a word.

Written by cnu

July 26th, 2008 at 11:22 pm

Posted in Python

Tagged with