All methods now return a Python/JSON value depicting the data Twitter sends back

This commit is contained in:
Ryan McGrath 2009-06-08 01:26:32 -04:00
parent 5342fbccc6
commit 402a2dddc0

127
tango.py
View file

@ -10,7 +10,7 @@
Questions, comments? ryan@venodesigns.net
"""
import httplib, urllib, urllib2, mimetypes, mimetools
import httplib, urllib, urllib2, mimetypes, mimetools, pprint
from urllib2 import HTTPError
@ -41,8 +41,6 @@ class setup:
self.handler = urllib2.HTTPBasicAuthHandler(self.auth_manager)
self.opener = urllib2.build_opener(self.handler)
self.authenticated = True
else:
pass
# OAuth functions; shortcuts for verifying the credentials.
def fetch_response_oauth(self, oauth_request):
@ -59,8 +57,12 @@ class setup:
# URL Shortening function huzzah
def shortenURL(self, url_to_shorten, shortener = "http://is.gd/api.php", query = "longurl"):
shortURL = urllib2.urlopen(shortener + "?" + urllib.urlencode({query: url_to_shorten})).read()
return shortURL
try:
return urllib2.urlopen(shortener + "?" + urllib.urlencode({query: url_to_shorten})).read()
except HTTPError, e:
if self.debug is True:
print e.headers
print "shortenURL() failed with a " + str(e.code) + " error code."
def constructApiURL(self, base_url, params):
queryURL = base_url
@ -71,38 +73,20 @@ class setup:
questionMarkUsed = True
return queryURL
def createGenericTimeline(self, existingTimeline):
# Many of Twitters API functions return the same style of data. This function just wraps it if we need it.
genericTimeline = []
for tweet in existingTimeline:
genericTimeline.append({
"created_at": tweet["created_at"],
"in_reply_to_screen_name": tweet["in_reply_to_screen_name"],
"in_reply_to_status_id": tweet["in_reply_to_status_id"],
"in_reply_to_user_id": tweet["in_reply_to_user_id"],
"id": tweet["id"],
"text": tweet["text"]
})
return genericTimeline
def getRateLimitStatus(self, rate_for = "requestingIP"):
try:
if rate_for == "requestingIP":
rate_limit = simplejson.load(urllib2.urlopen("http://twitter.com/account/rate_limit_status.json"))
return simplejson.load(urllib2.urlopen("http://twitter.com/account/rate_limit_status.json"))
else:
rate_limit = simplejson.load(self.opener.open("http://twitter.com/account/rate_limit_status.json"))
return simplejson.load(self.opener.open("http://twitter.com/account/rate_limit_status.json"))
except HTTPError, e:
if self.debug is True:
print e.headers
print "It seems that there's something wrong. Twitter gave you a " + str(e.code) + " error code; are you doing something you shouldn't be?"
return {"remaining-hits": rate_limit["remaining-hits"],
"hourly-limit": rate_limit["hourly-limit"],
"reset-time": rate_limit["reset-time"],
"reset-time-in-seconds": rate_limit["reset-time-in-seconds"]}
def getPublicTimeline(self):
try:
return self.createGenericTimeline(simplejson.load(urllib2.urlopen("http://twitter.com/statuses/public_timeline.json")))
return simplejson.load(urllib2.urlopen("http://twitter.com/statuses/public_timeline.json"))
except HTTPError, e:
if self.debug is True:
print e.headers
@ -112,7 +96,7 @@ class setup:
if self.authenticated is True:
try:
friendsTimelineURL = self.constructApiURL("http://twitter.com/statuses/friends_timeline.json", kwargs)
return self.createGenericTimeline(simplejson.load(self.opener.open(friendsTimelineURL)))
return simplejson.load(self.opener.open(friendsTimelineURL))
except HTTPError, e:
if self.debug is True:
print e.headers
@ -124,7 +108,7 @@ class setup:
def getUserTimeline(self, **kwargs):
userTimelineURL = self.constructApiURL("http://twitter.com/statuses/user_timeline/" + self.username + ".json", kwargs)
try:
return self.createGenericTimeline(simplejson.load(urllib2.urlopen(userTimelineURL)))
return simplejson.load(urllib2.urlopen(userTimelineURL))
except HTTPError, e:
if self.debug is True:
print e.headers
@ -135,8 +119,7 @@ class setup:
if self.authenticated is True:
try:
mentionsFeedURL = self.constructApiURL("http://twitter.com/statuses/mentions.json", kwargs)
mentionsFeed = simplejson.load(self.opener.open(mentionsFeedURL))
return self.createGenericTimeline(mentionsFeed)
return simplejson.load(self.opener.open(mentionsFeedURL))
except HTTPError, e:
if self.debug is True:
print e.headers
@ -147,13 +130,7 @@ class setup:
def showStatus(self, id):
try:
tweet = simplejson.load(self.opener.open("http://twitter.com/statuses/show/" + id + ".json"))
return {"created_at": tweet["created_at"],
"id": tweet["id"],
"text": tweet["text"],
"in_reply_to_status_id": tweet["in_reply_to_status_id"],
"in_reply_to_user_id": tweet["in_reply_to_user_id"],
"in_reply_to_screen_name": tweet["in_reply_to_screen_name"]}
return simplejson.load(self.opener.open("http://twitter.com/statuses/show/" + id + ".json"))
except HTTPError, e:
if self.debug is True:
print e.headers
@ -163,7 +140,7 @@ class setup:
def updateStatus(self, status, in_reply_to_status_id = None):
if self.authenticated is True:
try:
self.opener.open("http://twitter.com/statuses/update.json?", urllib.urlencode({"status": status}, {"in_reply_to_status_id": in_reply_to_status_id}))
return simplejson.load(self.opener.open("http://twitter.com/statuses/update.json?", urllib.urlencode({"status": status}, {"in_reply_to_status_id": in_reply_to_status_id})))
except HTTPError, e:
if self.debug is True:
print e.headers
@ -175,7 +152,7 @@ class setup:
def destroyStatus(self, id):
if self.authenticated is True:
try:
self.opener.open("http://twitter.com/status/destroy/" + id + ".json", "POST")
return simplejson.load(self.opener.open("http://twitter.com/status/destroy/" + id + ".json", "POST"))
except HTTPError, e:
if self.debug is True:
print e.headers
@ -312,7 +289,7 @@ class setup:
def updateDeliveryDevice(self, device_name = "none"):
if self.authenticated is True:
try:
self.opener.open("http://twitter.com/account/update_delivery_device.json?", urllib.urlencode({"device": device_name}))
return self.opener.open("http://twitter.com/account/update_delivery_device.json?", urllib.urlencode({"device": device_name}))
except HTTPError, e:
if self.debug is True:
print e.headers
@ -323,7 +300,7 @@ class setup:
def updateProfileColors(self, **kwargs):
if self.authenticated is True:
try:
self.opener.open(self.constructApiURL("http://twitter.com/account/update_profile_colors.json?", kwargs))
return self.opener.open(self.constructApiURL("http://twitter.com/account/update_profile_colors.json?", kwargs))
except HTTPError, e:
if self.debug is True:
print e.headers
@ -379,7 +356,7 @@ class setup:
if updateProfileQueryString != "":
try:
self.opener.open("http://twitter.com/account/update_profile.json?", updateProfileQueryString)
return self.opener.open("http://twitter.com/account/update_profile.json?", updateProfileQueryString)
except HTTPError, e:
if self.debug is True:
print e.headers
@ -391,8 +368,7 @@ class setup:
def getFavorites(self, page = "1"):
if self.authenticated is True:
try:
favoritesTimeline = simplejson.load(self.opener.open("http://twitter.com/favorites.json?page=" + page))
return self.createGenericTimeline(favoritesTimeline)
return simplejson.load(self.opener.open("http://twitter.com/favorites.json?page=" + page))
except HTTPError, e:
if self.debug:
print e.headers
@ -403,7 +379,7 @@ class setup:
def createFavorite(self, id):
if self.authenticated is True:
try:
self.opener.open("http://twitter.com/favorites/create/" + id + ".json", "")
return simplejson.load(self.opener.open("http://twitter.com/favorites/create/" + id + ".json", ""))
except HTTPError, e:
if self.debug:
print e.headers
@ -414,7 +390,7 @@ class setup:
def destroyFavorite(self, id):
if self.authenticated is True:
try:
self.opener.open("http://twitter.com/favorites/destroy/" + id + ".json", "")
return simplejson.load(self.opener.open("http://twitter.com/favorites/destroy/" + id + ".json", ""))
except HTTPError, e:
if self.debug:
print e.headers
@ -432,7 +408,7 @@ class setup:
if screen_name is not None:
apiURL = "http://twitter.com/notifications/follow/follow.json?screen_name=" + screen_name
try:
self.opener.open(apiURL, "")
return simplejson.load(self.opener.open(apiURL, ""))
except HTTPError, e:
if self.debug is True:
print e.headers
@ -450,7 +426,7 @@ class setup:
if screen_name is not None:
apiURL = "http://twitter.com/notifications/leave/leave.json?screen_name=" + screen_name
try:
self.opener.open(apiURL, "")
return simplejson.load(self.opener.open(apiURL, ""))
except HTTPError, e:
if self.debug is True:
print e.headers
@ -491,7 +467,7 @@ class setup:
def createBlock(self, id):
if self.authenticated is True:
try:
self.opener.open("http://twitter.com/blocks/create/" + id + ".json", "")
return simplejson.load(self.opener.open("http://twitter.com/blocks/create/" + id + ".json", ""))
except HTTPError, e:
if self.debug is True:
print e.headers
@ -502,7 +478,7 @@ class setup:
def destroyBlock(self, id):
if self.authenticated is True:
try:
self.opener.open("http://twitter.com/blocks/destroy/" + id + ".json", "")
return simplejson.load(self.opener.open("http://twitter.com/blocks/destroy/" + id + ".json", ""))
except HTTPError, e:
if self.debug is True:
print e.headers
@ -550,20 +526,7 @@ class setup:
def getSearchTimeline(self, search_query, optional_page):
params = urllib.urlencode({'q': search_query, 'rpp': optional_page}) # Doesn't hurt to do pages this way. *shrug*
try:
searchTimeline = simplejson.load(urllib2.urlopen("http://search.twitter.com/search.json", params))
# This one is custom built because the search feed is a bit different than the other feeds.
genericTimeline = []
for tweet in searchTimeline["results"]:
genericTimeline.append({
"created_at": tweet["created_at"],
"from_user": tweet["from_user"],
"from_user_id": tweet["from_user_id"],
"profile_image_url": tweet["profile_image_url"],
"id": tweet["id"],
"text": tweet["text"],
"to_user_id": tweet["to_user_id"]
})
return genericTimeline
return simplejson.load(urllib2.urlopen("http://search.twitter.com/search.json", params))
except HTTPError, e:
if self.debug is True:
print e.headers
@ -571,13 +534,7 @@ class setup:
def getCurrentTrends(self):
try:
# Returns an array of dictionary items containing the current trends
trendingTopicsURL = "http://search.twitter.com/trends.json"
trendingTopics = simplejson.load(urllib.urlopen(trendingTopicsURL))
trendingTopicsArray = []
for topic in trendingTopics['trends']:
trendingTopicsArray.append({"name" : topic['name'], "url" : topic['url']})
return trendingTopicsArray
return simplejson.load(urllib.urlopen("http://search.twitter.com/trends.json"))
except HTTPError, e:
if self.debug is True:
print e.headers
@ -586,15 +543,17 @@ class setup:
# The following methods are apart from the other Account methods, because they rely on a whole multipart-data posting function set.
def updateProfileBackgroundImage(self, filename, tile="true"):
if self.authenticated is True:
#try:
files = [("image", filename, open(filename).read())]
fields = []
content_type, body = self.encode_multipart_formdata(fields, files)
headers = {'Content-Type': content_type, 'Content-Length': str(len(body))}
r = urllib2.Request("http://twitter.com/account/update_profile_background_image.json?tile=" + tile, body, headers)
return self.opener.open(r).read()
#except:
#print "Oh god, this failed so horribly."
try:
files = [("image", filename, open(filename).read())]
fields = []
content_type, body = self.encode_multipart_formdata(fields, files)
headers = {'Content-Type': content_type, 'Content-Length': str(len(body))}
r = urllib2.Request("http://twitter.com/account/update_profile_background_image.json?tile=" + tile, body, headers)
return self.opener.open(r).read()
except HTTPError, e:
if self.debug is True:
print e.headers
print "updateProfileBackgroundImage() failed with a " + str(e.code) + " error code."
else:
print "You realize you need to be authenticated to change a background image, right?"
@ -607,8 +566,10 @@ class setup:
headers = {'Content-Type': content_type, 'Content-Length': str(len(body))}
r = urllib2.Request("http://twitter.com/account/update_profile_image.json", body, headers)
return self.opener.open(r).read()
except:
print "Oh god, this failed so horribly."
except HTTPError, e:
if self.debug is True:
print e.headers
print "updateProfileImage() failed with a " + str(e.code) + " error code."
else:
print "You realize you need to be authenticated to change a profile image, right?"