From a172136f3edf9c6b085d8a350788767da0dd098b Mon Sep 17 00:00:00 2001 From: Mike Helmick Date: Tue, 19 Mar 2013 15:40:40 -0400 Subject: [PATCH] Update Twitter Endpoints & Internal Functions * Twitter Endpoints are now in the order of https://dev.twitter.com/docs/api/1.1 * No need to repeat search function internally when it is available via `twitter_endpoints.py` * Make `searchGen` use self.search, instead of self.get with the full search url --- README.md | 9 - README.rst | 8 - setup.py | 2 +- twython/twitter_endpoints.py | 496 +++++++++++++++++++---------------- twython/twython.py | 37 +-- 5 files changed, 270 insertions(+), 282 deletions(-) diff --git a/README.md b/README.md index 31c3cc7..c3fcca5 100644 --- a/README.md +++ b/README.md @@ -100,15 +100,6 @@ print t.getProfileImageUrl('ryanmcgrath', size='bigger') print t.getProfileImageUrl('mikehelmick') ``` -###### Search Twitter *(no authentication needed)* - -```python -from twython import Twython - -t = Twython() -print t.search(q='python') -``` - ###### 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) streams.* diff --git a/README.rst b/README.rst index fc834ec..1bb6677 100644 --- a/README.rst +++ b/README.rst @@ -100,14 +100,6 @@ Get a user avatar url *(no authentication needed)* print t.getProfileImageUrl('ryanmcgrath', size='bigger') print t.getProfileImageUrl('mikehelmick') -Search Twitter *(no authentication needed)* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -:: - - from twython import Twython - t = Twython() - print t.search(q='python') - 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) diff --git a/setup.py b/setup.py index 3583fec..94d4006 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup from setuptools import find_packages __author__ = 'Ryan McGrath ' -__version__ = '2.5.5' +__version__ = '2.6.0' setup( # Basic package information. diff --git a/twython/twitter_endpoints.py b/twython/twitter_endpoints.py index 6ba82c3..03c418a 100644 --- a/twython/twitter_endpoints.py +++ b/twython/twitter_endpoints.py @@ -10,50 +10,97 @@ 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). + + 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_url = 'http://api.twitter.com/{{version}}' api_table = { - 'getRateLimitStatus': { - 'url': '/application/rate_limit_status.json', - 'method': 'GET', - }, - - 'verifyCredentials': { - 'url': '/account/verify_credentials.json', - 'method': 'GET', - }, - - 'endSession': { - 'url': '/account/end_session.json', - 'method': 'POST', - }, - - # Timeline methods - 'getHomeTimeline': { - 'url': '/statuses/home_timeline.json', + # Timelines + 'getMentionsTimeline': { + 'url': 'statuses/mentions_timeline', 'method': 'GET', }, 'getUserTimeline': { 'url': '/statuses/user_timeline.json', 'method': 'GET', }, - - # Interfacing with friends/followers - 'getUserMentions': { - 'url': '/statuses/mentions.json', + 'getHomeTimeline': { + 'url': '/statuses/home_timeline.json', 'method': 'GET', }, - 'createFriendship': { - 'url': '/friendships/create.json', + 'retweetedOfMe': { + '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', }, - 'destroyFriendship': { - 'url': '/friendships/destroy.json', + 'updateStatus': { + 'url': '/statuses/update.json', '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': { 'url': '/friends/ids.json', 'method': 'GET', @@ -62,12 +109,8 @@ api_table = { 'url': '/followers/ids.json', 'method': 'GET', }, - 'getFriendsList': { - 'url': '/friends/list.json', - 'method': 'GET', - }, - 'getFollowersList': { - 'url': '/followers/list.json', + 'lookupFriendships': { + 'url': '/friendships/lookup.json', 'method': 'GET', }, 'getIncomingFriendshipIDs': { @@ -78,119 +121,67 @@ api_table = { 'url': '/friendships/outgoing.json', 'method': 'GET', }, - - # Retweets - 'reTweet': { - 'url': '/statuses/retweet/{{id}}.json', + 'createFriendship': { + 'url': '/friendships/create.json', 'method': 'POST', }, - 'getRetweets': { - 'url': '/statuses/retweets/{{id}}.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', + 'destroyFriendship': { + 'url': '/friendships/destroy.json', 'method': 'POST', }, - 'destroyStatus': { - 'url': '/statuses/destroy/{{id}}.json', + 'updateFriendship': { + 'url': '/friendships/update.json', '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': { 'url': '/friendships/show.json', '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': { 'url': '/account/update_profile.json', 'method': 'POST', }, + # See twython.py for update_profile_background_image 'updateProfileColors': { 'url': '/account/update_profile_colors.json', 'method': 'POST', }, - 'myTotals': { - 'url': '/account/totals.json', + # See twython.py for update_profile_image + 'listBlocks': { + 'url': '/blocks/list.json', 'method': 'GET', }, - 'removeProfileBanner': { - 'url': '/account/remove_profile_banner.json', - 'method': 'POST', - }, - - # Favorites methods - 'getFavorites': { - 'url': '/favorites.json', + 'listBlockIds': { + 'url': '/blocks/ids.json', 'method': 'GET', }, - 'createFavorite': { - 'url': '/favorites/create/{{id}}.json', - 'method': 'POST', - }, - 'destroyFavorite': { - 'url': '/favorites/destroy/{{id}}.json', - 'method': 'POST', - }, - - # Blocking methods 'createBlock': { 'url': '/blocks/create/{{id}}.json', 'method': 'POST', @@ -199,119 +190,79 @@ api_table = { 'url': '/blocks/destroy/{{id}}.json', 'method': 'POST', }, - 'getBlocking': { - 'url': '/blocks/blocking.json', + 'lookupUser': { + 'url': '/users/lookup.json', 'method': 'GET', }, - 'getBlockedIDs': { - 'url': '/blocks/blocking/ids.json', + 'showUser': { + 'url': '/users/show.json', 'method': 'GET', }, - 'checkIfBlockExists': { - 'url': '/blocks/exists.json', + 'searchUsers': { + 'url': '/users/search.json', 'method': 'GET', }, - - # Trending methods - 'getCurrentTrends': { - 'url': '/trends/current.json', + 'getContributees': { + 'url': '/users/contributees.json', 'method': 'GET', }, - 'getDailyTrends': { - 'url': '/trends/daily.json', + 'getContributors': { + 'url': '/users/contributors.json', 'method': 'GET', }, - 'getWeeklyTrends': { - 'url': '/trends/weekly.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', + 'removeProfileBanner': { + 'url': '/account/remove_profile_banner.json', 'method': 'POST', }, - 'updateList': { - 'url': '/lists/update.json', + # See twython.py for update_profile_banner + + + # 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', }, + 'createFavorite': { + 'url': '/favorites/create.json', + 'method': 'POST', + }, + + + # Lists 'showLists': { - 'url': '/lists.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', + 'url': '/lists/list.json', 'method': 'GET', }, 'getListStatuses': { 'url': '/lists/statuses.json', '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': { 'url': '/lists/members/destroy.json', 'method': 'POST', }, - 'deleteListMembers': { - 'url': '/lists/members/destroy_all.json', - 'method': 'POST' + 'getListMemberships': { + 'url': '/lists/memberships.json', + 'method': 'GET', }, 'getListSubscribers': { 'url': '/lists/subscribers.json', @@ -321,34 +272,121 @@ api_table = { 'url': '/lists/subscribers/create.json', 'method': 'POST', }, + 'isListSubscriber': { + 'url': '/lists/subscribers/show.json', + 'method': 'GET', + }, 'unsubscribeFromList': { 'url': '/lists/subscribers/destroy.json', 'method': 'POST', }, - - # The one-offs - 'notificationFollow': { - 'url': '/notifications/follow/follow.json', - 'method': 'POST', + 'createListMembers': { + 'url': '/lists/members/create_all.json', + 'method': 'POST' }, - 'notificationLeave': { - 'url': '/notifications/leave/leave.json', - 'method': 'POST', - }, - 'updateDeliveryService': { - 'url': '/account/update_delivery_device.json', - 'method': 'POST', - }, - 'reportSpam': { - 'url': '/report_spam.json', - 'method': 'POST', - }, - 'getOembedTweet': { - 'url': '/statuses/oembed.json', + 'isListMember': { + 'url': '/lists/members/show.json', '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 twitter_http_status_codes = { 200: ('OK', 'Success!'), diff --git a/twython/twython.py b/twython/twython.py index 717080e..29b7418 100644 --- a/twython/twython.py +++ b/twython/twython.py @@ -7,7 +7,7 @@ """ __author__ = "Ryan McGrath " -__version__ = "2.5.5" +__version__ = "2.6.0" import urllib import re @@ -337,39 +337,6 @@ class Twython(object): 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()]) - 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): """ Returns a generator of tweets that match a specified query. @@ -382,7 +349,7 @@ class Twython(object): print result """ 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']: raise StopIteration