Jon Loyens RSS

Technologist, Tennis Fan, Musician

Archive

May
31st
Sun
permalink

The Python Twitter API, Timezones and PYTZ

In coding the open source Django Twitter Tribes app, I ran into what’s a pretty common problem for a lot of developers.  Alex Z, the designer of Bazaarvoice’s twitter page had created a wonderful skin for my tribes application.  However, one of the things he wanted to do was to list the Twitter status updates’ times using the nice, human readable format: ‘n hrs, m mins, d days ago’.  This presented me with a few problems that I had to overcome:

1) The Python Twitter API has a nice convenience function that allows you to get the time the status update was left in seconds.  This is a handy first step but in order to use Django’s ‘timesince’ filter, I needed a datetime object.  I accomplished this initially as follows:

for s in status_list:
s.created_at_as_datetime =         datetime.fromtimestamp(s.created_at_in_seconds)

(where status_list is the list of updates returned from the twitter API)

2) This worked but there was a side effect from the standpoint that the Twitter API returns time stamps in GMT.  When Python creates a new datetime object from a time stamp, it creates it by default in the local time of the machine.  This results in the time being significantly off when using the timesince filter.  What we need to do instead is create a datetime object in GMT.  In order to do this, you need to create a subclass of tzinfo.  Instead of doing this work though, we can use the PYTZ Python Timezone library instead like this:

for s in status_list:
s.created_at_as_datetime = pytz.utc.localize(datetime.fromtimestamp(s.created_at_in_seconds)).astimezone(pytz.timezone(‘US/Central’))

The PYTZ library is extremely useful for converting between timezones.  Essentially it has all the tzinfo subclasses for an entire database of timezones.  It makes working with timezones very easy.

Jan
2nd
Fri
permalink

Date Checking Python

So Python’s datetime library makes it pretty easy to check dates and it’s got an awesome timedelta class to make date math super simple.  We’ve got a client that we’re building out a social networking site for (in Django of course) and today I was working on a requirement for them that certain parts of the profile could only be publicly displayed if the user was over 18.

I thought this would be a perfect use of the timedelta class but alas, the you can only give create timedeltas in increments less than months (ie. weeks, days, minutes, seconds, milliseconds only).  First I thought that I could just multiply weeks but then you run into leap year issues etc.  Instead here’s a handy little function I added to our user profile model that’s still a pretty nice example of Python datetime code (note: we allow our users not to disclose their age but assume they’re underage if they haven’t):

def is_of_age(self):
  if self.dob:
    min_dob = datetime.date.today()
    min_dob = datetime.date(year=min_dob.year-18,
       month=min_dob.month, day=min_dob.day)
    return min_dob >= self.dob
return False

Dec
29th
Mon
permalink

Something quick and useful with Django and the Twitter API

Last night a friend contacted me about wanting to put together a quick stats application for Twitter.  I had never messed with the Twitter API before and didn’t know what was possible so I poked around and wrote up a simple application in a couple of hours.

The application I chose to write performs a simple task that’s actually surprisingly hard to do with Twitter’s interface:  Figure out which of your followers is following you back.  Twitter alerts you when someone starts following you but doesn’t when someone stops, so sometimes its hard to know when your @replies are falling on deaf ears.  This app solves that problem (and also lets you know which people to drop if they’re no longer following you too).

Without further ado, here’s the application: Twitter follow-back (please note that if a lot of people start hitting this, it may bump up against the Twitter api rate limit).

Using Django and the python-twitter api this was really easy to write.  The entire application is essentially one form and one view (no models, admin or anything else).  On GET the view renders the form which asks for a twitter username and password.  Here’s the (very simple) code for the form:

from django import forms
class TwitterUserInfoForm(forms.Form):
    ”“” TwitterUserInfoForm
    collect a twitter user name and password
    ”“”
    
    username = forms.CharField(label=”Twitter Username”)
    password = forms.CharField(widget=forms.PasswordInput, label=”Twitter Password”,help_text=”We won’t store this anywhere” )

Next up was the view itself that did the processing.  The python-twitter api is nice and pythonic.  For example,it nicely implements the equivalence operator on the twitter.User class such that a user that shows up in the followers list evaluates as equal to the same user object in the following list.  This allows us to use the ‘in’ operator to detect if the user is in both lists.  Additionally, this python-twitter api makes very thorough use of pythonic exceptions.  Here’s the post code from the view:

def follow_back(request):
    error = None
    if request.POST:
        form = TwitterUserInfoForm(request.POST)

        if form.is_valid():
    try:
        api = twitter.Api(username=form.cleaned_data[‘username’],                      password=form.cleaned_data[‘password’])
        friends = api.GetFriends()
        friends.sort(sort_by_screen_name)
        followers = api.GetFollowers()

        for friend in friends:
             friend.follows_me = friend in followers

        return render_to_response(‘twstats/followback_results.html’,
                  {‘friends’ : friends },
                  context_instance=RequestContext(request))
     except HTTPError, e:
        if e.code == 401:
            error = “Unknown Username/Password”
     else:
        error = str(e)
     except Exception, e:
        error = str(e)

    else:
        form = TwitterUserInfoForm()

    return render_to_response(‘twstats/followback_form.html’,
              {‘form’ : form, ’error’ : error, },
              context_instance=RequestContext(request))

I was going to try and deploy this as a google appengine application and got about 75% of the way there but unfortunately, python-twitter will need a bit more of a re-write since many of it’s dependencies are available in the Google appengine.  Therefore for the time being, it will exist in my webfaction account.

Enjoy.

Dec
28th
Sun
permalink
permalink
permalink
permalink
Dec
27th
Sat
permalink
permalink
permalink