Archive for the 'Python' Category

Writing interactive command line DB query tools with pyDBCLI

While some people can’t navigate a relational database without reaching for a GUI, the vast majority of us spend a good proportion of our lives inside interactive command line interfaces, such as psql or mysql.

What do you do, however, if there isn’t a CLI query tool available for the DB you’re working with?
I had this exact same problem recently with a project, the main reason for the lack of any such tooling is because I wasn’t actually dealing with a real DB at all, but an ODBC interface to a web service that exposed reporting data as if it were tables in a DB. Rather than spend the rest of my life messing around with queries in a hooked up spreadsheet, or repeatedly writing one off Python snippets, I decided to write my own psql-like tool.

Thus the first version of pyDBCLI was born; well not really, my first tool really only handled querying Webtrends (I’ll save that for another post), while pyDBCLI is a base class for making such tools as long as you have a DB API compatible cursor to query.
pyDBCLI is based on the fantastic cmd.Cmd, so you can extend pretty much exactly as you would would Cmd, except with some extra properties such as cursor and multi_prompt are provided.

In order to make a Cmd based tool behave more like psql I ended up overriding the parseline method with regular expressions to handle escaped commands such as “\d” and “\c”, fuzzing them if not escaped, or un-escaping them if escaped so that Cmd’s unmodified parseline method can handle parsing and dispatching to defined do_* methods.

The other main change was modifying the default method to dispatch command lines to the a query method for querying against the DB API cursor; as well as this default and several other commands will detect an unfinished SQL query and wait for a finishing character (“;” by default) before sending it (or doing anything) else. This is what the multi_prompt property is for, the prompt property is replaced with multi_prompt when a query spans more than one line, and is set back again when the query is finished and executed.

2 example tools are bundled with pyDBCLI, in the extras package:

  • odbc – a tool to query an ODBC exposed data source, using PyODBC; takes PyODBC compatible DSN strings.
  • litecli – a tool to query a SQLite database; SQLite has it’s own CLI tool to do this, which is very well rounded and much better than litecli, but this is provided as a fairly functional example tool.

Tomorrow I’ll discuss the original reason I whipped up pyDBCLI: creating a tool for querying Webtrends, via ODBC, quickly and with more ease.

Querying Webtrends analytics via ODBC with SQLAlchemy

Webtrends is a web traffic analytics package, similar to Google Analytics. Recently we had the requirement of being able to pull data out of reports on a Webtrends instance.
Luckily enough they have a nice RESTful data extraction API; not so luckily it is only available for Webtrends Analytics 9 instances, while we were limited in our requirements to Webtrends 8.

Prior to Webtrends 9 the official data extraction method is a Windows-only ODBC driver, primarily used for connecting Excel spreadsheets and Microsoft ADO applications. The driver provides a pseudo-relational-database interface to pre-made reports on a Webtrends instance, which you can query using a simple SQL-subset.
Notice I use qualifiers like “pseudo” and “interface”, that’s because what’s really going on in the background is the driver makes an HTTP call (with details such as the SQL being sent) to a web service on the Webtrends instance, and the web service returns some binary data representing data in the queried report, which the driver then returns as a table. The reports themselves aren’t actually real tables in a real database, although I’m sure this is how they’re represented somewhere in the Webtrends system, what we get back is a set of aggregated data normally used to display pretty graphs and bar charts in the web interface.

To make life easier for us, as we were already using SQLAlchemy for querying PostgreSQL tables, and we would need to mock our Webtrends data at some point, it made sense to be able to use SQLAlchemy for all the data objects; with that in mind I made the SQLAWebtrends dialect.
After installing SQLAWebtrends you can create ORM classes matching the Webtrends reports you want to query, and then, using a specially formatted DSN, run queries against them as you would any other DB.

Considerations in making a dialect for Webtrends:

  • Nearly all the special features of SQLAlchemy from full unicode support, to field binding and various row counting hacks, need to be disabled as the feature-set provided by the Windows ODBC driver are extremely limited.
  • Method for getting meta-data such as table names and columns needed to be overridden and done using Microsoft ADO compatible method.
  • Some combination of PyODBC’s column pre-binding and the Webtrends driver’s complete lack of features means any attempt at binding will fail, so being executing queries I needed to “unbind” them, replacing ? placeholders with actual data, and relying on inbuilt filtering method to provide any sort of field escaping/filtering.
  • LIMIT clauses are also extremely, erm, limited for want of better words. So that needed overriding too.
  • Finally, SQLAlchemy likes to wrap every value, include names, in quotes; Webtrends doesn’t like this, and quite frankly borks, so we disable this functionality too.
  • Bonus point: PyODBC rocks.

Caveats for use:

  • Your SQLAlchemy models for Webtrends reports shouldn’t include primary key columns, because frankly there probably aren’t any unique primary keys in the reports, but this doesn’t matter as SQLAlchemy won’t care as long as Webtrends doesn’t complain (which it won’t).
  • As with any other SQLAlchemy model you can call properties in the ORM class anything you like, but the underlying table column names need to match up to the column names in the Webtrends report.
  • The ODBC driver and web service don’t support JOINs, so you can’t use these with your ORM models either.
  • The iterator wrapper around the PyODBC cursor instance returned by queries will only ever returns one row unless you call .yield_per(1) on the query-set. I haven’t had time to figure out why this is the case, but I suspect it’s something to do with row pre-buffering, which is disabled as a consequence of yield_per.
  • Every now and again you’ll see rows with lots of blank values in them, except that any number values (measures in Webtrends) will be higher. If you look closely these are actually sums of all the values following it up until the next row of seemingly blank data. These are aggregated summary rows, displaying sums of the data for that particular subset of data (depending on which field is the “dimension” for the report, a sort of primary key used in creating reports). Unless you’re after this data as well, I find the best thing is to just do a quick check for so many blank fields and skip these rows.

Example using models and running a query:

from sqlalchemy.orm import mapper, sessionmaker
from sqlalchemy import create_engine
from sqlalchemy import String, MetaData, Column, Table

# You would probably setup your username, password
# host etc. here, including the profile and template
# you want to query.

# Create the DB connection
engine = create_engine(
    "webtrends+pyodbc://%s:%s@%s:80/%s?dsn=Webtrends&profile_guid=%s" %
        {user, password, host, template, profile}
)
metadata = MetaData(bind=engine)
Session = sessionmaker(bind=engine)
session = Session()

# Table schema
wt_user_report = Table('UsersByPages', metadata,
    Column('User', String, nullable=True),
    Column('PagesURLs', String, nullable=True),
    Column('PageHits', String, nullable=True),
    Column('TimePeriod', String, nullable=True),
    Column('StartDate', String, nullable=True),
    Column('EndDate', String, nullable=True)
)

# ORM class
class WTUserReport(object):
    pass
mapper(WTUserReport, wt_user_report)

# Create a query
query = session.query(WTUserReport).filter(
    TimePeriod="2010.m06.d22"
).yield_per(1) # Remember we need this for the iterator to work

# Iterate over the query-set and print some columns
for r in query:
    print "User %s hit %s %s times" % (
        r.User,
        r.PagesURLs,
        r.PageHits,
)

Generating sample unicode values for testing

When writing tests, there’s one thing we’re now sure to do because it’s caught us out so many times before: use unicode everywhere, particularly in Python.

Often, people will just go to Wikipedia and paste bits of unicode chosen at random into sample values, but that doesn’t always make for good readability when the tests you forgot to comment break two months later and you have to revisit them.

I’ve found a simple way to generate test unicode values that make sense, is to use an upside-down text generator, or some other l33t text transformer which produces unicode. Using text detailing whatever the sample value is supposed to represent, it’s still pretty legible at a glance and you’ll hopefully flag up those pesky UnicodeDecode errors quicker.

There’s a handy list of different text transformations and websites that will perform them for you on Wikipedia.

Announcing FuncBrows – A browser testing tool

For the short version: System web browser testing abstraction layer. Get it here

For the last month or so, I have been heavily investigating various functional browser testing tools, with the aim of adding them to our Continuous Integration build.

The History

I settled on using zc.testbrowser for writing quick, functional tests that can be added to the end of a unit test run. As testbrowser isn’t a full browser in itself, it’s fast to run tests with, and can easily be integrated with the Zope and Plone functional tools.
However, for a full suite of integration tests, testbrowser isn’t a great fit. It doesn’t support javascript, and won’t tell you that ‘The login button is missing in IE6’, or that ‘Firefox 3 can’t access the profile changer’. For this type of test, the current leader is Selenium, which can instrument and drive real browsers (IE, Firefox, Chrome, Safari), in order to perform more accurate real world tests.
Selenium is currently undergoing a massive revamp in order to add better functionality and clean up the API (including a mode that will work similar to testbrowser), however this means that we are currently stuck with the older, stable version, as it has python bindings and more documentation.

So, given these two tools, I wrote a simple suite of tests for a project. They registered a user, logged in, logged out, and changed a user profle. Not massively complex, but it’s often surprising how many times such simple processes can be broken, and you won’t notice as you tend to always use the same test user details.

This was all well and good, and everyone was happy and it was sunny.

The Problem

The problem then became, that although developers can write testbrowser scripts fairly easily, and run them quickly, selenium is a lot more heavyweight, requiring selenium installs, multiple browsers and virtual machines to run a full test.

Fundamentally, the selenium API is very different from testbrowser, and asking people to write both was never going to happen.

This meant that selenium was added to the CI build, but the developers would never usually run the tests themselves, creating a disconnect between the current tests that the developers would run as part of their unit test suite, and what would be tested more heavily with the CI build.

The Solution

I (with a lot of help from other people, some ‘creative language’, and some frustration) created FuncBrows. This is a simple, lightweight abstraction tool over both testbrowser and selenium, that can easily be extended to add more tools to it, when required (selenium v2 and twill are on the target list).
It can easily be included, and configured in one line, with a base set of tests that can then be run by every tool, as required.

This means that the developers can write fast tests for their own use, and the exact same code can then be reused for more complete browser testing later in the system tests. A quick, simple way to smoke test for browser issues

There is a samples directory in the github repository, with a simple example of how to set up the tests so that they can be run with either the python standard test runner, or nosetests.
It’s fairly simple, and can’t do any advanced stuff, it only progressed to the stage where we could dogfood our existing tests, I expect the API to grow slightly as we need more functionality from it.
Patches and issues gratefully accepted at the github page.

Get the bits here: Isotoma Github
Or ‘easy_install FuncBrows’

On Ubuntu Python, Exceptions and unnecessary imports

A few days ago Alexander Limi (one of Plone’s founders) tweeted the following:

Ubuntu Python: Raise an exception, import 190 modules: http://bit.ly/bCxlhC – this is why you don’t want to use the system Python.

Now this gets my goat on a few points. First up, why the hell would I not want to use the system python? If I’m using any sane distribution I’ll have package management and security updates, and any flaw in Python will be patched, packaged and tested by people that are far smarter than me. Upgrading the Python that ships with the Plone Unified Installer just isn’t going to be as easy, however you play it. And that’s without the risk of the Plone community moving on to more exciting things, leaving their version of Python unsupported.

Secondly, there’s a fatal flaw in the original blog post to which limi refers. Yes, on the desktop, Ubuntu imports 190 packages when an exception is raised. As the author explains this is to enable Apport to provide as much information to the Ubuntu devs about application failures. What the author does not mention is that this doesn’t happen on the Server edition of Ubuntu. Why would it? Apport is designed to handle desktop application failures and to improve the end user experience. It isn’t installed by default on the server edition, because it isn’t needed.

On my Karmic desktop:

Python 2.6.4 (r264:75706, Dec  7 2009, 18:43:55)
[GCC 4.4.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> len(sys.modules)
35
>>> raise KeyError
Traceback (most recent call last):
  File "", line 1, in 
KeyError
>>> len(sys.modules)
225

On my Karmic server:

Python 2.6.4 (r264:75706, Dec  7 2009, 18:43:55)
[GCC 4.4.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> len(sys.modules)
32
>>> raise KeyError
Traceback (most recent call last):
  File "", line 1, in 
KeyError
>>> len(sys.modules)
32

Being quick to condemn Ubuntu, and their packaging of Python, doesn’t do anyone any good. Think before you tweet. And don’t go live on a desktop distro.

Compiling Python2.3 on Karmic

We still have some (now very old) Plone 2.1 sites running.  Up until Ubuntu 8.10 python2.3 was still available from package management (albeit with limited support), but as of Ubuntu 9.04 python2.3 was removed entirely.

To recreate a development environment for these older sites means downloading Python 2.3 and compiling it by hand.  Unfortunately it’s not a default build any more – as it says on the download page:

Since the release candidate, we received various reports that the this release may fail to build on current operating systems, in particular on OS X. We have made no attempt to fix these problems, as the release is targeted for systems that were current at the time Python 2.3 was originally released. For more recent systems, you might have to come up with work-arounds.

For Ubuntu 9.10 (Karmic Koala) to compile python2.3 you’ll need to disable buffer overflow checking by doing the following:

wget http://www.python.org/ftp/python/2.3.7/Python-2.3.7.tgz
tar zxvf Python-2.3.7.tgz
cd Python-2.3.7
./configure --prefix=/usr/local BASECFLAGS=-U_FORTIFY_SOURCE
make
sudo make install

Getting the name of the current view in a Django template

Recently I have been working with generalised/reusable Django base templates, and I had the need to know the name of the current view using the template.
As it turns out, there currently aren’t any simple methods of doing this out there, and some of the nicer ones at their best make use of monkey patching.

After some playing around I found the cleanest, and quite simple, way is to use a custom template context processor.
A context processor provides extra values to bind to a template instance (it’s context; similar to including items in the data dict when calling render_to_response()).

By using a custom context processor we can assign a ‘current_view’ value to the template context, containing the namespaced name of the current view.
That just leaves one problem: how do we find the current view from within the request context.
inspect to the rescue!

Update: see Alexander Dutton’s comment for the even cleaner way by using middleware instead of stack inspection.

With inspect.stack() and inspect.getmodule() we can both grab the a stack of frames (e.g. the execution frames up to and including the current execution frame, which should be our context processor instance), and the module the frame is in.

from inspect import stack, getmodule

def ContextWithView(request):
    """Template context with current_view value,
    a string with the full namespaced django view in use.
    """
    # Frame 0 is the current frame
    # So assuming normal usage the frame of the view
    # calling this processor should be Frame 1
    name = getmodule(stack()[1][0]).__name__
    return {
        'current_view': "%s.%s" % (name, stack()[1][3]),
    }

To use this in a view, just import it and then pass it as the context in your render_to_response() call:

"""main/my_site/views/misc.py - misc views"""

from main.my_site.context_processors import ContextWithView

def my_view(request):
    # Do some stuff
    return render_to_response(
        'my_template.html',
        {},
        context_instance=ContextWithView(request)
    )

From within a template you can then use current_view, which for the above should output something like “main.my_site.views.misc.my_view”

Misc.

If you’re using RequestContext with your templates to make sure request, user etc. are always available in your templates, you can chain context processor calls like so:

from inspect import stack, getmodule
from django.template import RequestContext

def ContextWithView(request):
    """Template context with current_view value,
    a string with the full namespaced django view in use.
    """
    d = RequestContext(request)
    # Frame 0 is the current frame
    # So assuming normal usage the frame of the view
    # calling this processor should be Frame 1
    name = getmodule(stack()[1][0]).__name__
    d['current_view'] = "%s.%s" % (name, stack()[1][3])
    return d

If, like me, you then need to render a reverse URL using the ‘current_view’ variable, you’ll find the the {% url %} tag in Django only works on static strings, and not variables, so we need to make a custom tag to do this for us:

"""main/my_site/templatetags/extras.py
"""

from django.core.urlresolvers import reverse
from django import template

register = template.Library()

@register.simple_tag
def var_url(view, *args, **kwargs):
    return reverse(view, args=args, kwargs=kwargs)
{% comment %}
To use {% var_url %} in your template
just import and use as you would {% url %}
{% endcomment %}

{% load extras %}

{% block content %}
The URL for this view is <em>{% var_url current_view %}</em>.
{% endblock content %}

Monitoring Your Power Usage

I was lucky enough to attend LUG Radio and Ogg Camp recently and was inspired by a talk given by Andy Standford-Clark and his house that twitters. I had been sent a power monitor after switching power supplier, but never done much with it. Watching Andy’s energetic performance inspired my to dig it out and have a go at getting the data off it. Also the thought of adding twitter to anything was too strong to resist.

My unit is a branded version of Classic Current Cost unit with a standard transmitter. The first hurdle was to get the transmitter and the monitor talking again. The monitor has three buttons at the base, pressing and holding the middle button syncs the unit to the transmitter. It is possible to associate more than one transmitter to the monitor, the Classic model I believe can talk to 3 transmitters.

Next issue was connecting it to a PC, the unit didn’t come with a data cable. The output from the monitor is slow trickle of XML over a RJ45 serial connector. I found a suitable cable on eBay from Current Cost RJ45 to USB. They so sell the same cables on Amazon but on eBay the postage is free.

Connecting the cable is simple. To get access the feed is slightly more complex but luckily there are some great articles on the web. Connecting under Linux is fairly straight forward, there is fantastic article at http://www.linuxuk.org/2008/12/currentcost-and-ubuntu/. This explains how make the USB device available to read from as a device. Next you can use a Perl script from http://www.jibble.org/currentcost/ or read on for the Python I wrote to interpret the XML. I used the python-serial package from Karmic Koala Ubuntu.

#!/usr/bin/env python

import serial
from lxml import etree

# open the device, 2400 is baud rate
ser = serial.Serial('/dev/ttyUSB0', 2400, timeout=1)

while (True):
    reading = ser.readline()
    if reading:
        try:
            # use lxml to extract what we care about
            xml = etree.fromstring(reading)
            print xml.xpath('/msg/ch1/watts')[0].text
            print xml.xpath('/msg/tmpr')[0].text
        except:
            pass

This will print the watts and the temperature as the data is sent from the monitor via the serial cable.

Without any processing the input from the monitor looks like (replace the hrr with hr – I was losing the fight with html tags…):



    
        00002
205102
    
    CC02037771
    01429
    00000
    00000
    18.2


For some more detailed information check out: http://mungbean.org/blog/?p=477 and also http://knolleary.net/2008/05/05/power-graphing/ for some tips on graphing.

To finish off below is a script to log the data into a sqlite database:

#!/usr/bin/env python

import serial
import twitter
import sqlite3

from sqlalchemy import *
from sqlalchemy.orm import sessionmaker, mapper

from datetime import datetime
from lxml import etree
from lxml.etree import XMLSyntaxError
ser = serial.Serial('/dev/ttyUSB0', 2400, timeout=1)

while (True):
    reading = ser.readline()
    if reading:
        try:
            xml = etree.fromstring(reading)
            watts = xml.xpath('/msg/ch1/watts')[0].text
            temp = xml.xpath('/msg/tmpr')[0].text
            now = datetime.now()
            time = now.strftime("%Y%m%d%H%M%S")

            metadata = MetaData()
            engine = create_engine('sqlite:////home/yourusername/Desktop/power.db')
            metadata.bind = engine
            Session = sessionmaker(bind=engine, autoflush=True)
            session = Session()
            session.autocommit = False

            # create a class to map to
            class Power(object): pass
            table = Table('power', metadata, autoload=True)
            mapper(Power, table)

            entry = Power()
            entry.datetime = time
            entry.watts = watts
            entry.temperature = temp
            session.add(entry)
            session.commit()

            break
        except XMLSyntaxError:
            pass

Of Python, memcached and decorators: easy-peasy function caching

Following on from channam’s Memcached in 2 minutes, I’ve been working on a decorator to make life even simpler than this, memorised.
The most popular use-case for using memcached in Python apps is to cache the return value of a function or method. Over and over again you’ll find yourself doing something like:

mc = memcached.Client(['localhost:11211'])
def get_something(mc=mc):
    value = mc.get('something')
    if value is not None:
        return value
    else:
        # Do something else ...
        return 'hello world'

So in the interests of DRY, why not reduce that down to a reusable pattern?
We can do this using a decorator, to replace our function with a function that instead checks for the existance of some sort of key, returns the value, otherwise delegates to the actual function for output (and then caches this output back into memcache).

The simplest way to add reusable implementations of patterns such as these onto existing functions in Python is to use a decorator, effectively a function wrapper that replaces (or returns a replacement) function in place of the original call.
How does this help? Well using this we can intercept a call to the decorated function, generate a signature for use as a key in memcache, check if the item is available in the cache, if so return that, otherwise grab the output from the function, pop it into memcache using our generated key, and finally return this value.

The biggest challenge we face is generating the unique (at least to that particularly function call) key to reference in memcache. The way I’ve found best to do this is to use a combination of module, class name and key attributes (if it’s a method of an instance or decorated with @classmethod), function name, and call arguments, in this form: <module>.<class>[<key attributes>]::(<arguments>)

In order to do this we need information about both the arguments, and if it’s a method we also need information about the class the method is bound to. Ordinarily these are both easy tasks using the inspect module, and the im_self attribute (funnily enough, referencing self) that bound methods contain.
However, a quick explanation of how the @<decorator> shortcut tag works, and indeed how decorators work, reveals a slight kink in this assumption. For example take the following:

class Test:
    @testfunc
    def test(self, arg1):
        pass

This simple bit of syntactic sugar is actually equal in functionality to the following (which is how you had to do it before Python 2.4, see PEP-318):

class Test:
    def test(self, arg1):
        pass
    test = testfunc(test)

To explain further, as I said before, decorators are just function which take other function instances and wrap around or replace them, and they are applied at the time of definition, and not as you might think at first calltime.
This is the reason the decorator function returns a function, as it is first called and instanced at this point, but any arguments to the function it is wrapping are passed at call time as a call to the function returned by the decorator.

If this confuses you, don’t worry, it’s not actually that important right now, except for the fact that because the function instance is not passed in at calltime, it means it is not bound, and loses it’s frame (e.g. how it is called, from which instance etc.).
This means we can no longer use im_self and several of the class functions in the inspect module. What we can do however is cheat and use the fact that bound methods always pass in their bound object instance or class instance as the first argument of a call, the ’self’ argument.

memorised.decorators.memorise() uses the following trick, to first check if ’self’ or ‘cls’ (the standard first parameter of an @classmethod) is there, and then using the *args list of passed in arguments to access the first parameter and grab either .__class__._name for an object instance’s class name or .__name__ for class instances:

# Get the list of arg names from func_code
argnames = fn.func_code.co_varnames[:fn.func_code.co_argcount]

. . .

if classmethod:
    # Get the class name from the cls argument
    class_name = args[0].__name__
else:
    # Get the class name from the self argument
    class_name = args[0].__class__.__name__

By then merging *args and **kwargs, we can build a hash key of this particular function call. Next just create a handy MD5 hash of this string using hashlib.md5, and then do our memcache, checks pretty much as above in the first example.

Using memorise() to replace the first example, we get:

mc = memcached.Client(['localhost:11211'])
@memorise(mc=mc)
def get_something():
    return 'hello world'

Notice I’m still defining the mc variable to be a memcached.Client instance, memorise() does handle do this itself, either by using the default localhost:11211 server setting or by accepting a list of servers (via an argument named ‘mc_servers’). However, this isn’t ideal as the memcached.Client instance would be created every time a function definition is decorated with memorise() (which could be lots), so best to pass an instance in each time.
Not to mention the fact using dependency injection like this over any other way of keeping the instance (e.g. singleton) is much cleaner.

Another point of interest is that we need to always include the call parenthesis even when not passing in any arguments to memorise(), e.g. @memorise() and not @memorise, as you would expect from decorators such as @classmethod. This is best of the way arguments are passed to both a decorator, and then to the function being decorated. There are workarounds for this problem, but up until now I haven’t seen one that can be used with class-based decorators (which memorise() is). I hope to solve this in a future release, so expect a follow up post on using optional arguments with class-based decorators sometime in the near future.

Finally I’ll finish with a more realistic example of using this to decorate methods on a Django Model:

class BlogUser(User):
    objects = UserManager()

    def __unicode__(self):
        return u'%s' self.get_full_name();

    @property
    @memorise(parent_keys=['id'], mc=mc)
    def posts(self):
        Post.objects.filter(creator=self)

And there you have it, any posts by that user will be cached for as long as memcached’s cachetime is set, or until memorised.utils.uncache() is used to clear down the cache for that method.

Memcached in 2 Minutes

So you need to use memcached with Python? Below is a brief intro.

First install everything you need. I run Ubuntu so python-memcached memcached packages were required. python-memcached is available from www.tummy.com and the memcached site is available here

Start the memcached server if its not already running:

/usr/bin/memcached -m 64 -p 11211 -u nobody -l 127.0.0.1

The above gets you a 64Mb server, more than enough to play on.

Next some python below is from the interpreter:

>>> import memcache
>>> memc = memcache.Client(['127.0.0.1:11211'])
>>> class test():
>>>    def __init__(self):
>>>        self.message = "Hello, world"
>>>
>>> t = test()
>>> memc.set('testname', t, 120)
True
>>> got = memc.get('testname')
>>> got.message
'Hello, world'

The above instantiates an object and then saves it memcached with set() and then we get it back using get(). In the set call we specify the number 120, this is the number of seconds the object should be held in the cache. The usage is pretty simple: try and fetch from memcached if it fails fetch from your datasource and then save that document ready for next time.