From 23d3cca4fcc3de482770d4975f6032bf4b5cd87e Mon Sep 17 00:00:00 2001 From: Ryan McGrath Date: Mon, 1 Jun 2009 04:52:07 -0400 Subject: [PATCH] Finished off the Account methods after a 3 hour session of figuring out multipart data in Python - this seriously needs to be part of the standard language. The only thing I've wished I had out of the box thus far. --- tango.py | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/tango.py b/tango.py index d7cc832..d50897c 100644 --- a/tango.py +++ b/tango.py @@ -8,18 +8,18 @@ Questions, comments? ryan@venodesigns.net """ -import httplib, urllib, urllib2, mimetypes +import httplib, urllib, urllib2, mimetypes, mimetools from urllib2 import HTTPError try: import simplejson -except: +except ImportError: print "Tango requires the simplejson library to work. http://www.undefined.org/python/" try: import oauth -except: +except ImportError: print "Tango requires oauth for authentication purposes. http://oauth.googlecode.com/svn/code/python/oauth/oauth.py" class setup: @@ -70,7 +70,7 @@ class setup: return queryURL def createGenericTimeline(self, existingTimeline): - # Many of Twitter's API functions return the same style of data. This function just wraps it if we need it. + # 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({ @@ -379,3 +379,56 @@ class setup: if self.debug is True: print e.headers print "getCurrentTrends() failed with a " + str(e.code) + " error code." + + # 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." + else: + print "You realize you need to be authenticated to change a background image, right?" + + def updateProfileImage(self, filename): + 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_image.json", body, headers) + return self.opener.open(r).read() + except: + print "Oh god, this failed so horribly." + else: + print "You realize you need to be authenticated to change a profile image, right?" + + def encode_multipart_formdata(self, fields, files): + BOUNDARY = mimetools.choose_boundary() + CRLF = '\r\n' + L = [] + for (key, value) in fields: + L.append('--' + BOUNDARY) + L.append('Content-Disposition: form-data; name="%s"' % key) + L.append('') + L.append(value) + for (key, filename, value) in files: + L.append('--' + BOUNDARY) + L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename)) + L.append('Content-Type: %s' % self.get_content_type(filename)) + L.append('') + L.append(value) + L.append('--' + BOUNDARY + '--') + L.append('') + body = CRLF.join(L) + content_type = 'multipart/form-data; boundary=%s' % BOUNDARY + return content_type, body + + def get_content_type(self, filename): + return mimetypes.guess_type(filename)[0] or 'application/octet-stream'