2.3.2, latest @michaelhelmick fixes
This commit is contained in:
commit
0bcc15ecf3
3 changed files with 35 additions and 62 deletions
14
README.md
14
README.md
|
|
@ -11,7 +11,7 @@ Features
|
||||||
- Twitter lists
|
- Twitter lists
|
||||||
- Timelines
|
- Timelines
|
||||||
- User avatar URL
|
- User avatar URL
|
||||||
- and anything found in `the docs <https://dev.twitter.com/docs/api>`_
|
- and anything found in [the docs](https://dev.twitter.com/docs/api)
|
||||||
* Image Uploading!
|
* Image Uploading!
|
||||||
- **Update user status with an image**
|
- **Update user status with an image**
|
||||||
- Change user avatar
|
- Change user avatar
|
||||||
|
|
@ -31,7 +31,7 @@ Installation
|
||||||
Usage
|
Usage
|
||||||
-----
|
-----
|
||||||
|
|
||||||
Authorization URL
|
###### Authorization URL
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from twython import Twython
|
from twython import Twython
|
||||||
|
|
@ -50,7 +50,7 @@ print 'Connect to Twitter via: %s' % auth_props['auth_url']
|
||||||
|
|
||||||
Be sure you have a URL set up to handle the callback after the user has allowed your app to access their data, the callback can be used for storing their final OAuth Token and OAuth Token Secret in a database for use at a later date.
|
Be sure you have a URL set up to handle the callback after the user has allowed your app to access their data, the callback can be used for storing their final OAuth Token and OAuth Token Secret in a database for use at a later date.
|
||||||
|
|
||||||
Handling the callback
|
###### Handling the callback
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from twython import Twython
|
from twython import Twython
|
||||||
|
|
@ -71,7 +71,7 @@ print auth_tokens
|
||||||
|
|
||||||
*Function definitions (i.e. getHomeTimeline()) can be found by reading over twython/twitter_endpoints.py*
|
*Function definitions (i.e. getHomeTimeline()) can be found by reading over twython/twitter_endpoints.py*
|
||||||
|
|
||||||
Getting a user home timeline
|
###### Getting a user home timeline
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from twython import Twython
|
from twython import Twython
|
||||||
|
|
@ -90,7 +90,7 @@ t = Twython(app_key=app_key,
|
||||||
print t.getHomeTimeline()
|
print t.getHomeTimeline()
|
||||||
```
|
```
|
||||||
|
|
||||||
Get a user avatar url *(no authentication needed)*
|
###### Get a user avatar url *(no authentication needed)*
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from twython import Twython
|
from twython import Twython
|
||||||
|
|
@ -100,7 +100,7 @@ print t.getProfileImageUrl('ryanmcgrath', size='bigger')
|
||||||
print t.getProfileImageUrl('mikehelmick')
|
print t.getProfileImageUrl('mikehelmick')
|
||||||
```
|
```
|
||||||
|
|
||||||
Search Twitter *(no authentication needed)*
|
###### Search Twitter *(no authentication needed)*
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from twython import Twython
|
from twython import Twython
|
||||||
|
|
@ -109,7 +109,7 @@ t = Twython()
|
||||||
print t.search(q='python')
|
print t.search(q='python')
|
||||||
```
|
```
|
||||||
|
|
||||||
Streaming API
|
###### Streaming API
|
||||||
*Usage is as follows; it's designed to be open-ended enough that you can adapt it to higher-level (read: Twitter must give you access)
|
*Usage is as follows; it's designed to be open-ended enough that you can adapt it to higher-level (read: Twitter must give you access)
|
||||||
streams.*
|
streams.*
|
||||||
|
|
||||||
|
|
|
||||||
4
setup.py
4
setup.py
|
|
@ -4,7 +4,7 @@ from setuptools import setup
|
||||||
from setuptools import find_packages
|
from setuptools import find_packages
|
||||||
|
|
||||||
__author__ = 'Ryan McGrath <ryan@venodesigns.net>'
|
__author__ = 'Ryan McGrath <ryan@venodesigns.net>'
|
||||||
__version__ = '2.3.1'
|
__version__ = '2.3.2'
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
# Basic package information.
|
# Basic package information.
|
||||||
|
|
@ -16,7 +16,7 @@ setup(
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
|
|
||||||
# Package dependencies.
|
# Package dependencies.
|
||||||
install_requires=['simplejson', 'requests>=0.13.0'],
|
install_requires=['simplejson', 'requests>=0.13.2'],
|
||||||
|
|
||||||
# Metadata for PyPI.
|
# Metadata for PyPI.
|
||||||
author='Ryan McGrath',
|
author='Ryan McGrath',
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__author__ = "Ryan McGrath <ryan@venodesigns.net>"
|
__author__ = "Ryan McGrath <ryan@venodesigns.net>"
|
||||||
__version__ = "2.3.1"
|
__version__ = "2.3.2"
|
||||||
|
|
||||||
import urllib
|
import urllib
|
||||||
import re
|
import re
|
||||||
|
|
@ -27,12 +27,7 @@ except ImportError:
|
||||||
# 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, twitter_http_status_codes
|
from twitter_endpoints import base_url, api_table, twitter_http_status_codes
|
||||||
|
|
||||||
|
|
||||||
# There are some special setups (like, oh, a Django application) where
|
|
||||||
# simplejson exists behind the scenes anyway. Past Python 2.6, this should
|
|
||||||
# never really cause any problems to begin with.
|
|
||||||
try:
|
try:
|
||||||
# If they have the library, chances are they're gonna want to use that.
|
|
||||||
import simplejson
|
import simplejson
|
||||||
except ImportError:
|
except ImportError:
|
||||||
try:
|
try:
|
||||||
|
|
@ -40,7 +35,6 @@ except ImportError:
|
||||||
import json as simplejson
|
import json as simplejson
|
||||||
except ImportError:
|
except ImportError:
|
||||||
try:
|
try:
|
||||||
# This case gets rarer by the day, but if we need to, we can pull it from Django provided it's there.
|
|
||||||
from django.utils import simplejson
|
from django.utils import simplejson
|
||||||
except:
|
except:
|
||||||
# Seriously wtf is wrong with you if you get this Exception.
|
# Seriously wtf is wrong with you if you get this Exception.
|
||||||
|
|
@ -110,45 +104,34 @@ class Twython(object):
|
||||||
self.authenticate_url = self.api_url % 'oauth/authenticate'
|
self.authenticate_url = self.api_url % 'oauth/authenticate'
|
||||||
|
|
||||||
# Enforce unicode on keys and secrets
|
# Enforce unicode on keys and secrets
|
||||||
self.app_key = None
|
self.app_key = app_key and unicode(app_key) or twitter_token and unicode(twitter_token)
|
||||||
if app_key is not None or twitter_token is not None:
|
self.app_secret = app_key and unicode(app_secret) or twitter_secret and unicode(twitter_secret)
|
||||||
self.app_key = u'%s' % (app_key or twitter_token)
|
|
||||||
|
|
||||||
self.app_secret = None
|
self.oauth_token = oauth_token and u'%s' % oauth_token
|
||||||
if app_secret is not None or twitter_secret is not None:
|
self.oauth_token_secret = oauth_token_secret and u'%s' % oauth_token_secret
|
||||||
self.app_secret = u'%s' % (app_secret or twitter_secret)
|
|
||||||
|
|
||||||
self.oauth_token = None
|
|
||||||
if oauth_token is not None:
|
|
||||||
self.oauth_token = u'%s' % oauth_token
|
|
||||||
|
|
||||||
self.oauth_token_secret = None
|
|
||||||
if oauth_token_secret is not None:
|
|
||||||
self.oauth_token_secret = u'%s' % oauth_token_secret
|
|
||||||
|
|
||||||
self.callback_url = callback_url
|
self.callback_url = callback_url
|
||||||
|
|
||||||
# If there's headers, set them, otherwise be an embarassing parent for their own good.
|
# If there's headers, set them, otherwise be an embarassing parent for their own good.
|
||||||
self.headers = headers
|
self.headers = headers or {'User-Agent': 'Twython v' + __version__}
|
||||||
if self.headers is None:
|
|
||||||
self.headers = {'User-agent': 'Twython Python Twitter Library v' + __version__}
|
|
||||||
|
|
||||||
self.client = None
|
# Allow for unauthenticated requests
|
||||||
|
self.client = requests.session(proxies=proxies)
|
||||||
self.auth = None
|
self.auth = None
|
||||||
|
|
||||||
if self.app_key is not None and self.app_secret is not None:
|
if self.app_key is not None and self.app_secret is not None and \
|
||||||
|
self.oauth_token is None and self.oauth_token_secret is None:
|
||||||
self.auth = OAuth1(self.app_key, self.app_secret,
|
self.auth = OAuth1(self.app_key, self.app_secret,
|
||||||
signature_type='auth_header')
|
signature_type='auth_header')
|
||||||
|
|
||||||
if self.oauth_token is not None and self.oauth_token_secret is not None:
|
if self.app_key is not None and self.app_secret is not None and \
|
||||||
|
self.oauth_token is not None and self.oauth_token_secret is not None:
|
||||||
self.auth = OAuth1(self.app_key, self.app_secret,
|
self.auth = OAuth1(self.app_key, self.app_secret,
|
||||||
self.oauth_token, self.oauth_token_secret,
|
self.oauth_token, self.oauth_token_secret,
|
||||||
signature_type='auth_header')
|
signature_type='auth_header')
|
||||||
|
|
||||||
if self.client is None:
|
if self.auth is not None:
|
||||||
# If they don't do authentication, but still want to request
|
self.client = requests.session(headers=self.headers, auth=self.auth, proxies=proxies)
|
||||||
# unprotected resources, we need an opener.
|
|
||||||
self.client = requests.session(proxies=proxies)
|
|
||||||
|
|
||||||
# register available funcs to allow listing name when debugging.
|
# register available funcs to allow listing name when debugging.
|
||||||
def setFunc(key):
|
def setFunc(key):
|
||||||
|
|
@ -169,11 +152,7 @@ class Twython(object):
|
||||||
base_url + fn['url']
|
base_url + fn['url']
|
||||||
)
|
)
|
||||||
|
|
||||||
method = fn['method'].lower()
|
content = self._request(url, method=fn['method'], params=kwargs)
|
||||||
if not method in ('get', 'post'):
|
|
||||||
raise TwythonError('Method must be of GET or POST')
|
|
||||||
|
|
||||||
content = self._request(url, method=method, params=kwargs)
|
|
||||||
|
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
|
@ -181,18 +160,19 @@ class Twython(object):
|
||||||
'''Internal response generator, no sense in repeating the same
|
'''Internal response generator, no sense in repeating the same
|
||||||
code twice, right? ;)
|
code twice, right? ;)
|
||||||
'''
|
'''
|
||||||
myargs = {}
|
|
||||||
method = method.lower()
|
method = method.lower()
|
||||||
|
if not method in ('get', 'post'):
|
||||||
|
raise TwythonError('Method must be of GET or POST')
|
||||||
|
|
||||||
params = params or {}
|
params = params or {}
|
||||||
|
|
||||||
if method == 'get':
|
|
||||||
url = '%s?%s' % (url, urllib.urlencode(params))
|
|
||||||
else:
|
|
||||||
myargs = params
|
|
||||||
|
|
||||||
func = getattr(self.client, method)
|
func = getattr(self.client, method)
|
||||||
response = func(url, data=myargs, files=files, headers=self.headers, auth=self.auth)
|
if method == 'get':
|
||||||
|
# Still wasn't fixed in `requests` 0.13.2? :(
|
||||||
|
url = url + '?' + urllib.urlencode(params)
|
||||||
|
response = func(url)
|
||||||
|
else:
|
||||||
|
response = func(url, data=params, files=files)
|
||||||
content = response.content.decode('utf-8')
|
content = response.content.decode('utf-8')
|
||||||
|
|
||||||
# create stash for last function intel
|
# create stash for last function intel
|
||||||
|
|
@ -207,10 +187,6 @@ class Twython(object):
|
||||||
'content': content,
|
'content': content,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Python 2.6 `json` will throw a ValueError if it
|
|
||||||
# can't load the string as valid JSON,
|
|
||||||
# `simplejson` will throw simplejson.decoder.JSONDecodeError
|
|
||||||
# But excepting just ValueError will work with both. o.O
|
|
||||||
try:
|
try:
|
||||||
content = simplejson.loads(content)
|
content = simplejson.loads(content)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
|
@ -287,7 +263,7 @@ class Twython(object):
|
||||||
request_args['oauth_callback'] = self.callback_url
|
request_args['oauth_callback'] = self.callback_url
|
||||||
|
|
||||||
req_url = self.request_token_url + '?' + urllib.urlencode(request_args)
|
req_url = self.request_token_url + '?' + urllib.urlencode(request_args)
|
||||||
response = self.client.get(req_url, headers=self.headers, auth=self.auth)
|
response = self.client.get(req_url)
|
||||||
|
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
raise TwythonAuthError("Seems something couldn't be verified with your OAuth junk. Error: %s, Message: %s" % (response.status_code, response.content))
|
raise TwythonAuthError("Seems something couldn't be verified with your OAuth junk. Error: %s, Message: %s" % (response.status_code, response.content))
|
||||||
|
|
@ -313,7 +289,7 @@ class Twython(object):
|
||||||
def get_authorized_tokens(self):
|
def get_authorized_tokens(self):
|
||||||
"""Returns authorized tokens after they go through the auth_url phase.
|
"""Returns authorized tokens after they go through the auth_url phase.
|
||||||
"""
|
"""
|
||||||
response = self.client.get(self.access_token_url, headers=self.headers, auth=self.auth)
|
response = self.client.get(self.access_token_url)
|
||||||
authorized_tokens = dict(parse_qsl(response.content))
|
authorized_tokens = dict(parse_qsl(response.content))
|
||||||
if not authorized_tokens:
|
if not authorized_tokens:
|
||||||
raise TwythonError('Unable to decode authorized tokens.')
|
raise TwythonError('Unable to decode authorized tokens.')
|
||||||
|
|
@ -382,8 +358,6 @@ class Twython(object):
|
||||||
|
|
||||||
e.g x.search(q='jjndf', page='2')
|
e.g x.search(q='jjndf', page='2')
|
||||||
"""
|
"""
|
||||||
if 'q' in kwargs:
|
|
||||||
kwargs['q'] = urllib.quote_plus(Twython.unicode2utf8(kwargs['q'], ':'))
|
|
||||||
|
|
||||||
return self.get('https://search.twitter.com/search.json', params=kwargs)
|
return self.get('https://search.twitter.com/search.json', params=kwargs)
|
||||||
|
|
||||||
|
|
@ -398,7 +372,7 @@ class Twython(object):
|
||||||
for result in search:
|
for result in search:
|
||||||
print result
|
print result
|
||||||
"""
|
"""
|
||||||
kwargs['q'] = urllib.quote_plus(Twython.unicode2utf8(search_query))
|
kwargs['q'] = search_query
|
||||||
content = self.get('https://search.twitter.com/search.json', params=kwargs)
|
content = self.get('https://search.twitter.com/search.json', params=kwargs)
|
||||||
|
|
||||||
if not content['results']:
|
if not content['results']:
|
||||||
|
|
@ -458,7 +432,6 @@ class Twython(object):
|
||||||
return self._media_update(url,
|
return self._media_update(url,
|
||||||
{'image': (file_, open(file_, 'rb'))})
|
{'image': (file_, open(file_, 'rb'))})
|
||||||
|
|
||||||
# statuses/update_with_media
|
|
||||||
def updateStatusWithMedia(self, file_, version=1, **params):
|
def updateStatusWithMedia(self, file_, version=1, **params):
|
||||||
"""Updates the users status with media
|
"""Updates the users status with media
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue