Tango now raises an APILimit error that should make catching API rate limit issues easier. More work was also done to fix the bad way that strings are concatenated, though this is still ongoing - this updates applies to both tango and tango3k.

This commit is contained in:
Ryan McGrath 2009-07-20 00:24:23 -04:00
parent 5236a85cda
commit 9bd05aaab6
2 changed files with 130 additions and 92 deletions

111
tango.py
View file

@ -14,6 +14,16 @@ import httplib, urllib, urllib2, mimetypes, mimetools
from urllib2 import HTTPError from urllib2 import HTTPError
__author__ = "Ryan McGrath <ryan@venodesigns.net>"
__version__ = "0.5"
"""
REQUEST_TOKEN_URL = 'https://twitter.com/oauth/request_token'
ACCESS_TOKEN_URL = 'https://twitter.com/oauth/access_token'
AUTHORIZATION_URL = 'http://twitter.com/oauth/authorize'
SIGNIN_URL = 'http://twitter.com/oauth/authenticate'
"""
try: try:
import simplejson import simplejson
except ImportError: except ImportError:
@ -25,10 +35,17 @@ except ImportError:
try: try:
import oauth import oauth
except ImportError: except ImportError:
# Need to figure out a better way to signal that this is an optional thing pass
print "Tango requires oauth for authentication purposes. http://oauth.googlecode.com/svn/code/python/oauth/oauth.py"
class TangoError(Exception): class TangoError(Exception):
def __init__(self, msg, error_code=None):
self.msg = msg
if error_code == 400:
raise APILimit(msg)
def __str__(self):
return repr(self.msg)
class APILimit(TangoError):
def __init__(self, msg): def __init__(self, msg):
self.msg = msg self.msg = msg
def __str__(self): def __str__(self):
@ -53,7 +70,7 @@ class setup:
test_verify = simplejson.load(self.opener.open("http://twitter.com/account/verify_credentials.json")) test_verify = simplejson.load(self.opener.open("http://twitter.com/account/verify_credentials.json"))
self.authenticated = True self.authenticated = True
except HTTPError, e: except HTTPError, e:
raise TangoError("Authentication failed with your provided credentials. Try again? (" + str(e.code) + " failure)") raise TangoError("Authentication failed with your provided credentials. Try again? (%s failure)" % `e.code`, e.code)
# OAuth functions; shortcuts for verifying the credentials. # OAuth functions; shortcuts for verifying the credentials.
def fetch_response_oauth(self, oauth_request): def fetch_response_oauth(self, oauth_request):
@ -88,7 +105,7 @@ class setup:
else: else:
raise TangoError("You need to be authenticated to check a rate limit status on an account.") raise TangoError("You need to be authenticated to check a rate limit status on an account.")
except HTTPError, e: except HTTPError, e:
raise TangoError("It seems that there's something wrong. Twitter gave you a %s error code; are you doing something you shouldn't be?" % `e.code`) raise TangoError("It seems that there's something wrong. Twitter gave you a %s error code; are you doing something you shouldn't be?" % `e.code`, e.code)
def getPublicTimeline(self): def getPublicTimeline(self):
try: try:
@ -121,7 +138,7 @@ class setup:
return simplejson.load(urllib2.urlopen(userTimelineURL)) return simplejson.load(urllib2.urlopen(userTimelineURL))
except HTTPError, e: except HTTPError, e:
raise TangoError("Failed with a %s error code. Does this user hide/protect their updates? If so, you'll need to authenticate and be their friend to get their timeline." raise TangoError("Failed with a %s error code. Does this user hide/protect their updates? If so, you'll need to authenticate and be their friend to get their timeline."
% `e.code`) % `e.code`, e.code)
def getUserMentions(self, **kwargs): def getUserMentions(self, **kwargs):
if self.authenticated is True: if self.authenticated is True:
@ -129,15 +146,16 @@ class setup:
mentionsFeedURL = self.constructApiURL("http://twitter.com/statuses/mentions.json", kwargs) mentionsFeedURL = self.constructApiURL("http://twitter.com/statuses/mentions.json", kwargs)
return simplejson.load(self.opener.open(mentionsFeedURL)) return simplejson.load(self.opener.open(mentionsFeedURL))
except HTTPError, e: except HTTPError, e:
raise TangoError("getUserMentions() failed with a %s error code." % `e.code`) raise TangoError("getUserMentions() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("getUserMentions() requires you to be authenticated.") raise TangoError("getUserMentions() requires you to be authenticated.")
def showStatus(self, id): def showStatus(self, id):
try: try:
return simplejson.load(self.opener.open("http://twitter.com/statuses/show/" + id + ".json")) return simplejson.load(self.opener.open("http://twitter.com/statuses/show/%s.json" % id))
except HTTPError, e: except HTTPError, e:
raise TangoError("Failed with a %s error code. Does this user hide/protect their updates? You'll need to authenticate and be friends to get their timeline." % `e.code`) raise TangoError("Failed with a %s error code. Does this user hide/protect their updates? You'll need to authenticate and be friends to get their timeline."
% `e.code`, e.code)
def updateStatus(self, status, in_reply_to_status_id = None): def updateStatus(self, status, in_reply_to_status_id = None):
if self.authenticated is True: if self.authenticated is True:
@ -146,16 +164,16 @@ class setup:
try: try:
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}))) 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: except HTTPError, e:
raise TangoError("updateStatus() failed with a " + str(e.code) + "error code.") raise TangoError("updateStatus() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("updateStatus() requires you to be authenticated.") raise TangoError("updateStatus() requires you to be authenticated.")
def destroyStatus(self, id): def destroyStatus(self, id):
if self.authenticated is True: if self.authenticated is True:
try: try:
return simplejson.load(self.opener.open("http://twitter.com/status/destroy/" + id + ".json", "POST")) return simplejson.load(self.opener.open("http://twitter.com/status/destroy/%s.json", "POST" % id))
except HTTPError, e: except HTTPError, e:
raise TangoError("destroyStatus() failed with a %s error code." % `e.code`) raise TangoError("destroyStatus() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("destroyStatus() requires you to be authenticated.") raise TangoError("destroyStatus() requires you to be authenticated.")
@ -165,9 +183,9 @@ class setup:
self.opener.open("http://twitter.com/account/end_session.json", "") self.opener.open("http://twitter.com/account/end_session.json", "")
self.authenticated = False self.authenticated = False
except HTTPError, e: except HTTPError, e:
raise TangoError("endSession failed with a %s error code." % `e.code`) raise TangoError("endSession failed with a %s error code." % `e.code`, e.code)
else: else:
print "You can't end a session when you're not authenticated to begin with." raise TangoError("You can't end a session when you're not authenticated to begin with.")
def getDirectMessages(self, since_id = None, max_id = None, count = None, page = "1"): def getDirectMessages(self, since_id = None, max_id = None, count = None, page = "1"):
if self.authenticated is True: if self.authenticated is True:
@ -182,7 +200,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open(apiURL)) return simplejson.load(self.opener.open(apiURL))
except HTTPError, e: except HTTPError, e:
raise TangoError("getDirectMessages() failed with a %s error code." % `e.code`) raise TangoError("getDirectMessages() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("getDirectMessages() requires you to be authenticated.") raise TangoError("getDirectMessages() requires you to be authenticated.")
@ -199,7 +217,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open(apiURL)) return simplejson.load(self.opener.open(apiURL))
except HTTPError, e: except HTTPError, e:
raise TangoError("getSentMessages() failed with a %s error code." % `e.code`) raise TangoError("getSentMessages() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("getSentMessages() requires you to be authenticated.") raise TangoError("getSentMessages() requires you to be authenticated.")
@ -209,7 +227,7 @@ class setup:
try: try:
return self.opener.open("http://twitter.com/direct_messages/new.json", urllib.urlencode({"user": user, "text": text})) return self.opener.open("http://twitter.com/direct_messages/new.json", urllib.urlencode({"user": user, "text": text}))
except HTTPError, e: except HTTPError, e:
raise TangoError("sendDirectMessage() failed with a %s error code." % `e.code`) raise TangoError("sendDirectMessage() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("Your message must not be longer than 140 characters") raise TangoError("Your message must not be longer than 140 characters")
else: else:
@ -218,9 +236,9 @@ class setup:
def destroyDirectMessage(self, id): def destroyDirectMessage(self, id):
if self.authenticated is True: if self.authenticated is True:
try: try:
return self.opener.open("http://twitter.com/direct_messages/destroy/" + id + ".json", "") return self.opener.open("http://twitter.com/direct_messages/destroy/%s.json" % id, "")
except HTTPError, e: except HTTPError, e:
raise TangoError("destroyDirectMessage() failed with a %s error code." % `e.code`) raise TangoError("destroyDirectMessage() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("You must be authenticated to destroy a direct message.") raise TangoError("You must be authenticated to destroy a direct message.")
@ -236,9 +254,10 @@ class setup:
try: try:
return simplejson.load(self.opener.open(apiURL)) return simplejson.load(self.opener.open(apiURL))
except HTTPError, e: except HTTPError, e:
# Rate limiting is done differently here for API reasons...
if e.code == 403: if e.code == 403:
raise TangoError("You've hit the update limit for this method. Try again in 24 hours.") raise TangoError("You've hit the update limit for this method. Try again in 24 hours.")
raise TangoError("createFriendship() failed with a %s error code." % `e.code`) raise TangoError("createFriendship() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("createFriendship() requires you to be authenticated.") raise TangoError("createFriendship() requires you to be authenticated.")
@ -254,7 +273,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open(apiURL)) return simplejson.load(self.opener.open(apiURL))
except HTTPError, e: except HTTPError, e:
raise TangoError("destroyFriendship() failed with a %s error code." % `e.code`) raise TangoError("destroyFriendship() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("destroyFriendship() requires you to be authenticated.") raise TangoError("destroyFriendship() requires you to be authenticated.")
@ -263,7 +282,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open("http://twitter.com/friendships/exists.json", urllib.urlencode({"user_a": user_a, "user_b": user_b}))) return simplejson.load(self.opener.open("http://twitter.com/friendships/exists.json", urllib.urlencode({"user_a": user_a, "user_b": user_b})))
except HTTPError, e: except HTTPError, e:
raise TangoError("checkIfFriendshipExists() failed with a %s error code." % `e.code`) raise TangoError("checkIfFriendshipExists() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("checkIfFriendshipExists(), oddly, requires that you be authenticated.") raise TangoError("checkIfFriendshipExists(), oddly, requires that you be authenticated.")
@ -272,7 +291,7 @@ class setup:
try: try:
return 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: except HTTPError, e:
raise TangoError("updateDeliveryDevice() failed with a %s error code." % `e.code`) raise TangoError("updateDeliveryDevice() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("updateDeliveryDevice() requires you to be authenticated.") raise TangoError("updateDeliveryDevice() requires you to be authenticated.")
@ -281,7 +300,7 @@ class setup:
try: try:
return 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: except HTTPError, e:
raise TangoError("updateProfileColors() failed with a %s error code." % `e.code`) raise TangoError("updateProfileColors() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("updateProfileColors() requires you to be authenticated.") raise TangoError("updateProfileColors() requires you to be authenticated.")
@ -335,7 +354,7 @@ class setup:
try: try:
return 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: except HTTPError, e:
raise TangoError("updateProfile() failed with a %s error code." % `e.code`) raise TangoError("updateProfile() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("updateProfile() requires you to be authenticated.") raise TangoError("updateProfile() requires you to be authenticated.")
@ -344,7 +363,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open("http://twitter.com/favorites.json?page=" + page)) return simplejson.load(self.opener.open("http://twitter.com/favorites.json?page=" + page))
except HTTPError, e: except HTTPError, e:
raise TangoError("getFavorites() failed with a %s error code." % `e.code`) raise TangoError("getFavorites() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("getFavorites() requires you to be authenticated.") raise TangoError("getFavorites() requires you to be authenticated.")
@ -353,7 +372,7 @@ class setup:
try: try:
return simplejson.load(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: except HTTPError, e:
raise TangoError("createFavorite() failed with a %s error code." % `e.code`) raise TangoError("createFavorite() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("createFavorite() requires you to be authenticated.") raise TangoError("createFavorite() requires you to be authenticated.")
@ -362,7 +381,7 @@ class setup:
try: try:
return simplejson.load(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: except HTTPError, e:
raise TangoError("destroyFavorite() failed with a %s error code." % `e.code`) raise TangoError("destroyFavorite() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("destroyFavorite() requires you to be authenticated.") raise TangoError("destroyFavorite() requires you to be authenticated.")
@ -378,7 +397,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open(apiURL, "")) return simplejson.load(self.opener.open(apiURL, ""))
except HTTPError, e: except HTTPError, e:
raise TangoError("notificationFollow() failed with a %s error code." % `e.code`) raise TangoError("notificationFollow() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("notificationFollow() requires you to be authenticated.") raise TangoError("notificationFollow() requires you to be authenticated.")
@ -394,7 +413,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open(apiURL, "")) return simplejson.load(self.opener.open(apiURL, ""))
except HTTPError, e: except HTTPError, e:
raise TangoError("notificationLeave() failed with a %s error code." % `e.code`) raise TangoError("notificationLeave() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("notificationLeave() requires you to be authenticated.") raise TangoError("notificationLeave() requires you to be authenticated.")
@ -409,7 +428,7 @@ class setup:
try: try:
return simplejson.load(urllib2.urlopen(apiURL)) return simplejson.load(urllib2.urlopen(apiURL))
except HTTPError, e: except HTTPError, e:
raise TangoError("getFriendsIDs() failed with a %s error code." % `e.code`) raise TangoError("getFriendsIDs() failed with a %s error code." % `e.code`, e.code)
def getFollowersIDs(self, id = None, user_id = None, screen_name = None, page = "1"): def getFollowersIDs(self, id = None, user_id = None, screen_name = None, page = "1"):
apiURL = "" apiURL = ""
@ -422,14 +441,14 @@ class setup:
try: try:
return simplejson.load(urllib2.urlopen(apiURL)) return simplejson.load(urllib2.urlopen(apiURL))
except HTTPError, e: except HTTPError, e:
raise TangoError("getFollowersIDs() failed with a %s error code." % `e.code`) raise TangoError("getFollowersIDs() failed with a %s error code." % `e.code`, e.code)
def createBlock(self, id): def createBlock(self, id):
if self.authenticated is True: if self.authenticated is True:
try: try:
return simplejson.load(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: except HTTPError, e:
raise TangoError("createBlock() failed with a %s error code." % `e.code`) raise TangoError("createBlock() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("createBlock() requires you to be authenticated.") raise TangoError("createBlock() requires you to be authenticated.")
@ -438,7 +457,7 @@ class setup:
try: try:
return simplejson.load(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: except HTTPError, e:
raise TangoError("destroyBlock() failed with a %s error code." % `e.code`) raise TangoError("destroyBlock() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("destroyBlock() requires you to be authenticated.") raise TangoError("destroyBlock() requires you to be authenticated.")
@ -453,14 +472,14 @@ class setup:
try: try:
return simplejson.load(urllib2.urlopen(apiURL)) return simplejson.load(urllib2.urlopen(apiURL))
except HTTPError, e: except HTTPError, e:
raise TangoError("checkIfBlockExists() failed with a %s error code." % `e.code`) raise TangoError("checkIfBlockExists() failed with a %s error code." % `e.code`, e.code)
def getBlocking(self, page = "1"): def getBlocking(self, page = "1"):
if self.authenticated is True: if self.authenticated is True:
try: try:
return simplejson.load(self.opener.open("http://twitter.com/blocks/blocking.json?page=" + page)) return simplejson.load(self.opener.open("http://twitter.com/blocks/blocking.json?page=" + page))
except HTTPError, e: except HTTPError, e:
raise TangoError("getBlocking() failed with a %s error code." % `e.code`) raise TangoError("getBlocking() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("getBlocking() requires you to be authenticated") raise TangoError("getBlocking() requires you to be authenticated")
@ -469,7 +488,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open("http://twitter.com/blocks/blocking/ids.json")) return simplejson.load(self.opener.open("http://twitter.com/blocks/blocking/ids.json"))
except HTTPError, e: except HTTPError, e:
raise TangoError("getBlockedIDs() failed with a %s error code." % `e.code`) raise TangoError("getBlockedIDs() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("getBlockedIDs() requires you to be authenticated.") raise TangoError("getBlockedIDs() requires you to be authenticated.")
@ -478,7 +497,7 @@ class setup:
try: try:
return simplejson.load(urllib2.urlopen(searchURL)) return simplejson.load(urllib2.urlopen(searchURL))
except HTTPError, e: except HTTPError, e:
raise TangoError("getSearchTimeline() failed with a %s error code." % `e.code`) raise TangoError("getSearchTimeline() failed with a %s error code." % `e.code`, e.code)
def getCurrentTrends(self, excludeHashTags = False): def getCurrentTrends(self, excludeHashTags = False):
apiURL = "http://search.twitter.com/trends/current.json" apiURL = "http://search.twitter.com/trends/current.json"
@ -487,7 +506,7 @@ class setup:
try: try:
return simplejson.load(urllib.urlopen(apiURL)) return simplejson.load(urllib.urlopen(apiURL))
except HTTPError, e: except HTTPError, e:
raise TangoError("getCurrentTrends() failed with a %s error code." % `e.code`) raise TangoError("getCurrentTrends() failed with a %s error code." % `e.code`, e.code)
def getDailyTrends(self, date = None, exclude = False): def getDailyTrends(self, date = None, exclude = False):
apiURL = "http://search.twitter.com/trends/daily.json" apiURL = "http://search.twitter.com/trends/daily.json"
@ -503,7 +522,7 @@ class setup:
try: try:
return simplejson.load(urllib.urlopen(apiURL)) return simplejson.load(urllib.urlopen(apiURL))
except HTTPError, e: except HTTPError, e:
raise TangoError("getDailyTrends() failed with a %s error code." % `e.code`) raise TangoError("getDailyTrends() failed with a %s error code." % `e.code`, e.code)
def getWeeklyTrends(self, date = None, exclude = False): def getWeeklyTrends(self, date = None, exclude = False):
apiURL = "http://search.twitter.com/trends/daily.json" apiURL = "http://search.twitter.com/trends/daily.json"
@ -519,14 +538,14 @@ class setup:
try: try:
return simplejson.load(urllib.urlopen(apiURL)) return simplejson.load(urllib.urlopen(apiURL))
except HTTPError, e: except HTTPError, e:
raise TangoError("getWeeklyTrends() failed with a %s error code." % `e.code`) raise TangoError("getWeeklyTrends() failed with a %s error code." % `e.code`, e.code)
def getSavedSearches(self): def getSavedSearches(self):
if self.authenticated is True: if self.authenticated is True:
try: try:
return simplejson.load(self.opener.open("http://twitter.com/saved_searches.json")) return simplejson.load(self.opener.open("http://twitter.com/saved_searches.json"))
except HTTPError, e: except HTTPError, e:
raise TangoError("getSavedSearches() failed with a %s error code." % `e.code`) raise TangoError("getSavedSearches() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("getSavedSearches() requires you to be authenticated.") raise TangoError("getSavedSearches() requires you to be authenticated.")
@ -535,7 +554,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open("http://twitter.com/saved_searches/show/" + id + ".json")) return simplejson.load(self.opener.open("http://twitter.com/saved_searches/show/" + id + ".json"))
except HTTPError, e: except HTTPError, e:
raise TangoError("showSavedSearch() failed with a %s error code." % `e.code`) raise TangoError("showSavedSearch() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("showSavedSearch() requires you to be authenticated.") raise TangoError("showSavedSearch() requires you to be authenticated.")
@ -544,7 +563,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open("http://twitter.com/saved_searches/create.json?query=" + query, "")) return simplejson.load(self.opener.open("http://twitter.com/saved_searches/create.json?query=" + query, ""))
except HTTPError, e: except HTTPError, e:
raise TangoError("createSavedSearch() failed with a %s error code." % `e.code`) raise TangoError("createSavedSearch() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("createSavedSearch() requires you to be authenticated.") raise TangoError("createSavedSearch() requires you to be authenticated.")
@ -553,7 +572,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open("http://twitter.com/saved_searches/destroy/" + id + ".json", "")) return simplejson.load(self.opener.open("http://twitter.com/saved_searches/destroy/" + id + ".json", ""))
except HTTPError, e: except HTTPError, e:
raise TangoError("destroySavedSearch() failed with a %s error code." % `e.code`) raise TangoError("destroySavedSearch() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("destroySavedSearch() requires you to be authenticated.") raise TangoError("destroySavedSearch() requires you to be authenticated.")
@ -568,7 +587,7 @@ class setup:
r = urllib2.Request("http://twitter.com/account/update_profile_background_image.json?tile=" + tile, body, headers) r = urllib2.Request("http://twitter.com/account/update_profile_background_image.json?tile=" + tile, body, headers)
return self.opener.open(r).read() return self.opener.open(r).read()
except HTTPError, e: except HTTPError, e:
raise TangoError("updateProfileBackgroundImage() failed with a %s error code." % `e.code`) raise TangoError("updateProfileBackgroundImage() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("You realize you need to be authenticated to change a background image, right?") raise TangoError("You realize you need to be authenticated to change a background image, right?")
@ -582,7 +601,7 @@ class setup:
r = urllib2.Request("http://twitter.com/account/update_profile_image.json", body, headers) r = urllib2.Request("http://twitter.com/account/update_profile_image.json", body, headers)
return self.opener.open(r).read() return self.opener.open(r).read()
except HTTPError, e: except HTTPError, e:
raise TangoError("updateProfileImage() failed with a %s error code." % `e.code`) raise TangoError("updateProfileImage() failed with a %s error code." % `e.code`, e.code)
else: else:
raise TangoError("You realize you need to be authenticated to change a profile image, right?") raise TangoError("You realize you need to be authenticated to change a profile image, right?")

View file

@ -14,6 +14,16 @@ import http.client, urllib, urllib.request, urllib.error, urllib.parse, mimetype
from urllib.error import HTTPError from urllib.error import HTTPError
__author__ = "Ryan McGrath <ryan@venodesigns.net>"
__version__ = "0.5"
"""
REQUEST_TOKEN_URL = 'https://twitter.com/oauth/request_token'
ACCESS_TOKEN_URL = 'https://twitter.com/oauth/access_token'
AUTHORIZATION_URL = 'http://twitter.com/oauth/authorize'
SIGNIN_URL = 'http://twitter.com/oauth/authenticate'
"""
try: try:
import simplejson import simplejson
except ImportError: except ImportError:
@ -25,10 +35,17 @@ except ImportError:
try: try:
import oauth import oauth
except ImportError: except ImportError:
# Need to figure out a better way to signal that this is an optional thing pass
print("Tango requires oauth for authentication purposes. http://oauth.googlecode.com/svn/code/python/oauth/oauth.py")
class TangoError(Exception): class TangoError(Exception):
def __init__(self, msg, error_code=None):
self.msg = msg
if error_code == 400:
raise APILimit(msg)
def __str__(self):
return repr(self.msg)
class APILimit(TangoError):
def __init__(self, msg): def __init__(self, msg):
self.msg = msg self.msg = msg
def __str__(self): def __str__(self):
@ -53,7 +70,7 @@ class setup:
test_verify = simplejson.load(self.opener.open("http://twitter.com/account/verify_credentials.json")) test_verify = simplejson.load(self.opener.open("http://twitter.com/account/verify_credentials.json"))
self.authenticated = True self.authenticated = True
except HTTPError as e: except HTTPError as e:
raise TangoError("Authentication failed with your provided credentials. Try again? (" + str(e.code) + " failure)") raise TangoError("Authentication failed with your provided credentials. Try again? (%s failure)" % repr(e.code), e.code)
# OAuth functions; shortcuts for verifying the credentials. # OAuth functions; shortcuts for verifying the credentials.
def fetch_response_oauth(self, oauth_request): def fetch_response_oauth(self, oauth_request):
@ -88,7 +105,7 @@ class setup:
else: else:
raise TangoError("You need to be authenticated to check a rate limit status on an account.") raise TangoError("You need to be authenticated to check a rate limit status on an account.")
except HTTPError as e: except HTTPError as e:
raise TangoError("It seems that there's something wrong. Twitter gave you a %s error code; are you doing something you shouldn't be?" % repr(e.code)) raise TangoError("It seems that there's something wrong. Twitter gave you a %s error code; are you doing something you shouldn't be?" % repr(e.code), e.code)
def getPublicTimeline(self): def getPublicTimeline(self):
try: try:
@ -121,7 +138,7 @@ class setup:
return simplejson.load(urllib.request.urlopen(userTimelineURL)) return simplejson.load(urllib.request.urlopen(userTimelineURL))
except HTTPError as e: except HTTPError as e:
raise TangoError("Failed with a %s error code. Does this user hide/protect their updates? If so, you'll need to authenticate and be their friend to get their timeline." raise TangoError("Failed with a %s error code. Does this user hide/protect their updates? If so, you'll need to authenticate and be their friend to get their timeline."
% repr(e.code)) % repr(e.code), e.code)
def getUserMentions(self, **kwargs): def getUserMentions(self, **kwargs):
if self.authenticated is True: if self.authenticated is True:
@ -129,15 +146,16 @@ class setup:
mentionsFeedURL = self.constructApiURL("http://twitter.com/statuses/mentions.json", kwargs) mentionsFeedURL = self.constructApiURL("http://twitter.com/statuses/mentions.json", kwargs)
return simplejson.load(self.opener.open(mentionsFeedURL)) return simplejson.load(self.opener.open(mentionsFeedURL))
except HTTPError as e: except HTTPError as e:
raise TangoError("getUserMentions() failed with a %s error code." % repr(e.code)) raise TangoError("getUserMentions() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("getUserMentions() requires you to be authenticated.") raise TangoError("getUserMentions() requires you to be authenticated.")
def showStatus(self, id): def showStatus(self, id):
try: try:
return simplejson.load(self.opener.open("http://twitter.com/statuses/show/" + id + ".json")) return simplejson.load(self.opener.open("http://twitter.com/statuses/show/%s.json" % id))
except HTTPError as e: except HTTPError as e:
raise TangoError("Failed with a %s error code. Does this user hide/protect their updates? You'll need to authenticate and be friends to get their timeline." % repr(e.code)) raise TangoError("Failed with a %s error code. Does this user hide/protect their updates? You'll need to authenticate and be friends to get their timeline."
% repr(e.code), e.code)
def updateStatus(self, status, in_reply_to_status_id = None): def updateStatus(self, status, in_reply_to_status_id = None):
if self.authenticated is True: if self.authenticated is True:
@ -146,16 +164,16 @@ class setup:
try: try:
return simplejson.load(self.opener.open("http://twitter.com/statuses/update.json?", urllib.parse.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.parse.urlencode({"status": status, "in_reply_to_status_id": in_reply_to_status_id})))
except HTTPError as e: except HTTPError as e:
raise TangoError("updateStatus() failed with a " + str(e.code) + "error code.") raise TangoError("updateStatus() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("updateStatus() requires you to be authenticated.") raise TangoError("updateStatus() requires you to be authenticated.")
def destroyStatus(self, id): def destroyStatus(self, id):
if self.authenticated is True: if self.authenticated is True:
try: try:
return simplejson.load(self.opener.open("http://twitter.com/status/destroy/" + id + ".json", "POST")) return simplejson.load(self.opener.open("http://twitter.com/status/destroy/%s.json", "POST" % id))
except HTTPError as e: except HTTPError as e:
raise TangoError("destroyStatus() failed with a %s error code." % repr(e.code)) raise TangoError("destroyStatus() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("destroyStatus() requires you to be authenticated.") raise TangoError("destroyStatus() requires you to be authenticated.")
@ -165,9 +183,9 @@ class setup:
self.opener.open("http://twitter.com/account/end_session.json", "") self.opener.open("http://twitter.com/account/end_session.json", "")
self.authenticated = False self.authenticated = False
except HTTPError as e: except HTTPError as e:
raise TangoError("endSession failed with a %s error code." % repr(e.code)) raise TangoError("endSession failed with a %s error code." % repr(e.code), e.code)
else: else:
print("You can't end a session when you're not authenticated to begin with.") raise TangoError("You can't end a session when you're not authenticated to begin with.")
def getDirectMessages(self, since_id = None, max_id = None, count = None, page = "1"): def getDirectMessages(self, since_id = None, max_id = None, count = None, page = "1"):
if self.authenticated is True: if self.authenticated is True:
@ -182,7 +200,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open(apiURL)) return simplejson.load(self.opener.open(apiURL))
except HTTPError as e: except HTTPError as e:
raise TangoError("getDirectMessages() failed with a %s error code." % repr(e.code)) raise TangoError("getDirectMessages() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("getDirectMessages() requires you to be authenticated.") raise TangoError("getDirectMessages() requires you to be authenticated.")
@ -199,7 +217,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open(apiURL)) return simplejson.load(self.opener.open(apiURL))
except HTTPError as e: except HTTPError as e:
raise TangoError("getSentMessages() failed with a %s error code." % repr(e.code)) raise TangoError("getSentMessages() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("getSentMessages() requires you to be authenticated.") raise TangoError("getSentMessages() requires you to be authenticated.")
@ -209,7 +227,7 @@ class setup:
try: try:
return self.opener.open("http://twitter.com/direct_messages/new.json", urllib.parse.urlencode({"user": user, "text": text})) return self.opener.open("http://twitter.com/direct_messages/new.json", urllib.parse.urlencode({"user": user, "text": text}))
except HTTPError as e: except HTTPError as e:
raise TangoError("sendDirectMessage() failed with a %s error code." % repr(e.code)) raise TangoError("sendDirectMessage() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("Your message must not be longer than 140 characters") raise TangoError("Your message must not be longer than 140 characters")
else: else:
@ -218,9 +236,9 @@ class setup:
def destroyDirectMessage(self, id): def destroyDirectMessage(self, id):
if self.authenticated is True: if self.authenticated is True:
try: try:
return self.opener.open("http://twitter.com/direct_messages/destroy/" + id + ".json", "") return self.opener.open("http://twitter.com/direct_messages/destroy/%s.json" % id, "")
except HTTPError as e: except HTTPError as e:
raise TangoError("destroyDirectMessage() failed with a %s error code." % repr(e.code)) raise TangoError("destroyDirectMessage() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("You must be authenticated to destroy a direct message.") raise TangoError("You must be authenticated to destroy a direct message.")
@ -236,9 +254,10 @@ class setup:
try: try:
return simplejson.load(self.opener.open(apiURL)) return simplejson.load(self.opener.open(apiURL))
except HTTPError as e: except HTTPError as e:
# Rate limiting is done differently here for API reasons...
if e.code == 403: if e.code == 403:
raise TangoError("You've hit the update limit for this method. Try again in 24 hours.") raise TangoError("You've hit the update limit for this method. Try again in 24 hours.")
raise TangoError("createFriendship() failed with a %s error code." % repr(e.code)) raise TangoError("createFriendship() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("createFriendship() requires you to be authenticated.") raise TangoError("createFriendship() requires you to be authenticated.")
@ -254,7 +273,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open(apiURL)) return simplejson.load(self.opener.open(apiURL))
except HTTPError as e: except HTTPError as e:
raise TangoError("destroyFriendship() failed with a %s error code." % repr(e.code)) raise TangoError("destroyFriendship() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("destroyFriendship() requires you to be authenticated.") raise TangoError("destroyFriendship() requires you to be authenticated.")
@ -263,7 +282,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open("http://twitter.com/friendships/exists.json", urllib.parse.urlencode({"user_a": user_a, "user_b": user_b}))) return simplejson.load(self.opener.open("http://twitter.com/friendships/exists.json", urllib.parse.urlencode({"user_a": user_a, "user_b": user_b})))
except HTTPError as e: except HTTPError as e:
raise TangoError("checkIfFriendshipExists() failed with a %s error code." % repr(e.code)) raise TangoError("checkIfFriendshipExists() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("checkIfFriendshipExists(), oddly, requires that you be authenticated.") raise TangoError("checkIfFriendshipExists(), oddly, requires that you be authenticated.")
@ -272,7 +291,7 @@ class setup:
try: try:
return self.opener.open("http://twitter.com/account/update_delivery_device.json?", urllib.parse.urlencode({"device": device_name})) return self.opener.open("http://twitter.com/account/update_delivery_device.json?", urllib.parse.urlencode({"device": device_name}))
except HTTPError as e: except HTTPError as e:
raise TangoError("updateDeliveryDevice() failed with a %s error code." % repr(e.code)) raise TangoError("updateDeliveryDevice() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("updateDeliveryDevice() requires you to be authenticated.") raise TangoError("updateDeliveryDevice() requires you to be authenticated.")
@ -281,7 +300,7 @@ class setup:
try: try:
return 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 as e: except HTTPError as e:
raise TangoError("updateProfileColors() failed with a %s error code." % repr(e.code)) raise TangoError("updateProfileColors() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("updateProfileColors() requires you to be authenticated.") raise TangoError("updateProfileColors() requires you to be authenticated.")
@ -335,7 +354,7 @@ class setup:
try: try:
return 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 as e: except HTTPError as e:
raise TangoError("updateProfile() failed with a %s error code." % repr(e.code)) raise TangoError("updateProfile() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("updateProfile() requires you to be authenticated.") raise TangoError("updateProfile() requires you to be authenticated.")
@ -344,7 +363,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open("http://twitter.com/favorites.json?page=" + page)) return simplejson.load(self.opener.open("http://twitter.com/favorites.json?page=" + page))
except HTTPError as e: except HTTPError as e:
raise TangoError("getFavorites() failed with a %s error code." % repr(e.code)) raise TangoError("getFavorites() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("getFavorites() requires you to be authenticated.") raise TangoError("getFavorites() requires you to be authenticated.")
@ -353,7 +372,7 @@ class setup:
try: try:
return simplejson.load(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 as e: except HTTPError as e:
raise TangoError("createFavorite() failed with a %s error code." % repr(e.code)) raise TangoError("createFavorite() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("createFavorite() requires you to be authenticated.") raise TangoError("createFavorite() requires you to be authenticated.")
@ -362,7 +381,7 @@ class setup:
try: try:
return simplejson.load(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 as e: except HTTPError as e:
raise TangoError("destroyFavorite() failed with a %s error code." % repr(e.code)) raise TangoError("destroyFavorite() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("destroyFavorite() requires you to be authenticated.") raise TangoError("destroyFavorite() requires you to be authenticated.")
@ -378,7 +397,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open(apiURL, "")) return simplejson.load(self.opener.open(apiURL, ""))
except HTTPError as e: except HTTPError as e:
raise TangoError("notificationFollow() failed with a %s error code." % repr(e.code)) raise TangoError("notificationFollow() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("notificationFollow() requires you to be authenticated.") raise TangoError("notificationFollow() requires you to be authenticated.")
@ -394,7 +413,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open(apiURL, "")) return simplejson.load(self.opener.open(apiURL, ""))
except HTTPError as e: except HTTPError as e:
raise TangoError("notificationLeave() failed with a %s error code." % repr(e.code)) raise TangoError("notificationLeave() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("notificationLeave() requires you to be authenticated.") raise TangoError("notificationLeave() requires you to be authenticated.")
@ -409,7 +428,7 @@ class setup:
try: try:
return simplejson.load(urllib.request.urlopen(apiURL)) return simplejson.load(urllib.request.urlopen(apiURL))
except HTTPError as e: except HTTPError as e:
raise TangoError("getFriendsIDs() failed with a %s error code." % repr(e.code)) raise TangoError("getFriendsIDs() failed with a %s error code." % repr(e.code), e.code)
def getFollowersIDs(self, id = None, user_id = None, screen_name = None, page = "1"): def getFollowersIDs(self, id = None, user_id = None, screen_name = None, page = "1"):
apiURL = "" apiURL = ""
@ -422,14 +441,14 @@ class setup:
try: try:
return simplejson.load(urllib.request.urlopen(apiURL)) return simplejson.load(urllib.request.urlopen(apiURL))
except HTTPError as e: except HTTPError as e:
raise TangoError("getFollowersIDs() failed with a %s error code." % repr(e.code)) raise TangoError("getFollowersIDs() failed with a %s error code." % repr(e.code), e.code)
def createBlock(self, id): def createBlock(self, id):
if self.authenticated is True: if self.authenticated is True:
try: try:
return simplejson.load(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 as e: except HTTPError as e:
raise TangoError("createBlock() failed with a %s error code." % repr(e.code)) raise TangoError("createBlock() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("createBlock() requires you to be authenticated.") raise TangoError("createBlock() requires you to be authenticated.")
@ -438,7 +457,7 @@ class setup:
try: try:
return simplejson.load(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 as e: except HTTPError as e:
raise TangoError("destroyBlock() failed with a %s error code." % repr(e.code)) raise TangoError("destroyBlock() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("destroyBlock() requires you to be authenticated.") raise TangoError("destroyBlock() requires you to be authenticated.")
@ -453,14 +472,14 @@ class setup:
try: try:
return simplejson.load(urllib.request.urlopen(apiURL)) return simplejson.load(urllib.request.urlopen(apiURL))
except HTTPError as e: except HTTPError as e:
raise TangoError("checkIfBlockExists() failed with a %s error code." % repr(e.code)) raise TangoError("checkIfBlockExists() failed with a %s error code." % repr(e.code), e.code)
def getBlocking(self, page = "1"): def getBlocking(self, page = "1"):
if self.authenticated is True: if self.authenticated is True:
try: try:
return simplejson.load(self.opener.open("http://twitter.com/blocks/blocking.json?page=" + page)) return simplejson.load(self.opener.open("http://twitter.com/blocks/blocking.json?page=" + page))
except HTTPError as e: except HTTPError as e:
raise TangoError("getBlocking() failed with a %s error code." % repr(e.code)) raise TangoError("getBlocking() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("getBlocking() requires you to be authenticated") raise TangoError("getBlocking() requires you to be authenticated")
@ -469,7 +488,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open("http://twitter.com/blocks/blocking/ids.json")) return simplejson.load(self.opener.open("http://twitter.com/blocks/blocking/ids.json"))
except HTTPError as e: except HTTPError as e:
raise TangoError("getBlockedIDs() failed with a %s error code." % repr(e.code)) raise TangoError("getBlockedIDs() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("getBlockedIDs() requires you to be authenticated.") raise TangoError("getBlockedIDs() requires you to be authenticated.")
@ -478,7 +497,7 @@ class setup:
try: try:
return simplejson.load(urllib.request.urlopen(searchURL)) return simplejson.load(urllib.request.urlopen(searchURL))
except HTTPError as e: except HTTPError as e:
raise TangoError("getSearchTimeline() failed with a %s error code." % repr(e.code)) raise TangoError("getSearchTimeline() failed with a %s error code." % repr(e.code), e.code)
def getCurrentTrends(self, excludeHashTags = False): def getCurrentTrends(self, excludeHashTags = False):
apiURL = "http://search.twitter.com/trends/current.json" apiURL = "http://search.twitter.com/trends/current.json"
@ -487,7 +506,7 @@ class setup:
try: try:
return simplejson.load(urllib.urlopen(apiURL)) return simplejson.load(urllib.urlopen(apiURL))
except HTTPError as e: except HTTPError as e:
raise TangoError("getCurrentTrends() failed with a %s error code." % repr(e.code)) raise TangoError("getCurrentTrends() failed with a %s error code." % repr(e.code), e.code)
def getDailyTrends(self, date = None, exclude = False): def getDailyTrends(self, date = None, exclude = False):
apiURL = "http://search.twitter.com/trends/daily.json" apiURL = "http://search.twitter.com/trends/daily.json"
@ -503,7 +522,7 @@ class setup:
try: try:
return simplejson.load(urllib.urlopen(apiURL)) return simplejson.load(urllib.urlopen(apiURL))
except HTTPError as e: except HTTPError as e:
raise TangoError("getDailyTrends() failed with a %s error code." % repr(e.code)) raise TangoError("getDailyTrends() failed with a %s error code." % repr(e.code), e.code)
def getWeeklyTrends(self, date = None, exclude = False): def getWeeklyTrends(self, date = None, exclude = False):
apiURL = "http://search.twitter.com/trends/daily.json" apiURL = "http://search.twitter.com/trends/daily.json"
@ -519,14 +538,14 @@ class setup:
try: try:
return simplejson.load(urllib.urlopen(apiURL)) return simplejson.load(urllib.urlopen(apiURL))
except HTTPError as e: except HTTPError as e:
raise TangoError("getWeeklyTrends() failed with a %s error code." % repr(e.code)) raise TangoError("getWeeklyTrends() failed with a %s error code." % repr(e.code), e.code)
def getSavedSearches(self): def getSavedSearches(self):
if self.authenticated is True: if self.authenticated is True:
try: try:
return simplejson.load(self.opener.open("http://twitter.com/saved_searches.json")) return simplejson.load(self.opener.open("http://twitter.com/saved_searches.json"))
except HTTPError as e: except HTTPError as e:
raise TangoError("getSavedSearches() failed with a %s error code." % repr(e.code)) raise TangoError("getSavedSearches() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("getSavedSearches() requires you to be authenticated.") raise TangoError("getSavedSearches() requires you to be authenticated.")
@ -535,7 +554,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open("http://twitter.com/saved_searches/show/" + id + ".json")) return simplejson.load(self.opener.open("http://twitter.com/saved_searches/show/" + id + ".json"))
except HTTPError as e: except HTTPError as e:
raise TangoError("showSavedSearch() failed with a %s error code." % repr(e.code)) raise TangoError("showSavedSearch() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("showSavedSearch() requires you to be authenticated.") raise TangoError("showSavedSearch() requires you to be authenticated.")
@ -544,7 +563,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open("http://twitter.com/saved_searches/create.json?query=" + query, "")) return simplejson.load(self.opener.open("http://twitter.com/saved_searches/create.json?query=" + query, ""))
except HTTPError as e: except HTTPError as e:
raise TangoError("createSavedSearch() failed with a %s error code." % repr(e.code)) raise TangoError("createSavedSearch() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("createSavedSearch() requires you to be authenticated.") raise TangoError("createSavedSearch() requires you to be authenticated.")
@ -553,7 +572,7 @@ class setup:
try: try:
return simplejson.load(self.opener.open("http://twitter.com/saved_searches/destroy/" + id + ".json", "")) return simplejson.load(self.opener.open("http://twitter.com/saved_searches/destroy/" + id + ".json", ""))
except HTTPError as e: except HTTPError as e:
raise TangoError("destroySavedSearch() failed with a %s error code." % repr(e.code)) raise TangoError("destroySavedSearch() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("destroySavedSearch() requires you to be authenticated.") raise TangoError("destroySavedSearch() requires you to be authenticated.")
@ -568,7 +587,7 @@ class setup:
r = urllib.request.Request("http://twitter.com/account/update_profile_background_image.json?tile=" + tile, body, headers) r = urllib.request.Request("http://twitter.com/account/update_profile_background_image.json?tile=" + tile, body, headers)
return self.opener.open(r).read() return self.opener.open(r).read()
except HTTPError as e: except HTTPError as e:
raise TangoError("updateProfileBackgroundImage() failed with a %s error code." % repr(e.code)) raise TangoError("updateProfileBackgroundImage() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("You realize you need to be authenticated to change a background image, right?") raise TangoError("You realize you need to be authenticated to change a background image, right?")
@ -582,7 +601,7 @@ class setup:
r = urllib.request.Request("http://twitter.com/account/update_profile_image.json", body, headers) r = urllib.request.Request("http://twitter.com/account/update_profile_image.json", body, headers)
return self.opener.open(r).read() return self.opener.open(r).read()
except HTTPError as e: except HTTPError as e:
raise TangoError("updateProfileImage() failed with a %s error code." % repr(e.code)) raise TangoError("updateProfileImage() failed with a %s error code." % repr(e.code), e.code)
else: else:
raise TangoError("You realize you need to be authenticated to change a profile image, right?") raise TangoError("You realize you need to be authenticated to change a profile image, right?")