Uploading profile image and profile background image, update setup required packages, removed some funcs.
* You can now update user profile image or user profile background image thanks to the Python requests library. * Updated setup to include 'requests' as a required package * Changed to beginning hashbang to use the users environment python version * try/except for parse_qsl, removed try/excepts where it used cgi.parse_qsl/urlparse.parse_sql * Lines 161/162 (using self.consumer/token) <- this addition ended up not being needed, but it doesn't hurt. * updateProfileBackgroundImage() - param 'tile' is now True/False rather than a string "true" or string "false" * removed encode_multipart_formdata func, not needed any longer
This commit is contained in:
parent
fa1b581c0f
commit
e54183df9c
2 changed files with 64 additions and 64 deletions
2
setup.py
2
setup.py
|
|
@ -17,7 +17,7 @@ setup(
|
||||||
include_package_data = True,
|
include_package_data = True,
|
||||||
|
|
||||||
# Package dependencies.
|
# Package dependencies.
|
||||||
install_requires = ['simplejson', 'oauth2', 'httplib2'],
|
install_requires = ['simplejson', 'oauth2', 'httplib2', 'requests'],
|
||||||
|
|
||||||
# Metadata for PyPI.
|
# Metadata for PyPI.
|
||||||
author = 'Ryan McGrath',
|
author = 'Ryan McGrath',
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/env
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Twython is a library for Python that wraps the Twitter API.
|
Twython is a library for Python that wraps the Twitter API.
|
||||||
|
|
@ -21,9 +21,16 @@ import mimetypes
|
||||||
import mimetools
|
import mimetools
|
||||||
import re
|
import re
|
||||||
import inspect
|
import inspect
|
||||||
|
import time
|
||||||
|
|
||||||
|
import requests
|
||||||
import oauth2 as oauth
|
import oauth2 as oauth
|
||||||
|
|
||||||
|
try:
|
||||||
|
from urlparse import parse_qsl
|
||||||
|
except ImportError:
|
||||||
|
from cgi import parse_qsl
|
||||||
|
|
||||||
# Twython maps keyword based arguments to Twitter API endpoints. The endpoints
|
# Twython maps keyword based arguments to Twitter API endpoints. The endpoints
|
||||||
# table is a file with a dictionary of every API endpoint that Twython supports.
|
# table is a file with a dictionary of every API endpoint that Twython supports.
|
||||||
from twitter_endpoints import base_url, api_table
|
from twitter_endpoints import base_url, api_table
|
||||||
|
|
@ -151,20 +158,20 @@ class Twython(object):
|
||||||
if self.headers is None:
|
if self.headers is None:
|
||||||
self.headers = {'User-agent': 'Twython Python Twitter Library v1.3'}
|
self.headers = {'User-agent': 'Twython Python Twitter Library v1.3'}
|
||||||
|
|
||||||
consumer = None
|
self.consumer = None
|
||||||
token = None
|
self.token = None
|
||||||
|
|
||||||
if self.twitter_token is not None and self.twitter_secret is not None:
|
if self.twitter_token is not None and self.twitter_secret is not None:
|
||||||
consumer = oauth.Consumer(self.twitter_token, self.twitter_secret)
|
self.consumer = oauth.Consumer(self.twitter_token, self.twitter_secret)
|
||||||
|
|
||||||
if self.oauth_token is not None and self.oauth_secret is not None:
|
if self.oauth_token is not None and self.oauth_secret is not None:
|
||||||
token = oauth.Token(oauth_token, oauth_token_secret)
|
self.token = oauth.Token(oauth_token, oauth_token_secret)
|
||||||
|
|
||||||
# Filter down through the possibilities here - if they have a token, if they're first stage, etc.
|
# Filter down through the possibilities here - if they have a token, if they're first stage, etc.
|
||||||
if consumer is not None and token is not None:
|
if self.consumer is not None and self.token is not None:
|
||||||
self.client = oauth.Client(consumer, token, **client_args)
|
self.client = oauth.Client(self.consumer, self.token, **client_args)
|
||||||
elif consumer is not None:
|
elif self.consumer is not None:
|
||||||
self.client = oauth.Client(consumer, **client_args)
|
self.client = oauth.Client(self.consumer, **client_args)
|
||||||
else:
|
else:
|
||||||
# If they don't do authentication, but still want to request unprotected resources, we need an opener.
|
# If they don't do authentication, but still want to request unprotected resources, we need an opener.
|
||||||
self.client = httplib2.Http(**client_args)
|
self.client = httplib2.Http(**client_args)
|
||||||
|
|
@ -225,10 +232,7 @@ class Twython(object):
|
||||||
if resp['status'] != '200':
|
if resp['status'] != '200':
|
||||||
raise AuthError("Seems something couldn't be verified with your OAuth junk. Error: %s, Message: %s" % (resp['status'], content))
|
raise AuthError("Seems something couldn't be verified with your OAuth junk. Error: %s, Message: %s" % (resp['status'], content))
|
||||||
|
|
||||||
try:
|
request_tokens = dict(parse_qsl(content))
|
||||||
request_tokens = dict(urlparse.parse_qsl(content))
|
|
||||||
except:
|
|
||||||
request_tokens = dict(cgi.parse_qsl(content))
|
|
||||||
|
|
||||||
oauth_callback_confirmed = request_tokens.get('oauth_callback_confirmed')=='true'
|
oauth_callback_confirmed = request_tokens.get('oauth_callback_confirmed')=='true'
|
||||||
|
|
||||||
|
|
@ -256,10 +260,7 @@ class Twython(object):
|
||||||
Returns authorized tokens after they go through the auth_url phase.
|
Returns authorized tokens after they go through the auth_url phase.
|
||||||
"""
|
"""
|
||||||
resp, content = self.client.request(self.access_token_url, "GET")
|
resp, content = self.client.request(self.access_token_url, "GET")
|
||||||
try:
|
return dict(parse_qsl(content))
|
||||||
return dict(urlparse.parse_qsl(content))
|
|
||||||
except:
|
|
||||||
return dict(cgi.parse_qsl(content))
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------------------------------------------------
|
||||||
# The following methods are all different in some manner or require special attention with regards to the Twitter API.
|
# The following methods are all different in some manner or require special attention with regards to the Twitter API.
|
||||||
|
|
@ -421,26 +422,36 @@ class Twython(object):
|
||||||
raise TwythonError("isListMember() failed with a %d error code." % e.code, e.code)
|
raise TwythonError("isListMember() failed with a %d error code." % e.code, e.code)
|
||||||
|
|
||||||
# The following methods are apart from the other Account methods, because they rely on a whole multipart-data posting function set.
|
# 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", version = 1):
|
def updateProfileBackgroundImage(self, filename, tile=True, version = 1):
|
||||||
""" updateProfileBackgroundImage(filename, tile="true")
|
""" updateProfileBackgroundImage(filename, tile=True)
|
||||||
|
|
||||||
Updates the authenticating user's profile background image.
|
Updates the authenticating user's profile background image.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
image - Required. Must be a valid GIF, JPG, or PNG image of less than 800 kilobytes in size. Images with width larger than 2048 pixels will be forceably scaled down.
|
image - Required. Must be a valid GIF, JPG, or PNG image of less than 800 kilobytes in size. Images with width larger than 2048 pixels will be forceably scaled down.
|
||||||
tile - Optional (defaults to true). If set to true the background image will be displayed tiled. The image will not be tiled otherwise.
|
tile - Optional (defaults to True). If set to true the background image will be displayed tiled. The image will not be tiled otherwise.
|
||||||
** Note: It's sad, but when using this method, pass the tile value as a string, e.g tile="false"
|
|
||||||
version (number) - Optional. API version to request. Entire Twython class defaults to 1, but you can override on a function-by-function or class basis - (version=2), etc.
|
version (number) - Optional. API version to request. Entire Twython class defaults to 1, but you can override on a function-by-function or class basis - (version=2), etc.
|
||||||
"""
|
"""
|
||||||
try:
|
upload_url = 'http://api.twitter.com/%d/account/update_profile_background_image.json' % version
|
||||||
files = [("image", filename, open(filename, 'rb').read())]
|
params = {
|
||||||
fields = []
|
'oauth_version': "1.0",
|
||||||
content_type, body = Twython.encode_multipart_formdata(fields, files)
|
'oauth_nonce': oauth.generate_nonce(length=41),
|
||||||
headers = {'Content-Type': content_type, 'Content-Length': str(len(body))}
|
'oauth_timestamp': int(time.time()),
|
||||||
r = urllib2.Request("http://api.twitter.com/%d/account/update_profile_background_image.json?tile=%s" % (version, tile), body, headers)
|
}
|
||||||
return urllib2.urlopen(r).read()
|
|
||||||
except HTTPError, e:
|
#create a fake request with your upload url and parameters
|
||||||
raise TwythonError("updateProfileBackgroundImage() failed with a %d error code." % e.code, e.code)
|
faux_req = oauth.Request(method='POST', url=upload_url, parameters=params)
|
||||||
|
|
||||||
|
#sign the fake request.
|
||||||
|
signature_method = oauth.SignatureMethod_HMAC_SHA1()
|
||||||
|
faux_req.sign_request(signature_method, self.consumer, self.token)
|
||||||
|
|
||||||
|
#create a dict out of the fake request signed params
|
||||||
|
params = dict(parse_qsl(faux_req.to_postdata()))
|
||||||
|
self.headers.update(faux_req.to_header())
|
||||||
|
|
||||||
|
req = requests.post(upload_url, data={'tile':tile}, files={'image':(filename, open(filename, 'rb'))}, headers=self.headers)
|
||||||
|
return req.content
|
||||||
|
|
||||||
def updateProfileImage(self, filename, version = 1):
|
def updateProfileImage(self, filename, version = 1):
|
||||||
""" updateProfileImage(filename)
|
""" updateProfileImage(filename)
|
||||||
|
|
@ -451,15 +462,26 @@ class Twython(object):
|
||||||
image - Required. Must be a valid GIF, JPG, or PNG image of less than 700 kilobytes in size. Images with width larger than 500 pixels will be scaled down.
|
image - Required. Must be a valid GIF, JPG, or PNG image of less than 700 kilobytes in size. Images with width larger than 500 pixels will be scaled down.
|
||||||
version (number) - Optional. API version to request. Entire Twython class defaults to 1, but you can override on a function-by-function or class basis - (version=2), etc.
|
version (number) - Optional. API version to request. Entire Twython class defaults to 1, but you can override on a function-by-function or class basis - (version=2), etc.
|
||||||
"""
|
"""
|
||||||
try:
|
upload_url = 'http://api.twitter.com/%d/account/update_profile_image.json' % version
|
||||||
files = [("image", filename, open(filename, 'rb').read())]
|
params = {
|
||||||
fields = []
|
'oauth_version': "1.0",
|
||||||
content_type, body = Twython.encode_multipart_formdata(fields, files)
|
'oauth_nonce': oauth.generate_nonce(length=41),
|
||||||
headers = {'Content-Type': content_type, 'Content-Length': str(len(body))}
|
'oauth_timestamp': int(time.time()),
|
||||||
r = urllib2.Request("http://api.twitter.com/%d/account/update_profile_image.json" % version, body, headers)
|
}
|
||||||
return urllib2.urlopen(r).read()
|
|
||||||
except HTTPError, e:
|
#create a fake request with your upload url and parameters
|
||||||
raise TwythonError("updateProfileImage() failed with a %d error code." % e.code, e.code)
|
faux_req = oauth.Request(method='POST', url=upload_url, parameters=params)
|
||||||
|
|
||||||
|
#sign the fake request.
|
||||||
|
signature_method = oauth.SignatureMethod_HMAC_SHA1()
|
||||||
|
faux_req.sign_request(signature_method, self.consumer, self.token)
|
||||||
|
|
||||||
|
#create a dict out of the fake request signed params
|
||||||
|
params = dict(parse_qsl(faux_req.to_postdata()))
|
||||||
|
self.headers.update(faux_req.to_header())
|
||||||
|
|
||||||
|
req = requests.post(upload_url, files={'image':(filename, open(filename, 'rb'))}, headers=self.headers)
|
||||||
|
return req.content
|
||||||
|
|
||||||
def getProfileImageUrl(self, username, size=None, version=1):
|
def getProfileImageUrl(self, username, size=None, version=1):
|
||||||
""" getProfileImageUrl(username)
|
""" getProfileImageUrl(username)
|
||||||
|
|
@ -485,29 +507,7 @@ class Twython(object):
|
||||||
return simplejson.loads(content.decode('utf-8'))
|
return simplejson.loads(content.decode('utf-8'))
|
||||||
|
|
||||||
raise TwythonError("getProfileImageUrl() failed with a %d error code." % resp.status, resp.status)
|
raise TwythonError("getProfileImageUrl() failed with a %d error code." % resp.status, resp.status)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def encode_multipart_formdata(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' % mimetypes.guess_type(filename)[0] or 'application/octet-stream')
|
|
||||||
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
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def unicode2utf8(text):
|
def unicode2utf8(text):
|
||||||
try:
|
try:
|
||||||
|
|
@ -521,4 +521,4 @@ class Twython(object):
|
||||||
def encode(text):
|
def encode(text):
|
||||||
if isinstance(text, (str,unicode)):
|
if isinstance(text, (str,unicode)):
|
||||||
return Twython.unicode2utf8(text)
|
return Twython.unicode2utf8(text)
|
||||||
return str(text)
|
return str(text)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue