Archive for the ‘Tech’ Category

Writing a Facebook Application with Python Pt. III

Saturday, February 16th, 2008

This is the third part in a series of three posts about writing a Facebook application with Facebook. If you have not already ready done so, you should read the first and second parts first.

The technology behind Facebook applications is actually quite straight-forward. It is completely platform agnostic so you can build an app with any technology you might use to serve HTML content. My choice would be Python, but then I am a shameless Python fan-boy. Unfortunately there are still problems that any Facebook application developer will face, and most aren’t technology related.

Facebook have solved a number of challenging problems and for the most part it is an elegant solution to adding third party applications to their own site. But Facebook isn’t the grand free-for-all platform that the world wide web is — Facebook must tread a fine line between allowing the application developer to generate revenue and avoid annoying the user so much that they abandon their accounts. Its understandable — I wouldn’t want an application popping up adverts or sending mails on my behalf — but the rules they put in place tend to put the app developer at odds with Facebook admin.

For example, there is an API call that sends out notifications. When you receive a notification it displays a little text and link which you might use to inform a user that a friend has sent them something or done something else that is directly relevant to them. Facebook don’t want applications flooding other users with these notifications, so it places restrictions on the number that can be sent out. The documentation says the application can ’send up to 40 notifications to the notifications page per user per day’, which to to me is unclear whether an application can send 40 notifications per day on a user behalf or receive 40 notifications per day (apparently its the former). That used to be the case, but Facebook introduced a new system that restricts notifications even further. Applications receive a variable allowance of notifications that changes depending on how many users hide its notifications. The more users that hide your notifications, the less notifications an application may send out. The starting level seems to be 10 notification per day, a good bit under the original 40. This restriction strikes me as being excessively harsh on the application developer, and I’m not the only one who thinks so — the forums are full of application developers venting their annoyance at this and other restrictions. In my opinion it would be far more sensible to restrict the number of notifications that can be received from an application, even one per user per day would be fine! I don’t think anyone would be too annoyed by at most one notification per day send from a friend.

Facebook appear to be constantly tweaking and modifying their system to keep applications in check and make the content from applications as relevant as possible. And they prefer to do this by automated means, much to the chagrin of the application developers who feel they are being unfairly penalised by an flawed system. Unfortunately if you want a piece of Facebooks pie, you need to play by their rules. I suspect the gold-rush is over for Facebook applications, but as long as you keep on top the constantly shifting platform it could be a lucrative opportunity.

My own application doesn’t seem to be doing too well. Perhaps because of the reasons I am posting here, or because it is a waste of time and people don’t see the point. Whatever the reason, I am less inclined to create a Facebook app for becontrary.com, which was my original reason for looking in to it. It has started me thinking about how to make a better job of embedding an application inside a host web app, so writing a Facebook app may have been a good use of my time after all. Maybe I can do a better job, the poor schmucks at Facebook are lumbered with PHP. ;-)

Easy as Pie

Saturday, February 16th, 2008

To further my bid for the worlds dullest hobby award, I have been creating pie charts. I wanted to investigate generating Povray scene description files with Python. It turns out to be a winning combination; it didn’t take long to build a system where I can generate a scene containing pie segments of various colors and angles. I can also vary the height and explode individual pie segments. Povray can render very high quality scenes so this system could be used to make pie charts for television or print.

pie

I will experiment with other charts, bar charts etc. Maybe I’ll even generate an animation with it.

This isn’t entirely just for the heck of it. I plan to write an article about it for the Python magazine.

Writing a Facebook Application with Python Pt. II

Wednesday, February 13th, 2008

For the first part series of post, click here for Part I.

Writing a Facebook application is in essence the same as writing any web application, only with an additional step where the output from your web app is processed and inserted in to a Facebook page. Although PHP seems the most popular choice (and is what Facebook itself is written in) you can use any of the Python frameworks to write an app. You could even roll your own if you were so inclined. I used Turbogears, but you could easily adapt this to another Framework.

Serving FBML

You can generate FBML with any Python templating system. I used Genshi which was quite happy to generate FBML for me as long as it was instructed to produce xml and not html, which you can do by adding format=”xml” to the expose decorator. For example, here is the controller method for my stats page.

    @expose(template="genshi:microbes.templates.stats", format="xml")
    def stats(self, *args, **kwargs):

        num_users = User.select().count()
        num_added_users = User.select(User.q.added==True).count()
        num_infections = Infection.select().count()

        return dict(num_users=num_users,
                    num_added_users=num_added_users,
                    num_infections=num_infections)

To see what that renders, take a look at the source of http://microbes.willmcgugan.com, which is naked FBML (not processed by Facebook).

Adding and Removing Users

The first page that the user requests probably wont be FBML at all. When the user adds your application, then Facebook will redirect to a URL defined in your app settings. If your app needs to store users then this is where you would add the users id to your database. You could then display a welcome page, or simply redirect to one of the pages in your application. Similarly, when a user removes your application the Facebook server requests another. This ‘user removed’ URL is never actually seen by the user so you don’t need to return any meaningful content for it.

Using the Facebook API

For other pages within your application you need to do a little work to retrieve parameters from the page request that allow you to work with the API.

There are two Python modules to help with writing Facebook apps (that I know of). PyFacebook is a complete wrapper for the FB API and may be the obvious choice for writing a new application. However, the documentation was Django centric and I originally wanted to integrate an existing Turbogears application. So I decided to use minifb, which provides the necessary boiler-plate code for making calls to the Facebook API. If I write another application I would probably use PyFacebook to save a little time, but it turns out that doing it the hard way isn’t that hard at all.

Before you use any parameters from a Facebook request, they need to be validated with a call to minifb.validate which takes your secret key (supplied by Facebook when you create an application) and a dictionary containing the request parameters. In Turbogears you would simply pass the keyword arguments from the controller method to minifb.validate. When a user has added your app, every call has at least two parameters supplied by the Facebook server; ‘user’ is the user id of the current user and ’session_key’ is a string that identifies the current session which is needed for API calls. In the spirit of removing — even minimal — boilerplate I wrote a decorator to add to controller methods which does the validate step and optionally redirects to page if the user is not logged in.

_login_url = "http://apps.facebook.com/virtualmicrobes/"

def expose_fb(no_redirect=False):

    def decorate(f):

        def func(*args,  **kwargs):
            try:
                arguments = minifb.validate(FACEBOOK_SECRET_KEY, kwargs)
            except Exception, e:
                return str(e) 

            if not no_redirect and "session_key" not in arguments:
                return ''%_login_url

            ret = f(*args, **arguments)                        

            return ret

        func.__dict__.update(f.__dict__)
        return func

    return decorate

To use this decorator, just add it before Turbogears @expose decorator, which will make the controller appear just like any other request.

The minifb.call function can be used to make calls to the Facebook API. It takes the name of the API method you want to call, followed by your API key, secret key, session key and any additional parameters required by the method. It sends a POST request to the Facebook server and parses the returned JSON. The return value from minifb.call is a collection of basic Python data types, so it is very easy to work with. Generally API calls will return a list of integers / strings, or possibly a list of dictionaries.

Facebook Gotchas

The Facebook server imposes a timeout restriction on pages within your application. From my experiments this seems to be about 7 seconds, if the Facebook server doesn’t receive a response from your web app within that time limit it will display ‘page not found’, or words to that affect. If your server is under strain and you are also making a lot of api calls then it is quite possible to go over the timeout. I initially had this problem, but it turned out to be due to a faulty DNS server which webfaction.com quickly fixed for me. So you may not experience this issue, but if you do I would suggest reducing the number of API calls you make if possible, and if you don’t care about the return value of your API calls it would be worthwhile running them in a separate thread. I wrote the following helper function to do just that.

def fire_and_forget(callable, *args, **kwargs):

    def do_callable():
        try:
            callable(*args, **kwargs)
        except:
            pass

    thread = Thread(target=do_callable)
    thread.start()

If you wrap an API call with fire_and_forget it will run asynchronously and reduce the time to handle the request.

Cliffhanger

Hopefully I have convinced you that technology wise, writing a Facebook application is fairly straight-forward. Unfortunately there are other hardships which you will have to face when writing your app. I’ll go over them in Part III.

Writing a Facebook Application with Python, Pt. I

Saturday, February 9th, 2008

I promised to write up my experiences developing Virtual Microbes, a Facebook application. Its a lot to get through so I’ve decided to split it up in to installments. This installment is a lightning tour of the components in a Facebook application.

Facebook applications are basically content served up by any http server and seamlessly presented to users within Facebook pages. There are two ways this is done; either with an iframe tag or with Facebook Markup Language (FBML), which is basically HTML with additional tags to access Facebook features. Using an iframe may be the simplest option because you can just serve pages in the way you would with any web application, but FBML offers some additional capabilities that you wouldn’t otherwise be able to take advantage of.

FBML

When the user requests a page within your application, the Facebook server maps the url on to a corresponding url on your server, retrieves the FBML, converts it to HTML, then inserts the content in to the Facebook page. Of course, its all transparent to the end user, who doesn’t know and probably doesn’t care where the content is coming from. FBML supports a large subset of HTML tags, and also CSS, so you can format and style pages as normal. The additional tags are used to insert content, such as user details / photos and various widgets within your content. For instance the <fb:name uid=”12345″/> tag would insert the name of the Facebook user with the user id 12345.

FBJS

FBML supports FBJS, which is basically a slightly crippled form of Javascript which is re-written by the Facebook server to create a sandbox that prevents conflicts with Facebook’s own JS code, HTML and CSS. It also cripples some Javascript features so that your code can only run in response to active events initiated by the user, such as clicks — but not to events that the user hasn’t directly caused. I guess Facebook do this to avoid annoying the user with impolite Javascript code, but it does mean you will probably have to modify your coding style to compensate. Simple code should work as you would expect it to, but you will probably find that your code breaks if you refer directly to nodes in the DOM, which contains IDs that are different from the originals in your FBML. For instance if you use getElementById to get an explicit element, it is unlikely to work.

Facebook API

In addition to FBML, Facebook also offers a web service that you can use to retrieve information regarding users and access various site features. For example, you can ask Facebook for a list of a users friends, send out notifications and emails, set FBML to be displayed in a users profile page and do various other site related tasks. You send the details of the API method you want to call and the server returns a response in XML or JSON.

FBQL

You can retrieve a lot of information with the Facebook API, but occasionally you may need to make more complex queries on the various pieces of information stored regarding users. Naturally Facebook doesn’t want to give application developers the ability to drop or modify tables, so Facebook offers a cut down version of SQL that you can access via an API call. You can only SELECT with FBQL and there are restrictions regarding the columns you can use in the WHERE clause. For instance to query the user table, you must know either the users id or their name. I guess this is to prevent people from sucking down their entire database. But it does appear that if you know a users name you can retrieve a lot of information about them, that you wouldn’t be able to access through the site itself. And you don’t need to be an application developer either, you can user the test console to enter a query and retrieve the results. This feels like a privacy concern, but I guess applications couldn’t add much value without this kind of information.

That covers the basics components involved in writing a Facebook application, in the next exciting installment of this post series, I’ll cover how to write a Facebook application with a Python web framework.

Virtual Microbes

Monday, February 4th, 2008

I hacked together a Facebook application recently. I was looking in to integrating Becontrary.com with Facebook, but I had an idea for a simple app that would help me learn the ropes with FB. Its called Virtual Microbes — the idea is that you give your friends a virtual disease and encourage them to pass it on. You gain a point each time you give a friend a microbe and each time a friend (or friend of friend) passes it on, which has the potential for exponential growth. Its completely pointless, and couldn’t exist outside of the social networking sandbox, but it gave me the opportunity to experiment with integrating Turbogears with Facebook’s application system. There was some pain initially, but ultimately it went smoothly. I’ll write up my experiences with it, and give away some of the code soon.

Rotonym, what the heck is a rotonym?

Tuesday, January 22nd, 2008

Rotonyms are words that ROT-13 in to other words. I discovered the term from this site, which I found during my morning Reddit session. I think the author invented the term, because the only reference I found to ‘rotonym’ came from his site. Long story short, I knocked out a Python script to find all the rotonyms, given a list of words (just for the heck of it). I like problems like this. Its like the kind of work you had to do in high school and uni, before you enter the real word of programming and discover that most problems have blurry definitions and its hard to tell if your solution actualy works in all cases. Here’s the code, let me know if you have a better solution.

words = [line.rstrip() for line in open("WORD.LST")]
words_set = set(words)

letters = "abcdefghijklmnopqrstuvwxyz"
repl = dict(zip(letters, letters[13:]+letters[:13]))

def rot13(word):
    return "".join(repl.get(c, c) for c in word)

found = []

for word in words:
    rotword = rot13(word)
    if rotword in words_set:
        found.append( (word, rotword) )
        words_set.discard(word)

found.sort( key=lambda words:(len(words[0]), words[0]) )
for word, rotword in found:
    print "%s\\t%s"%(word, rotword)

If you want to run it, you will need this word list. Its not the most interesting code you will see, but I was impressed at how much functionality Python squeezes in to each line, without making it too obfusticated. It would be interesting to see this solved in other languages for comparison.

Update: fs111 reminded me that there was a rot13 string encoding in Python. So the code becomes:

words = [line.rstrip() for line in open("WORD.LST")]
words_set = set(words)

found = []

for word in words:
    rotword = word.encode("rot13")
    if rotword in words_set:
        found.append( (word, rotword) )
        words_set.discard(word)

found.sort( key=lambda words:(len(words[0]), words[0]) )
for word, rotword in found:
    print "%s\\t%s"%(word, rotword)

Netstring theory

Saturday, January 19th, 2008

I have create a google code project for my Python netstring module.

So what is a netstring? A netstring is a way of encoding strings of data in a file or network stream. The classic way of doing this is to terminate the string with a special character, such as carriage return, line-feed or a null byte. But this means that when reading the encoded data you have to check every character in the stream to see if it is the terminator character — which can be inefficient. It also makes it impossible to encode a string that contains the terminator character, because it will be incorrectly interpreted as the end of the string. Netstrings solve both these problems by encoding the size of the string up-front.

A string encoded as a netstring consists of the length of the string in ASCII, followed by a colon, the string itself and a comma character. For example, here is my name encoded as two netstrings:

4:Will,7:McGugan,

It’s a very simple protocol, but it can simplify writing file formats (Not everything need be XML!) and encoding network streams. For the official documentation on netstrings see http://cr.yp.to/proto/netstrings.txt.

You can install the netstring module with following command:

easy_install netstring

You can individual encode netstrings with the netstring.encode function, but it will probably be simpler to use the netstring.FileEncoder class which takes a writable file-like object as the only parameter, then call the write method to encode and write netstrings to the file. For network streams I would suggest writing a small proxy class that implements a write method that calls the sockets send method.

Decoding the netstring file / stream is done with the netstring.Decoder class. Simply create a Decoder object then call its feed method with data from the stream. The feed method is a generator that yields strings as they are decoded. Note that the data you feed to the decoder need not be whole netstrings, it could be a portion of a netstring or a group of netstrings — the decoder will buffer the data until it has encoded a full string, or strings. This means that feed may yield zero or mode strings, depending on the data you give it.

The following pseudo-code shows how you might use netstrings as the basis of a network stream (which is the purpose they were intended for).

import netstring

decoder = netstring.Decoder()

# Assumes that 'sock' is a previously opened socket
while True:
    data = sock.recv(1024)
    if not data:
        break
    for packet in decoder.feed(data):
        handle_packet(packet)

The license is Public Domain, even though Google Code claims otherwise (there was no setting for PD).

Fun with Fibonacci

Wednesday, December 12th, 2007

Just read an interesting blog post about comparing Python and Haskell code to calculate the Fibonacci sequence. I wrote a faster version, just for the hell of it. I realise that it is not a fair comparison any more, and doesn’t prove anything, but it does demonstrate a useful optimization technique. Here’s the code…

from time import time

def memoize(f):
    f._cache = {}
    def do_f(n):
        if n in f._cache:
            return f._cache[n]
        r = f(n)
        f._cache[n] = r
        return r
    return do_f

@memoize
def fib(n):
   if n == 0 or n == 1:
      return n
   else:
      return fib(n-1) + fib(n-2)

if __name__ == "__main__":
    start_time = time()
    for i in range(36):
        print "n=%d => %d" % (i, fib(i))

    print "Time elapsed: %f" % (time() - start_time)

When I run it on my machine, it claims to take 0.00000 seconds. Damn, thats fast!

Bountiful

Friday, December 7th, 2007

My employer has placed a number of bounties for wxPython features. Pays cash!

wxPython Bounties

A bad review

Wednesday, November 14th, 2007

I got a bad review of my book on Amazon.com. I wanted to post a comment to address his points, but Amazon told me that I must have purchased an item to post — which I have (many times)! So I thought I would post my comment here (below).

I’m the author of Beginning Game Development with Python and Pygame. Let me take a moment to comment on your scathing review.

1) As the title of the book indicates, the book is intended for beginners. As such there is an introduction to Python in the first two chapters. A total of 30 pages out of approximately 300. I don’t think this is unreasonable.

2) Some of the smaller listings aren’t in the downloadable files because they weren’t intended to run independently. A few small stand-alone listings in the early chapters don’t have filenames by them. My fault entirely, but then the downloadable code is organized in to a folder for each chapter - making it simple to find a listing you are looking for. The downloadable files don’t include the GameObjects library (or PyOpenGL). This is intentional — it is better to get the up-to-date versions. However, full instructions on how to download and install these libraries are given in the README.txt file and the book.

3) I use the GameObjects vector class because it is simple to use and efficient. But I do talk about how to go about creating your own vector class, which is far more important than the choice of library. I don’t use the Pygame sprite class, because it is more important that the reader knows how to manage sprites manually, before using the short-cut.

4) You must walk before you can run, young padawan. Pygame isn’t a game creation kit, it is an API. You can’t write a game if you don’t know how to do the simple stuff. If I write about how to create tic-tac-toe, then all you can do is create tic-tac-toe games.

5) 3D games are important. I don’t think you can find a clearer more accessible introduction to 3D anywhere, for any language.

There are topics that I would have have covered, if I had more time and space (although my book still covers more subjects than typical games books twice the size). Games development is a huge field. I chose to cover the essentials and topics that are poorly covered elsewhere. You are entitled to your one-star review Craig, but I would ask others to check out the free chapter on my blog before making a decision.

http://tinyurl.com/3xdmyq

Will McGugan