refactor in ssl_verify

Conflicts:
	twython/twython.py
This commit is contained in:
jonathan vanasco 2013-03-27 12:48:12 -04:00
commit 793525535c
5 changed files with 285 additions and 289 deletions

View file

@ -100,15 +100,6 @@ print t.getProfileImageUrl('ryanmcgrath', size='bigger')
print t.getProfileImageUrl('mikehelmick') print t.getProfileImageUrl('mikehelmick')
``` ```
###### Search Twitter *(no authentication needed)*
```python
from twython import Twython
t = Twython()
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.*

View file

@ -100,14 +100,6 @@ Get a user avatar url *(no authentication needed)*
print t.getProfileImageUrl('ryanmcgrath', size='bigger') print t.getProfileImageUrl('ryanmcgrath', size='bigger')
print t.getProfileImageUrl('mikehelmick') print t.getProfileImageUrl('mikehelmick')
Search Twitter *(no authentication needed)*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
from twython import Twython
t = Twython()
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)

View file

@ -2,7 +2,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.5.5' __version__ = '2.6.0'
setup( setup(
# Basic package information. # Basic package information.
@ -14,7 +14,7 @@ setup(
include_package_data=True, include_package_data=True,
# Package dependencies. # Package dependencies.
install_requires=['simplejson', 'requests==0.14.0'], install_requires=['simplejson', 'requests>=1.0.0, <2.0.0', 'requests_oauthlib==0.3.0'],
# Metadata for PyPI. # Metadata for PyPI.
author='Ryan McGrath', author='Ryan McGrath',

View file

@ -10,50 +10,97 @@
i.e, in this case, if I pass version = 47 to any function, {{version}} will be replaced i.e, in this case, if I pass version = 47 to any function, {{version}} will be replaced
with 47, instead of defaulting to 1 (said defaulting takes place at conversion time). with 47, instead of defaulting to 1 (said defaulting takes place at conversion time).
This map is organized the order functions are documented at:
https://dev.twitter.com/docs/api/1.1
""" """
# Base Twitter API url, no need to repeat this junk... # Base Twitter API url, no need to repeat this junk...
base_url = 'http://api.twitter.com/{{version}}' base_url = 'http://api.twitter.com/{{version}}'
api_table = { api_table = {
'getRateLimitStatus': { # Timelines
'url': '/account/rate_limit_status.json', 'getMentionsTimeline': {
'method': 'GET', 'url': 'statuses/mentions_timeline',
},
'verifyCredentials': {
'url': '/account/verify_credentials.json',
'method': 'GET',
},
'endSession': {
'url': '/account/end_session.json',
'method': 'POST',
},
# Timeline methods
'getHomeTimeline': {
'url': '/statuses/home_timeline.json',
'method': 'GET', 'method': 'GET',
}, },
'getUserTimeline': { 'getUserTimeline': {
'url': '/statuses/user_timeline.json', 'url': '/statuses/user_timeline.json',
'method': 'GET', 'method': 'GET',
}, },
'getHomeTimeline': {
# Interfacing with friends/followers 'url': '/statuses/home_timeline.json',
'getUserMentions': {
'url': '/statuses/mentions.json',
'method': 'GET', 'method': 'GET',
}, },
'createFriendship': { 'retweetedOfMe': {
'url': '/friendships/create.json', 'url': '/statuses/retweets_of_me.json',
'method': 'GET',
},
# Tweets
'getRetweets': {
'url': '/statuses/retweets/{{id}}.json',
'method': 'GET',
},
'showStatus': {
'url': '/statuses/show/{{id}}.json',
'method': 'GET',
},
'destroyStatus': {
'url': '/statuses/destroy/{{id}}.json',
'method': 'POST', 'method': 'POST',
}, },
'destroyFriendship': { 'updateStatus': {
'url': '/friendships/destroy.json', 'url': '/statuses/update.json',
'method': 'POST', 'method': 'POST',
}, },
'retweet': {
'url': '/statuses/retweet/{{id}}.json',
'method': 'POST',
},
# See twython.py for update_status_with_media
'getOembedTweet': {
'url': '/statuses/oembed.json',
'method': 'GET',
},
# Search
'search': {
'url': '/search/tweets.json',
'method': 'GET',
},
# Direct Messages
'getDirectMessages': {
'url': '/direct_messages.json',
'method': 'GET',
},
'getSentMessages': {
'url': '/direct_messages/sent.json',
'method': 'GET',
},
'getDirectMessage': {
'url': '/direct_messages/show.json',
'method': 'GET',
},
'destroyDirectMessage': {
'url': '/direct_messages/destroy/{{id}}.json',
'method': 'POST',
},
'sendDirectMessage': {
'url': '/direct_messages/new.json',
'method': 'POST',
},
# Friends & Followers
'getUserIdsOfBlockedRetweets': {
'url': '/friendships/no_retweets/ids.json',
'method': 'GET',
},
'getFriendsIDs': { 'getFriendsIDs': {
'url': '/friends/ids.json', 'url': '/friends/ids.json',
'method': 'GET', 'method': 'GET',
@ -62,12 +109,8 @@ api_table = {
'url': '/followers/ids.json', 'url': '/followers/ids.json',
'method': 'GET', 'method': 'GET',
}, },
'getFriendsList': { 'lookupFriendships': {
'url': '/friends/list.json', 'url': '/friendships/lookup.json',
'method': 'GET',
},
'getFollowersList': {
'url': '/followers/list.json',
'method': 'GET', 'method': 'GET',
}, },
'getIncomingFriendshipIDs': { 'getIncomingFriendshipIDs': {
@ -78,119 +121,67 @@ api_table = {
'url': '/friendships/outgoing.json', 'url': '/friendships/outgoing.json',
'method': 'GET', 'method': 'GET',
}, },
'createFriendship': {
# Retweets 'url': '/friendships/create.json',
'reTweet': {
'url': '/statuses/retweet/{{id}}.json',
'method': 'POST', 'method': 'POST',
}, },
'getRetweets': { 'destroyFriendship': {
'url': '/statuses/retweets/{{id}}.json', 'url': '/friendships/destroy.json',
'method': 'GET',
},
'retweetedOfMe': {
'url': '/statuses/retweets_of_me.json',
'method': 'GET',
},
'retweetedByMe': {
'url': '/statuses/retweeted_by_me.json',
'method': 'GET',
},
'retweetedToMe': {
'url': '/statuses/retweeted_to_me.json',
'method': 'GET',
},
# User methods
'showUser': {
'url': '/users/show.json',
'method': 'GET',
},
'searchUsers': {
'url': '/users/search.json',
'method': 'GET',
},
'lookupUser': {
'url': '/users/lookup.json',
'method': 'GET',
},
# Status methods - showing, updating, destroying, etc.
'showStatus': {
'url': '/statuses/show.json',
'method': 'GET',
},
'updateStatus': {
'url': '/statuses/update.json',
'method': 'POST', 'method': 'POST',
}, },
'destroyStatus': { 'updateFriendship': {
'url': '/statuses/destroy/{{id}}.json', 'url': '/friendships/update.json',
'method': 'POST', 'method': 'POST',
}, },
# Direct Messages - getting, sending, effing, etc.
'getDirectMessages': {
'url': '/direct_messages.json',
'method': 'GET',
},
'getSentMessages': {
'url': '/direct_messages/sent.json',
'method': 'GET',
},
'sendDirectMessage': {
'url': '/direct_messages/new.json',
'method': 'POST',
},
'destroyDirectMessage': {
'url': '/direct_messages/destroy/{{id}}.json',
'method': 'POST',
},
# Friendship methods
'checkIfFriendshipExists': {
'url': '/friendships/exists.json',
'method': 'GET',
},
'showFriendship': { 'showFriendship': {
'url': '/friendships/show.json', 'url': '/friendships/show.json',
'method': 'GET', 'method': 'GET',
}, },
'getFriendsList': {
'url': '/friends/list.json',
'method': 'GET',
},
'getFollowersList': {
'url': '/followers/list.json',
'method': 'GET',
},
# Profile methods
# Users
'getAccountSettings': {
'url': '/account/settings.json',
'method': 'GET',
},
'verifyCredentials': {
'url': '/account/verify_credentials.json',
'method': 'GET',
},
'updateAccountSettings': {
'url': '/account/settings.json',
'method': 'POST',
},
'updateDeliveryService': {
'url': '/account/update_delivery_device.json',
'method': 'POST',
},
'updateProfile': { 'updateProfile': {
'url': '/account/update_profile.json', 'url': '/account/update_profile.json',
'method': 'POST', 'method': 'POST',
}, },
# See twython.py for update_profile_background_image
'updateProfileColors': { 'updateProfileColors': {
'url': '/account/update_profile_colors.json', 'url': '/account/update_profile_colors.json',
'method': 'POST', 'method': 'POST',
}, },
'myTotals': { # See twython.py for update_profile_image
'url': '/account/totals.json', 'listBlocks': {
'url': '/blocks/list.json',
'method': 'GET', 'method': 'GET',
}, },
'removeProfileBanner': { 'listBlockIds': {
'url': '/account/remove_profile_banner.json', 'url': '/blocks/ids.json',
'method': 'POST',
},
# Favorites methods
'getFavorites': {
'url': '/favorites.json',
'method': 'GET', 'method': 'GET',
}, },
'createFavorite': {
'url': '/favorites/create/{{id}}.json',
'method': 'POST',
},
'destroyFavorite': {
'url': '/favorites/destroy/{{id}}.json',
'method': 'POST',
},
# Blocking methods
'createBlock': { 'createBlock': {
'url': '/blocks/create/{{id}}.json', 'url': '/blocks/create/{{id}}.json',
'method': 'POST', 'method': 'POST',
@ -199,119 +190,79 @@ api_table = {
'url': '/blocks/destroy/{{id}}.json', 'url': '/blocks/destroy/{{id}}.json',
'method': 'POST', 'method': 'POST',
}, },
'getBlocking': { 'lookupUser': {
'url': '/blocks/blocking.json', 'url': '/users/lookup.json',
'method': 'GET', 'method': 'GET',
}, },
'getBlockedIDs': { 'showUser': {
'url': '/blocks/blocking/ids.json', 'url': '/users/show.json',
'method': 'GET', 'method': 'GET',
}, },
'checkIfBlockExists': { 'searchUsers': {
'url': '/blocks/exists.json', 'url': '/users/search.json',
'method': 'GET', 'method': 'GET',
}, },
'getContributees': {
# Trending methods 'url': '/users/contributees.json',
'getCurrentTrends': {
'url': '/trends/current.json',
'method': 'GET', 'method': 'GET',
}, },
'getDailyTrends': { 'getContributors': {
'url': '/trends/daily.json', 'url': '/users/contributors.json',
'method': 'GET', 'method': 'GET',
}, },
'getWeeklyTrends': { 'removeProfileBanner': {
'url': '/trends/weekly.json', 'url': '/account/remove_profile_banner.json',
'method': 'GET',
},
'availableTrends': {
'url': '/trends/available.json',
'method': 'GET',
},
'trendsByLocation': {
'url': '/trends/{{woeid}}.json',
'method': 'GET',
},
# Saved Searches
'getSavedSearches': {
'url': '/saved_searches.json',
'method': 'GET',
},
'showSavedSearch': {
'url': '/saved_searches/show/{{id}}.json',
'method': 'GET',
},
'createSavedSearch': {
'url': '/saved_searches/create.json',
'method': 'GET',
},
'destroySavedSearch': {
'url': '/saved_searches/destroy/{{id}}.json',
'method': 'GET',
},
# List API methods/endpoints. Fairly exhaustive and annoying in general. ;P
'createList': {
'url': '/lists/create.json',
'method': 'POST', 'method': 'POST',
}, },
'updateList': { # See twython.py for update_profile_banner
'url': '/lists/update.json',
# Suggested Users
'getUserSuggestionsBySlug': {
'url': '/users/suggestions/{{slug}}.json',
'method': 'GET',
},
'getUserSuggestions': {
'url': '/users/suggestions.json',
'method': 'GET',
},
'getUserSuggestionsStatusesBySlug': {
'url': '/users/suggestions/{{slug}}/members.json',
'method': 'GET',
},
# Favorites
'getFavorites': {
'url': '/favorites/list.json',
'method': 'GET',
},
'destroyFavorite': {
'url': '/favorites/destroy.json',
'method': 'POST', 'method': 'POST',
}, },
'createFavorite': {
'url': '/favorites/create.json',
'method': 'POST',
},
# Lists
'showLists': { 'showLists': {
'url': '/lists.json', 'url': '/lists/list.json',
'method': 'GET',
},
'getListMemberships': {
'url': '/lists/memberships.json',
'method': 'GET',
},
'getListSubscriptions': {
'url': '/lists/subscriptions.json',
'method': 'GET',
},
'isListSubscriber': {
'url': '/lists/subscribers/show.json',
'method': 'GET',
},
'deleteList': {
'url': '/lists/destroy.json',
'method': 'POST',
},
'getListTimeline': {
'url': '/{{username}}/lists/{{list_id}}/statuses.json',
'method': 'GET',
},
'getSpecificList': {
'url': '/lists/show.json',
'method': 'GET', 'method': 'GET',
}, },
'getListStatuses': { 'getListStatuses': {
'url': '/lists/statuses.json', 'url': '/lists/statuses.json',
'method': 'GET' 'method': 'GET'
}, },
'isListMember': {
'url': '/lists/members/show.json',
'method': 'GET',
},
'addListMember': {
'url': '/lists/members/create.json',
'method': 'POST',
},
'getListMembers': {
'url': '/lists/members.json',
'method': 'GET',
},
'deleteListMember': { 'deleteListMember': {
'url': '/lists/members/destroy.json', 'url': '/lists/members/destroy.json',
'method': 'POST', 'method': 'POST',
}, },
'deleteListMembers': { 'getListMemberships': {
'url': '/lists/members/destroy_all.json', 'url': '/lists/memberships.json',
'method': 'POST' 'method': 'GET',
}, },
'getListSubscribers': { 'getListSubscribers': {
'url': '/lists/subscribers.json', 'url': '/lists/subscribers.json',
@ -321,34 +272,121 @@ api_table = {
'url': '/lists/subscribers/create.json', 'url': '/lists/subscribers/create.json',
'method': 'POST', 'method': 'POST',
}, },
'isListSubscriber': {
'url': '/lists/subscribers/show.json',
'method': 'GET',
},
'unsubscribeFromList': { 'unsubscribeFromList': {
'url': '/lists/subscribers/destroy.json', 'url': '/lists/subscribers/destroy.json',
'method': 'POST', 'method': 'POST',
}, },
'createListMembers': {
# The one-offs 'url': '/lists/members/create_all.json',
'notificationFollow': { 'method': 'POST'
'url': '/notifications/follow/follow.json',
'method': 'POST',
}, },
'notificationLeave': { 'isListMember': {
'url': '/notifications/leave/leave.json', 'url': '/lists/members/show.json',
'method': 'POST',
},
'updateDeliveryService': {
'url': '/account/update_delivery_device.json',
'method': 'POST',
},
'reportSpam': {
'url': '/report_spam.json',
'method': 'POST',
},
'getOembedTweet': {
'url': '/statuses/oembed.json',
'method': 'GET', 'method': 'GET',
}, },
'getListMembers': {
'url': '/lists/members.json',
'method': 'GET',
},
'addListMember': {
'url': '/lists/members/create.json',
'method': 'POST',
},
'deleteList': {
'url': '/lists/destroy.json',
'method': 'POST',
},
'updateList': {
'url': '/lists/update.json',
'method': 'POST',
},
'createList': {
'url': '/lists/create.json',
'method': 'POST',
},
'getSpecificList': {
'url': '/lists/show.json',
'method': 'GET',
},
'getListSubscriptions': {
'url': '/lists/subscriptions.json',
'method': 'GET',
},
'deleteListMembers': {
'url': '/lists/members/destroy_all.json',
'method': 'POST'
},
# Saved Searches
'getSavedSearches': {
'url': '/saved_searches/list.json',
'method': 'GET',
},
'showSavedSearch': {
'url': '/saved_searches/show/{{id}}.json',
'method': 'GET',
},
'createSavedSearch': {
'url': '/saved_searches/create.json',
'method': 'POST',
},
'destroySavedSearch': {
'url': '/saved_searches/destroy/{{id}}.json',
'method': 'POST',
},
# Places & Geo
'getGeoInfo': {
'url': '/geo/id/{{place_id}}.json',
'method': 'GET',
},
'reverseGeocode': {
'url': '/geo/reverse_geocode.json',
'method': 'GET',
},
'searchGeo': {
'url': '/geo/search.json',
'method': 'GET',
},
'getSimilarPlaces': {
'url': '/geo/similar_places.json',
'method': 'GET',
},
'createPlace': {
'url': '/geo/place.json',
'method': 'POST',
},
# Trends
'getPlaceTrends': {
'url': '/trends/place.json',
'method': 'GET',
},
'getAvailableTrends': {
'url': '/trends/available.json',
'method': 'GET',
},
'getClosestTrends': {
'url': '/trends/closest.json',
'method': 'GET',
},
# Spam Reporting
'reportSpam': {
'url': '/users/report_spam.json',
'method': 'POST',
},
} }
# from https://dev.twitter.com/docs/error-codes-responses # from https://dev.twitter.com/docs/error-codes-responses
twitter_http_status_codes = { twitter_http_status_codes = {
200: ('OK', 'Success!'), 200: ('OK', 'Success!'),

View file

@ -7,14 +7,14 @@
""" """
__author__ = "Ryan McGrath <ryan@venodesigns.net>" __author__ = "Ryan McGrath <ryan@venodesigns.net>"
__version__ = "2.5.5" __version__ = "2.6.0"
import urllib import urllib
import re import re
import warnings import warnings
import requests import requests
from requests.auth import OAuth1 from requests_oauthlib import OAuth1
try: try:
from urlparse import parse_qsl from urlparse import parse_qsl
@ -82,7 +82,11 @@ class TwythonRateLimitError(TwythonError):
class Twython(object): class Twython(object):
def __init__(self, app_key=None, app_secret=None, oauth_token=None, oauth_token_secret=None, \ def __init__(self, app_key=None, app_secret=None, oauth_token=None, oauth_token_secret=None, \
<<<<<<< HEAD
headers=None, callback_url=None, twitter_token=None, twitter_secret=None, proxies=None, version='1' , ssl_verify=True ): headers=None, callback_url=None, twitter_token=None, twitter_secret=None, proxies=None, version='1' , ssl_verify=True ):
=======
headers=None, callback_url=None, twitter_token=None, twitter_secret=None, proxies=None, version='1.1'):
>>>>>>> d6f3d731a2a89a0add5b01b918cf61cf93f97d62
"""Instantiates an instance of Twython. Takes optional parameters for authentication and such (see below). """Instantiates an instance of Twython. Takes optional parameters for authentication and such (see below).
:param app_key: (optional) Your applications key :param app_key: (optional) Your applications key
@ -117,7 +121,8 @@ class Twython(object):
self.headers = headers or {'User-Agent': 'Twython v' + __version__} self.headers = headers or {'User-Agent': 'Twython v' + __version__}
# Allow for unauthenticated requests # Allow for unauthenticated requests
self.client = requests.session(proxies=proxies) self.client = requests.Session()
self.client.proxies = proxies
self.auth = None self.auth = None
if self.app_key is not None and self.app_secret is not None and \ if self.app_key is not None and self.app_secret is not None and \
@ -132,7 +137,10 @@ class Twython(object):
signature_type='auth_header') signature_type='auth_header')
if self.auth is not None: if self.auth is not None:
self.client = requests.session(headers=self.headers, auth=self.auth, proxies=proxies) self.client = requests.Session()
self.client.headers = self.headers
self.client.auth = self.auth
self.client.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):
@ -183,7 +191,6 @@ class Twython(object):
'api_call': api_call, 'api_call': api_call,
'api_error': None, 'api_error': None,
'cookies': response.cookies, 'cookies': response.cookies,
'error': response.error,
'headers': response.headers, 'headers': response.headers,
'status_code': response.status_code, 'status_code': response.status_code,
'url': response.url, 'url': response.url,
@ -205,7 +212,8 @@ class Twython(object):
'error', 'An error occurred processing your request.') 'error', 'An error occurred processing your request.')
self._last_call['api_error'] = error_msg self._last_call['api_error'] = error_msg
exceptionType = TwythonRateLimitError if response.status_code == 420 else TwythonError #Twitter API 1.1 , always return 429 when rate limit is exceeded
exceptionType = TwythonRateLimitError if response.status_code == 429 else TwythonError
raise exceptionType(error_msg, raise exceptionType(error_msg,
error_code=response.status_code, error_code=response.status_code,
@ -261,7 +269,7 @@ class Twython(object):
raise TwythonError('This function must be called after an API call. It delivers header information.') raise TwythonError('This function must be called after an API call. It delivers header information.')
if header in self._last_call['headers']: if header in self._last_call['headers']:
return self._last_call['headers'][header] return self._last_call['headers'][header]
return None return self._last_call
def get_authentication_tokens(self): def get_authentication_tokens(self):
"""Returns an authorization URL for a user to hit. """Returns an authorization URL for a user to hit.
@ -335,39 +343,6 @@ class Twython(object):
def constructApiURL(base_url, params): def constructApiURL(base_url, params):
return base_url + "?" + "&".join(["%s=%s" % (Twython.unicode2utf8(key), urllib.quote_plus(Twython.unicode2utf8(value))) for (key, value) in params.iteritems()]) return base_url + "?" + "&".join(["%s=%s" % (Twython.unicode2utf8(key), urllib.quote_plus(Twython.unicode2utf8(value))) for (key, value) in params.iteritems()])
def search(self, **kwargs):
""" Returns tweets that match a specified query.
Documentation: https://dev.twitter.com/doc/get/search
:param q: (required) The query you want to search Twitter for
:param geocode: (optional) Returns tweets by users located within
a given radius of the given latitude/longitude.
The parameter value is specified by
"latitude,longitude,radius", where radius units
must be specified as either "mi" (miles) or
"km" (kilometers).
Example Values: 37.781157,-122.398720,1mi
:param lang: (optional) Restricts tweets to the given language,
given by an ISO 639-1 code.
:param locale: (optional) Specify the language of the query you
are sending. Only ``ja`` is currently effective.
:param page: (optional) The page number (starting at 1) to return
Max ~1500 results
:param result_type: (optional) Default ``mixed``
mixed: Include both popular and real time
results in the response.
recent: return only the most recent results in
the response
popular: return only the most popular results
in the response.
e.g x.search(q='jjndf', page='2')
"""
return self.get('https://api.twitter.com/1.1/search/tweets.json', params=kwargs)
def searchGen(self, search_query, **kwargs): def searchGen(self, search_query, **kwargs):
""" Returns a generator of tweets that match a specified query. """ Returns a generator of tweets that match a specified query.
@ -380,7 +355,7 @@ class Twython(object):
print result print result
""" """
kwargs['q'] = search_query kwargs['q'] = search_query
content = self.get('https://api.twitter.com/1.1/search/tweets.json', params=kwargs) content = self.search(q=search_query, **kwargs)
if not content['results']: if not content['results']:
raise StopIteration raise StopIteration