twython-3.8.2+dfsg.orig/0000755000175000017500000000000013642213174014451 5ustar noahfxnoahfxtwython-3.8.2+dfsg.orig/README.md0000644000175000017500000001412213641546501015732 0ustar noahfxnoahfx# Twython `Twython` is a Python library providing an easy way to access Twitter data. Supports Python 3. It's been battle tested by companies, educational institutions and individuals alike. Try it today! **Note**: As of Twython 3.7.0, there's a general call for maintainers put out. If you find the project useful and want to help out, reach out to Ryan with the info from the bottom of this README. Great open source project to get your feet wet with! ## Features - Query data for: - User information - Twitter lists - Timelines - Direct Messages - and anything found in [the docs](https://developer.twitter.com/en/docs) - Image Uploading: - Update user status with an image - Change user avatar - Change user background image - Change user banner image - OAuth 2 Application Only (read-only) Support - Support for Twitter's Streaming API - Seamless Python 3 support! ## Installation Install Twython via pip: ```bash $ pip install twython ``` Or, if you want the code that is currently on GitHub ```bash git clone git://github.com/ryanmcgrath/twython.git cd twython python setup.py install ``` ## Documentation Documentation is available at https://twython.readthedocs.io/en/latest/ ## Starting Out First, you'll want to head over to https://apps.twitter.com and register an application! After you register, grab your applications `Consumer Key` and `Consumer Secret` from the application details tab. The most common type of authentication is Twitter user authentication using OAuth 1. If you're a web app planning to have users sign up with their Twitter account and interact with their timelines, updating their status, and stuff like that this **is** the authentication for you! First, you'll want to import Twython ```python from twython import Twython ``` ## Obtain Authorization URL Now, you'll want to create a Twython instance with your `Consumer Key` and `Consumer Secret`: - Only pass *callback_url* to *get_authentication_tokens* if your application is a Web Application - Desktop and Mobile Applications **do not** require a callback_url ```python APP_KEY = 'YOUR_APP_KEY' APP_SECRET = 'YOUR_APP_SECRET' twitter = Twython(APP_KEY, APP_SECRET) auth = twitter.get_authentication_tokens(callback_url='http://mysite.com/callback') ``` From the `auth` variable, save the `oauth_token` and `oauth_token_secret` for later use (these are not the final auth tokens). In Django or other web frameworks, you might want to store it to a session variable ```python OAUTH_TOKEN = auth['oauth_token'] OAUTH_TOKEN_SECRET = auth['oauth_token_secret'] ``` Send the user to the authentication url, you can obtain it by accessing ```python auth['auth_url'] ``` ## Handling the Callback If your application is a Desktop or Mobile Application *oauth_verifier* will be the PIN code After they authorize your application to access some of their account details, they'll be redirected to the callback url you specified in `get_authentication_tokens`. You'll want to extract the `oauth_verifier` from the url. Django example: ```python oauth_verifier = request.GET['oauth_verifier'] ``` Now that you have the `oauth_verifier` stored to a variable, you'll want to create a new instance of Twython and grab the final user tokens ```python twitter = Twython( APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET ) final_step = twitter.get_authorized_tokens(oauth_verifier) ``` Once you have the final user tokens, store them in a database for later use:: ```python OAUTH_TOKEN = final_step['oauth_token'] OAUTH_TOKEN_SECRET = final_step['oauth_token_secret'] ``` For OAuth 2 (Application Only, read-only) authentication, see [our documentation](https://twython.readthedocs.io/en/latest/usage/starting_out.html#oauth-2-application-authentication). ## Dynamic Function Arguments Keyword arguments to functions are mapped to the functions available for each endpoint in the Twitter API docs. Doing this allows us to be incredibly flexible in querying the Twitter API, so changes to the API aren't held up from you using them by this library. Basic Usage ----------- **Function definitions (i.e. get_home_timeline()) can be found by reading over twython/endpoints.py** Create a Twython instance with your application keys and the users OAuth tokens ```python from twython import Twython twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET) ``` ## Authenticated Users Home Timeline ```python twitter.get_home_timeline() ``` ## Updating Status This method makes use of dynamic arguments, [read more about them](https://twython.readthedocs.io/en/latest/usage/starting_out.html#dynamic-function-arguments). ```python twitter.update_status(status='See how easy using Twython is!') ``` ## Advanced Usage - [Advanced Twython Usage](https://twython.readthedocs.io/en/latest/usage/advanced_usage.html) - [Streaming with Twython](https://twython.readthedocs.io/en/latest/usage/streaming_api.html) ## Questions, Comments, etc? My hope is that Twython is so simple that you'd never *have* to ask any questions, but if you feel the need to contact me for this (or other) reasons, you can hit me up at ryan@venodesigns.net. Or if I'm to busy to answer, feel free to ping mikeh@ydekproductions.com as well. Follow us on Twitter: - [@ryanmcgrath](https://twitter.com/ryanmcgrath) - [@mikehelmick](https://twitter.com/mikehelmick) ## Want to help? Twython is useful, but ultimately only as useful as the people using it (say that ten times fast!). If you'd like to help, write example code, contribute patches, document things on the wiki, tweet about it. Your help is always appreciated! twython-3.8.2+dfsg.orig/twython/0000755000175000017500000000000013642213174016165 5ustar noahfxnoahfxtwython-3.8.2+dfsg.orig/twython/streaming/0000755000175000017500000000000013642213174020156 5ustar noahfxnoahfxtwython-3.8.2+dfsg.orig/twython/streaming/api.py0000644000175000017500000001744313642213072021307 0ustar noahfxnoahfx# -*- coding: utf-8 -*- """ twython.streaming.api ~~~~~~~~~~~~~~~~~~~~~ This module contains functionality for interfacing with streaming Twitter API calls. """ from .. import __version__ from ..compat import json, is_py3 from ..helpers import _transparent_params from .types import TwythonStreamerTypes import requests from requests_oauthlib import OAuth1 import time class TwythonStreamer(object): def __init__(self, app_key, app_secret, oauth_token, oauth_token_secret, timeout=300, retry_count=None, retry_in=10, client_args=None, handlers=None, chunk_size=1): """Streaming class for a friendly streaming user experience Authentication IS required to use the Twitter Streaming API :param app_key: (required) Your applications key :param app_secret: (required) Your applications secret key :param oauth_token: (required) Used with oauth_token_secret to make authenticated calls :param oauth_token_secret: (required) Used with oauth_token to make authenticated calls :param timeout: (optional) How long (in secs) the streamer should wait for a response from Twitter Streaming API :param retry_count: (optional) Number of times the API call should be retired :param retry_in: (optional) Amount of time (in secs) the previous API call should be tried again :param client_args: (optional) Accepts some requests Session parameters and some requests Request parameters. See http://docs.python-requests.org/en/latest/api/#sessionapi and requests section below it for details. [ex. headers, proxies, verify(SSL verification)] :param handlers: (optional) Array of message types for which corresponding handlers will be called :param chunk_size: (optional) Define the buffer size before data is actually returned from the Streaming API. Default: 1 """ self.auth = OAuth1(app_key, app_secret, oauth_token, oauth_token_secret) self.client_args = client_args or {} default_headers = {'User-Agent': 'Twython Streaming v' + __version__} if 'headers' not in self.client_args: # If they didn't set any headers, set our defaults for them self.client_args['headers'] = default_headers elif 'User-Agent' not in self.client_args['headers']: # If they set headers, but didn't include User-Agent.. # set it for them self.client_args['headers'].update(default_headers) self.client_args['timeout'] = timeout self.client = requests.Session() self.client.auth = self.auth self.client.stream = True # Make a copy of the client args and iterate over them # Pop out all the acceptable args at this point because they will # Never be used again. client_args_copy = self.client_args.copy() for k, v in client_args_copy.items(): if k in ('cert', 'headers', 'hooks', 'max_redirects', 'proxies'): setattr(self.client, k, v) self.client_args.pop(k) # Pop, pop! self.api_version = '1.1' self.retry_in = retry_in self.retry_count = retry_count # Set up type methods StreamTypes = TwythonStreamerTypes(self) self.statuses = StreamTypes.statuses self.connected = False self.handlers = handlers if handlers else \ ['delete', 'limit', 'disconnect'] self.chunk_size = chunk_size def _request(self, url, method='GET', params=None): """Internal stream request handling""" self.connected = True retry_counter = 0 method = method.lower() func = getattr(self.client, method) params, _ = _transparent_params(params) def _send(retry_counter): requests_args = {} for k, v in self.client_args.items(): # Maybe this should be set as a class # variable and only done once? if k in ('timeout', 'allow_redirects', 'verify'): requests_args[k] = v while self.connected: try: if method == 'get': requests_args['params'] = params else: requests_args['data'] = params response = func(url, **requests_args) except requests.exceptions.Timeout: self.on_timeout() else: if response.status_code != 200: self.on_error(response.status_code, response.content, response.headers) if self.retry_count and \ (self.retry_count - retry_counter) > 0: time.sleep(self.retry_in) retry_counter += 1 _send(retry_counter) return response while self.connected: response = _send(retry_counter) for line in response.iter_lines(self.chunk_size): if not self.connected: break if line: try: if is_py3: line = line.decode('utf-8') data = json.loads(line) except ValueError: # pragma: no cover self.on_error(response.status_code, 'Unable to decode response, \ not valid JSON.') else: if self.on_success(data): # pragma: no cover for message_type in self.handlers: if message_type in data: handler = getattr(self, 'on_' + message_type, None) if handler \ and callable(handler) \ and not handler(data.get(message_type)): break response.close() def on_success(self, data): # pragma: no cover """Called when data has been successfully received from the stream. Returns True if other handlers for this message should be invoked. Feel free to override this to handle your streaming data how you want it handled. See https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/streaming-message-types for messages sent along in stream responses. :param data: data recieved from the stream :type data: dict """ return True def on_error(self, status_code, data, headers=None): # pragma: no cover """Called when stream returns non-200 status code Feel free to override this to handle your streaming data how you want it handled. :param status_code: Non-200 status code sent from stream :type status_code: int :param data: Error message sent from stream :type data: dict :param headers: Response headers sent from the stream (i.e. Retry-After) :type headers: dict """ return def on_timeout(self): # pragma: no cover """ Called when the request has timed out """ return def disconnect(self): """Used to disconnect the streaming client manually""" self.connected = False twython-3.8.2+dfsg.orig/twython/streaming/types.py0000644000175000017500000000560613641553571021712 0ustar noahfxnoahfx# -*- coding: utf-8 -*- """ twython.streaming.types ~~~~~~~~~~~~~~~~~~~~~~~ This module contains classes and methods for :class:`TwythonStreamer` to use. """ class TwythonStreamerTypes(object): """Class for different stream endpoints Not all streaming endpoints have nested endpoints. User Streams and Site Streams are single streams with no nested endpoints Status Streams include filter, sample and firehose endpoints """ def __init__(self, streamer): self.streamer = streamer self.statuses = TwythonStreamerTypesStatuses(streamer) class TwythonStreamerTypesStatuses(object): """Class for different statuses endpoints Available so :meth:`TwythonStreamer.statuses.filter()` is available. Just a bit cleaner than :meth:`TwythonStreamer.statuses_filter()`, :meth:`statuses_sample()`, etc. all being single methods in :class:`TwythonStreamer`. """ def __init__(self, streamer): self.streamer = streamer self.params = None def filter(self, **params): """Stream statuses/filter :param \*\*params: Parameters to send with your stream request Accepted params found at: https://developer.twitter.com/en/docs/tweets/filter-realtime/api-reference/post-statuses-filter """ url = 'https://stream.twitter.com/%s/statuses/filter.json' \ % self.streamer.api_version self.streamer._request(url, 'POST', params=params) def sample(self, **params): """Stream statuses/sample :param \*\*params: Parameters to send with your stream request Accepted params found at: https://developer.twitter.com/en/docs/tweets/sample-realtime/api-reference/get-statuses-sample """ url = 'https://stream.twitter.com/%s/statuses/sample.json' \ % self.streamer.api_version self.streamer._request(url, params=params) def firehose(self, **params): """Stream statuses/firehose :param \*\*params: Parameters to send with your stream request Accepted params found at: https://dev.twitter.com/docs/api/1.1/get/statuses/firehose """ url = 'https://stream.twitter.com/%s/statuses/firehose.json' \ % self.streamer.api_version self.streamer._request(url, params=params) def set_dynamic_filter(self, **params): """Set/update statuses/filter :param \*\*params: Parameters to send with your stream request Accepted params found at: https://developer.twitter.com/en/docs/tweets/filter-realtime/api-reference/post-statuses-filter """ self.params = params def dynamic_filter(self): """Stream statuses/filter with dynamic parameters""" url = 'https://stream.twitter.com/%s/statuses/filter.json' \ % self.streamer.api_version self.streamer._request(url, 'POST', params=self.params) twython-3.8.2+dfsg.orig/twython/streaming/__init__.py0000644000175000017500000000004112670232560022262 0ustar noahfxnoahfxfrom .api import TwythonStreamer twython-3.8.2+dfsg.orig/twython/compat.py0000644000175000017500000000127613641550517020034 0ustar noahfxnoahfx# -*- coding: utf-8 -*- """ twython.compat ~~~~~~~~~~~~~~ This module contains imports and declarations for seamless Python 2 and Python 3 compatibility. """ import sys _ver = sys.version_info #: Python 2.x? is_py2 = (_ver[0] == 2) #: Python 3.x? is_py3 = (_ver[0] == 3) try: import simplejson as json except ImportError: import json if is_py2: from urllib import urlencode, quote_plus from urlparse import parse_qsl, urlsplit str = unicode basestring = basestring numeric_types = (int, long, float) elif is_py3: from urllib.parse import urlencode, quote_plus, parse_qsl, urlsplit str = str basestring = (str, bytes) numeric_types = (int, float) twython-3.8.2+dfsg.orig/twython/exceptions.py0000644000175000017500000000325012670232560020720 0ustar noahfxnoahfx# -*- coding: utf-8 -*- """ twython.exceptions ~~~~~~~~~~~~~~~~~~ This module contains Twython specific Exception classes. """ from .endpoints import TWITTER_HTTP_STATUS_CODE class TwythonError(Exception): """Generic error class, catch-all for most Twython issues. Special cases are handled by TwythonAuthError & TwythonRateLimitError. from twython import TwythonError, TwythonRateLimitError, TwythonAuthError """ def __init__(self, msg, error_code=None, retry_after=None): self.error_code = error_code if error_code is not None and error_code in TWITTER_HTTP_STATUS_CODE: msg = 'Twitter API returned a %s (%s), %s' % \ (error_code, TWITTER_HTTP_STATUS_CODE[error_code][0], msg) super(TwythonError, self).__init__(msg) @property def msg(self): # pragma: no cover return self.args[0] class TwythonAuthError(TwythonError): """Raised when you try to access a protected resource and it fails due to some issue with your authentication. """ pass class TwythonRateLimitError(TwythonError): # pragma: no cover """Raised when you've hit a rate limit. The amount of seconds to retry your request in will be appended to the message. """ def __init__(self, msg, error_code, retry_after=None): if isinstance(retry_after, int): msg = '%s (Retry after %d seconds)' % (msg, retry_after) TwythonError.__init__(self, msg, error_code=error_code) self.retry_after = retry_after class TwythonStreamError(TwythonError): """Raised when an invalid response from the Stream API is received""" pass twython-3.8.2+dfsg.orig/twython/endpoints.py0000644000175000017500000012667513641543451020566 0ustar noahfxnoahfx# -*- coding: utf-8 -*- """ twython.endpoints ~~~~~~~~~~~~~~~~~ This module provides a mixin for a :class:`Twython ` instance. Parameters that need to be embedded in the API url just need to be passed as a keyword argument. e.g. Twython.retweet(id=12345) Official documentation for Twitter API endpoints can be found at: https://developer.twitter.com/en/docs/api-reference-index """ import json import os import warnings from io import BytesIO from time import sleep #try: #from StringIO import StringIO #except ImportError: #from io import StringIO from .advisory import TwythonDeprecationWarning class EndpointsMixin(object): # Timelines def get_mentions_timeline(self, **params): """Returns the 20 most recent mentions (tweets containing a users's @screen_name) for the authenticating user. Docs: https://developer.twitter.com/en/docs/tweets/timelines/api-reference/get-statuses-mentions_timeline """ return self.get('statuses/mentions_timeline', params=params) get_mentions_timeline.iter_mode = 'id' def get_user_timeline(self, **params): """Returns a collection of the most recent Tweets posted by the user indicated by the ``screen_name`` or ``user_id`` parameters. Docs: https://developer.twitter.com/en/docs/tweets/timelines/api-reference/get-statuses-user_timeline """ return self.get('statuses/user_timeline', params=params) get_user_timeline.iter_mode = 'id' def get_home_timeline(self, **params): """Returns a collection of the most recent Tweets and retweets posted by the authenticating user and the users they follow. Docs: https://developer.twitter.com/en/docs/tweets/timelines/api-reference/get-statuses-home_timeline """ return self.get('statuses/home_timeline', params=params) get_home_timeline.iter_mode = 'id' def retweeted_of_me(self, **params): """Returns the most recent tweets authored by the authenticating user that have been retweeted by others. Docs: https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-retweets_of_me """ return self.get('statuses/retweets_of_me', params=params) retweeted_of_me.iter_mode = 'id' # Tweets def get_retweets(self, **params): """Returns up to 100 of the first retweets of a given tweet. Docs: https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-retweet-id """ return self.get('statuses/retweets/%s' % params.get('id'), params=params) def show_status(self, **params): """Returns a single Tweet, specified by the ``id`` parameter Docs: https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-show-id """ return self.get('statuses/show/%s' % params.get('id'), params=params) def lookup_status(self, **params): """Returns fully-hydrated tweet objects for up to 100 tweets per request, as specified by comma-separated values passed to the ``id`` parameter. Docs: https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-lookup """ return self.post('statuses/lookup', params=params) def destroy_status(self, **params): """Destroys the status specified by the required ``id`` parameter Docs: https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-destroy-id """ return self.post('statuses/destroy/%s' % params.get('id')) def update_status(self, **params): """Updates the authenticating user's current status, also known as tweeting Docs: https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-update """ return self.post('statuses/update', params=params) def retweet(self, **params): """Retweets a tweet specified by the ``id`` parameter Docs: https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-retweet-id """ return self.post('statuses/retweet/%s' % params.get('id')) def update_status_with_media(self, **params): # pragma: no cover """Updates the authenticating user's current status and attaches media for upload. In other words, it creates a Tweet with a picture attached. Docs: https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-update_with_media """ warnings.warn( 'This method is deprecated. You should use Twython.upload_media instead.', TwythonDeprecationWarning, stacklevel=2 ) return self.post('statuses/update_with_media', params=params) def upload_media(self, **params): """Uploads media file to Twitter servers. The file will be available to be attached to a status for 60 minutes. To attach to a update, pass a list of returned media ids to the :meth:`update_status` method using the ``media_ids`` param. Docs: https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload """ # https://developer.twitter.com/en/docs/media/upload-media/api-reference/get-media-upload-status if params and params.get('command', '') == 'STATUS': return self.get('https://upload.twitter.com/1.1/media/upload.json', params=params) return self.post('https://upload.twitter.com/1.1/media/upload.json', params=params) def create_metadata(self, **params): """ Adds metadata to a media element, such as image descriptions for visually impaired. Docs: https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-metadata-create """ params = json.dumps(params) return self.post("https://upload.twitter.com/1.1/media/metadata/create.json", params=params) def upload_video(self, media, media_type, media_category=None, size=None, check_progress=False): """Uploads video file to Twitter servers in chunks. The file will be available to be attached to a status for 60 minutes. To attach to a update, pass a list of returned media ids to the :meth:`update_status` method using the ``media_ids`` param. Upload happens in 3 stages: - INIT call with size of media to be uploaded(in bytes). If this is more than 15mb, twitter will return error. - APPEND calls each with media chunk. This returns a 204(No Content) if chunk is received. - FINALIZE call to complete media upload. This returns media_id to be used with status update. Twitter media upload api expects each chunk to be not more than 5mb. We are sending chunk of 1mb each. Docs: https://developer.twitter.com/en/docs/media/upload-media/uploading-media/chunked-media-upload """ upload_url = 'https://upload.twitter.com/1.1/media/upload.json' if not size: media.seek(0, os.SEEK_END) size = media.tell() media.seek(0) # Stage 1: INIT call params = { 'command': 'INIT', 'media_type': media_type, 'total_bytes': size, 'media_category': media_category } response_init = self.post(upload_url, params=params) media_id = response_init['media_id'] # Stage 2: APPEND calls with 1mb chunks segment_index = 0 while True: data = media.read(1*1024*1024) if not data: break media_chunk = BytesIO() media_chunk.write(data) media_chunk.seek(0) params = { 'command': 'APPEND', 'media_id': media_id, 'segment_index': segment_index, 'media': media_chunk, } self.post(upload_url, params=params) segment_index += 1 # Stage 3: FINALIZE call to complete upload params = { 'command': 'FINALIZE', 'media_id': media_id } response = self.post(upload_url, params=params) # Only get the status if explicity asked to # Default to False if check_progress: # Stage 4: STATUS call if still processing params = { 'command': 'STATUS', 'media_id': media_id } # added code to handle if media_category is NOT set and check_progress=True # the API will return a NoneType object in this case try: processing_state = response.get('processing_info').get('state') except AttributeError: return response if processing_state: while (processing_state == 'pending' or processing_state == 'in_progress') : # get the secs to wait check_after_secs = response.get('processing_info').get('check_after_secs') if check_after_secs: sleep(check_after_secs) response = self.get(upload_url, params=params) # get new state after waiting processing_state = response.get('processing_info').get('state') return response def get_oembed_tweet(self, **params): """Returns information allowing the creation of an embedded representation of a Tweet on third party sites. Docs: https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-oembed """ return self.get('oembed', params=params) def get_retweeters_ids(self, **params): """Returns a collection of up to 100 user IDs belonging to users who have retweeted the tweet specified by the ``id`` parameter. Docs: https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-retweeters-ids """ return self.get('statuses/retweeters/ids', params=params) get_retweeters_ids.iter_mode = 'cursor' get_retweeters_ids.iter_key = 'ids' # Search def search(self, **params): """Returns a collection of relevant Tweets matching a specified query. Docs: https://developer.twitter.com/en/docs/tweets/search/api-reference/get-search-tweets """ return self.get('search/tweets', params=params) search.iter_mode = 'id' search.iter_key = 'statuses' search.iter_metadata = 'search_metadata' # Direct Messages def get_direct_messages(self, **params): """Returns the 20 most recent direct messages sent to the authenticating user. Docs: https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/list-events """ return self.get('direct_messages/events/list', params=params) get_direct_messages.iter_mode = 'id' def get_sent_messages(self, **params): """Returns the 20 most recent direct messages sent by the authenticating user. Docs: https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/get-sent-message """ return self.get('direct_messages/sent', params=params) get_sent_messages.iter_mode = 'id' def get_direct_message(self, **params): """Returns a single direct message, specified by an ``id`` parameter. Docs: https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/get-event """ return self.get('direct_messages/events/show', params=params) def destroy_direct_message(self, **params): """Destroys the direct message specified in the required ``id`` parameter Docs: https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/delete-message-event """ return self.delete('direct_messages/events/destroy', params=params) def send_direct_message(self, **params): """Sends a new direct message to the specified user from the authenticating user. Docs: https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/new-event """ return self.post('direct_messages/events/new', params=params, json_encoded=True) # Friends & Followers def get_user_ids_of_blocked_retweets(self, **params): """Returns a collection of user_ids that the currently authenticated user does not want to receive retweets from. Docs: https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friendships-no_retweets-ids """ return self.get('friendships/no_retweets/ids', params=params) def get_friends_ids(self, **params): """Returns a cursored collection of user IDs for every user the specified user is following (otherwise known as their "friends"). Docs: https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friends-ids """ return self.get('friends/ids', params=params) get_friends_ids.iter_mode = 'cursor' get_friends_ids.iter_key = 'ids' def get_followers_ids(self, **params): """Returns a cursored collection of user IDs for every user following the specified user. Docs: https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-followers-ids """ return self.get('followers/ids', params=params) get_followers_ids.iter_mode = 'cursor' get_followers_ids.iter_key = 'ids' def lookup_friendships(self, **params): """Returns the relationships of the authenticating user to the comma-separated list of up to 100 ``screen_names`` or ``user_ids`` provided. Docs: https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friendships-lookup """ return self.get('friendships/lookup', params=params) def get_incoming_friendship_ids(self, **params): """Returns a collection of numeric IDs for every user who has a pending request to follow the authenticating user. Docs: https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friendships-incoming """ return self.get('friendships/incoming', params=params) get_incoming_friendship_ids.iter_mode = 'cursor' get_incoming_friendship_ids.iter_key = 'ids' def get_outgoing_friendship_ids(self, **params): """Returns a collection of numeric IDs for every protected user for whom the authenticating user has a pending follow request. Docs: https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friendships-outgoing """ return self.get('friendships/outgoing', params=params) get_outgoing_friendship_ids.iter_mode = 'cursor' get_outgoing_friendship_ids.iter_key = 'ids' def create_friendship(self, **params): """Allows the authenticating users to follow the user specified in the ``id`` parameter. Docs: https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/post-friendships-create """ return self.post('friendships/create', params=params) def destroy_friendship(self, **params): """Allows the authenticating user to unfollow the user specified in the ``id`` parameter. Docs: https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/post-friendships-destroy """ return self.post('friendships/destroy', params=params) def update_friendship(self, **params): """Allows one to enable or disable retweets and device notifications from the specified user. Docs: https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/post-friendships-update """ return self.post('friendships/update', params=params) def show_friendship(self, **params): """Returns detailed information about the relationship between two arbitrary users. Docs: https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friendships-show """ return self.get('friendships/show', params=params) def get_friends_list(self, **params): """Returns a cursored collection of user objects for every user the specified user is following (otherwise known as their "friends"). Docs: https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friends-list """ return self.get('friends/list', params=params) get_friends_list.iter_mode = 'cursor' get_friends_list.iter_key = 'users' def get_followers_list(self, **params): """Returns a cursored collection of user objects for users following the specified user. Docs: https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-followers-list """ return self.get('followers/list', params=params) get_followers_list.iter_mode = 'cursor' get_followers_list.iter_key = 'users' # Users def get_account_settings(self, **params): """Returns settings (including current trend, geo and sleep time information) for the authenticating user. Docs: https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-account-settings """ return self.get('account/settings', params=params) def verify_credentials(self, **params): """Returns an HTTP 200 OK response code and a representation of the requesting user if authentication was successful; returns a 401 status code and an error message if not. Docs: https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-account-verify_credentials """ return self.get('account/verify_credentials', params=params) def update_account_settings(self, **params): """Updates the authenticating user's settings. Docs: https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-settings """ return self.post('account/settings', params=params) def update_delivery_service(self, **params): """Sets which device Twitter delivers updates to for the authenticating user. Docs: https://dev.twitter.com/docs/api/1.1/post/account/update_delivery_device """ return self.post('account/update_delivery_device', params=params) def update_profile(self, **params): """Sets values that users are able to set under the "Account" tab of their settings page. Docs: https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile """ return self.post('account/update_profile', params=params) def update_profile_banner_image(self, **params): # pragma: no cover """Updates the authenticating user's profile background image. Docs: https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile_background_image """ return self.post('account/update_profile_banner', params=params) def update_profile_colors(self, **params): # pragma: no cover """Sets one or more hex values that control the color scheme of the authenticating user's profile page on twitter.com. This method is deprecated, replaced by the ``profile_link_color`` parameter to :meth:`update_profile`. Docs: https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile """ warnings.warn( 'This method is deprecated. You should use the' ' profile_link_color parameter in Twython.update_profile instead.', TwythonDeprecationWarning, stacklevel=2 ) return self.post('account/update_profile_colors', params=params) def update_profile_image(self, **params): # pragma: no cover """Updates the authenticating user's profile image. Docs: https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile_image """ return self.post('account/update_profile_image', params=params) def list_blocks(self, **params): """Returns a collection of user objects that the authenticating user is blocking. Docs: https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/get-blocks-list """ return self.get('blocks/list', params=params) list_blocks.iter_mode = 'cursor' list_blocks.iter_key = 'users' def list_block_ids(self, **params): """Returns an array of numeric user ids the authenticating user is blocking. Docs: https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/get-blocks-ids """ return self.get('blocks/ids', params=params) list_block_ids.iter_mode = 'cursor' list_block_ids.iter_key = 'ids' def create_block(self, **params): """Blocks the specified user from following the authenticating user. Docs: https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-blocks-create """ return self.post('blocks/create', params=params) def destroy_block(self, **params): """Un-blocks the user specified in the ``id`` parameter for the authenticating user. Docs: https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-blocks-destroy """ return self.post('blocks/destroy', params=params) def lookup_user(self, **params): """Returns fully-hydrated user objects for up to 100 users per request, as specified by comma-separated values passed to the ``user_id`` and/or ``screen_name`` parameters. Docs: https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-lookup """ return self.get('users/lookup', params=params) def show_user(self, **params): """Returns a variety of information about the user specified by the required ``user_id`` or ``screen_name`` parameter. Docs: https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-show """ return self.get('users/show', params=params) def search_users(self, **params): """Provides a simple, relevance-based search interface to public user accounts on Twitter. Docs: https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-search """ return self.get('users/search', params=params) def get_contributees(self, **params): """Returns a collection of users that the specified user can "contribute" to. Docs: https://dev.twitter.com/docs/api/1.1/get/users/contributees """ return self.get('users/contributees', params=params) def get_contributors(self, **params): """Returns a collection of users who can contribute to the specified account. Docs: https://dev.twitter.com/docs/api/1.1/get/users/contributors """ return self.get('users/contributors', params=params) def remove_profile_banner(self, **params): """Removes the uploaded profile banner for the authenticating user. Returns HTTP 200 upon success. Docs: https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-remove_profile_banner """ return self.post('account/remove_profile_banner', params=params) def update_profile_background_image(self, **params): """Uploads a profile banner on behalf of the authenticating user. Docs: https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile_banner """ return self.post('account/update_profile_background_image', params=params) def get_profile_banner_sizes(self, **params): """Returns a map of the available size variations of the specified user's profile banner. Docs: https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-users-profile_banner """ return self.get('users/profile_banner', params=params) def list_mutes(self, **params): """Returns a collection of user objects that the authenticating user is muting. Docs: https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/get-mutes-users-list """ return self.get('mutes/users/list', params=params) list_mutes.iter_mode = 'cursor' list_mutes.iter_key = 'users' def list_mute_ids(self, **params): """Returns an array of numeric user ids the authenticating user is muting. Docs: https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/get-mutes-users-ids """ return self.get('mutes/users/ids', params=params) list_mute_ids.iter_mode = 'cursor' list_mute_ids.iter_key = 'ids' def create_mute(self, **params): """Mutes the specified user, preventing their tweets appearing in the authenticating user's timeline. Docs: https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-mutes-users-create """ return self.post('mutes/users/create', params=params) def destroy_mute(self, **params): """Un-mutes the user specified in the user or ``id`` parameter for the authenticating user. Docs: https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-mutes-users-destroy """ return self.post('mutes/users/destroy', params=params) # Suggested Users def get_user_suggestions_by_slug(self, **params): """Access the users in a given category of the Twitter suggested user list. Docs: https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-suggestions-slug """ return self.get('users/suggestions/%s' % params.get('slug'), params=params) def get_user_suggestions(self, **params): """Access to Twitter's suggested user list. Docs: https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-suggestions """ return self.get('users/suggestions', params=params) def get_user_suggestions_statuses_by_slug(self, **params): """Access the users in a given category of the Twitter suggested user list and return their most recent status if they are not a protected user. Docs: https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-suggestions-slug-members """ return self.get('users/suggestions/%s/members' % params.get('slug'), params=params) # Favorites def get_favorites(self, **params): """Returns the 20 most recent Tweets favorited by the authenticating or specified user. Docs: https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-favorites-list """ return self.get('favorites/list', params=params) get_favorites.iter_mode = 'id' def destroy_favorite(self, **params): """Un-favorites the status specified in the ``id`` parameter as the authenticating user. Docs: https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-favorites-destroy """ return self.post('favorites/destroy', params=params) def create_favorite(self, **params): """Favorites the status specified in the ``id`` parameter as the authenticating user. Docs: https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-favorites-create """ return self.post('favorites/create', params=params) # Lists def show_lists(self, **params): """Returns all lists the authenticating or specified user subscribes to, including their own. Docs: https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-list """ return self.get('lists/list', params=params) def get_list_statuses(self, **params): """Returns a timeline of tweets authored by members of the specified list. Docs: https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-statuses """ return self.get('lists/statuses', params=params) get_list_statuses.iter_mode = 'id' def delete_list_member(self, **params): """Removes the specified member from the list. Docs: https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-members-destroy """ return self.post('lists/members/destroy', params=params) def get_list_memberships(self, **params): """Returns the lists the specified user has been added to. Docs: https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-memberships """ return self.get('lists/memberships', params=params) get_list_memberships.iter_mode = 'cursor' get_list_memberships.iter_key = 'lists' def get_list_subscribers(self, **params): """Returns the subscribers of the specified list. Docs: https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-subscribers """ return self.get('lists/subscribers', params=params) get_list_subscribers.iter_mode = 'cursor' get_list_subscribers.iter_key = 'users' def subscribe_to_list(self, **params): """Subscribes the authenticated user to the specified list. Docs: https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-subscribers-create """ return self.post('lists/subscribers/create', params=params) def is_list_subscriber(self, **params): """Check if the specified user is a subscriber of the specified list. Docs: https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-subscribers-show """ return self.get('lists/subscribers/show', params=params) def unsubscribe_from_list(self, **params): """Unsubscribes the authenticated user from the specified list. Docs: https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-subscribers-destroy """ return self.post('lists/subscribers/destroy', params=params) def create_list_members(self, **params): """Adds multiple members to a list, by specifying a comma-separated list of member ids or screen names. Docs: https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-members-create_all """ return self.post('lists/members/create_all', params=params) def is_list_member(self, **params): """Check if the specified user is a member of the specified list. Docs: https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-members-show """ return self.get('lists/members/show', params=params) def get_list_members(self, **params): """Returns the members of the specified list. Docs: https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-members """ return self.get('lists/members', params=params) get_list_members.iter_mode = 'cursor' get_list_members.iter_key = 'users' def add_list_member(self, **params): """Add a member to a list. Docs: https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-members-create """ return self.post('lists/members/create', params=params) def delete_list(self, **params): """Deletes the specified list. Docs: https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-destroy """ return self.post('lists/destroy', params=params) def update_list(self, **params): """Updates the specified list. Docs: https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-update """ return self.post('lists/update', params=params) def create_list(self, **params): """Creates a new list for the authenticated user. Docs: https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-create """ return self.post('lists/create', params=params) def get_specific_list(self, **params): """Returns the specified list. Docs: https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-show """ return self.get('lists/show', params=params) def get_list_subscriptions(self, **params): """Obtain a collection of the lists the specified user is subscribed to. Docs: https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-subscriptions """ return self.get('lists/subscriptions', params=params) get_list_subscriptions.iter_mode = 'cursor' get_list_subscriptions.iter_key = 'lists' def delete_list_members(self, **params): """Removes multiple members from a list, by specifying a comma-separated list of member ids or screen names. Docs: https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-members-destroy_all """ return self.post('lists/members/destroy_all', params=params) def show_owned_lists(self, **params): """Returns the lists owned by the specified Twitter user. Docs: https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-ownerships """ return self.get('lists/ownerships', params=params) show_owned_lists.iter_mode = 'cursor' show_owned_lists.iter_key = 'lists' # Saved Searches def get_saved_searches(self, **params): """Returns the authenticated user's saved search queries. Docs: https://developer.twitter.com/en/docs/tweets/search/api-reference/get-saved_searches-list """ return self.get('saved_searches/list', params=params) def show_saved_search(self, **params): """Retrieve the information for the saved search represented by the given ``id``. Docs: https://developer.twitter.com/en/docs/tweets/search/api-reference/get-saved_searches-show-id """ return self.get('saved_searches/show/%s' % params.get('id'), params=params) def create_saved_search(self, **params): """Create a new saved search for the authenticated user. Docs: https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-mutes-users-create """ return self.post('saved_searches/create', params=params) def destroy_saved_search(self, **params): """Destroys a saved search for the authenticating user. Docs: https://developer.twitter.com/en/docs/tweets/search/api-reference/post-saved_searches-destroy-id """ return self.post('saved_searches/destroy/%s' % params.get('id'), params=params) # Places & Geo def get_geo_info(self, **params): """Returns all the information about a known place. Docs: https://developer.twitter.com/en/docs/geo/place-information/api-reference/get-geo-id-place_id """ return self.get('geo/id/%s' % params.get('place_id'), params=params) def reverse_geocode(self, **params): """Given a latitude and a longitude, searches for up to 20 places that can be used as a place_id when updating a status. Docs: https://developer.twitter.com/en/docs/geo/places-near-location/api-reference/get-geo-reverse_geocode """ return self.get('geo/reverse_geocode', params=params) def search_geo(self, **params): """Search for places that can be attached to a statuses/update. Docs: https://developer.twitter.com/en/docs/geo/places-near-location/api-reference/get-geo-search """ return self.get('geo/search', params=params) def get_similar_places(self, **params): """Locates places near the given coordinates which are similar in name. Docs: https://dev.twitter.com/docs/api/1.1/get/geo/similar_places """ return self.get('geo/similar_places', params=params) def create_place(self, **params): # pragma: no cover """Creates a new place object at the given latitude and longitude. Docs: https://dev.twitter.com/docs/api/1.1/post/geo/place """ return self.post('geo/place', params=params) # Trends def get_place_trends(self, **params): """Returns the top 10 trending topics for a specific WOEID, if trending information is available for it. Docs: https://developer.twitter.com/en/docs/trends/trends-for-location/api-reference/get-trends-place """ return self.get('trends/place', params=params) def get_available_trends(self, **params): """Returns the locations that Twitter has trending topic information for. Docs: https://developer.twitter.com/en/docs/trends/locations-with-trending-topics/api-reference/get-trends-available """ return self.get('trends/available', params=params) def get_closest_trends(self, **params): """Returns the locations that Twitter has trending topic information for, closest to a specified location. Docs: https://developer.twitter.com/en/docs/trends/locations-with-trending-topics/api-reference/get-trends-closest """ return self.get('trends/closest', params=params) # Spam Reporting def report_spam(self, **params): # pragma: no cover """Report the specified user as a spam account to Twitter. Docs: https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-users-report_spam """ return self.post('users/report_spam', params=params) # OAuth def invalidate_token(self, **params): # pragma: no cover """Allows a registered application to revoke an issued OAuth 2 Bearer Token by presenting its client credentials. Docs: https://developer.twitter.com/en/docs/basics/authentication/api-reference/invalidate_token """ return self.post('oauth2/invalidate_token', params=params) # Help def get_twitter_configuration(self, **params): """Returns the current configuration used by Twitter Docs: https://developer.twitter.com/en/docs/developer-utilities/configuration/api-reference/get-help-configuration """ return self.get('help/configuration', params=params) def get_supported_languages(self, **params): """Returns the list of languages supported by Twitter along with their ISO 639-1 code. Docs: https://developer.twitter.com/en/docs/developer-utilities/supported-languages/api-reference/get-help-languages """ return self.get('help/languages', params=params) def get_privacy_policy(self, **params): """Returns Twitter's Privacy Policy Docs: https://developer.twitter.com/en/docs/developer-utilities/privacy-policy/api-reference/get-help-privacy """ return self.get('help/privacy', params=params) def get_tos(self, **params): """Return the Twitter Terms of Service Docs: https://developer.twitter.com/en/docs/developer-utilities/terms-of-service/api-reference/get-help-tos """ return self.get('help/tos', params=params) def get_application_rate_limit_status(self, **params): """Returns the current rate limits for methods belonging to the specified resource families. Docs: https://developer.twitter.com/en/docs/developer-utilities/rate-limit-status/api-reference/get-application-rate_limit_status """ return self.get('application/rate_limit_status', params=params) # from https://developer.twitter.com/en/docs/ads/general/guides/response-codes TWITTER_HTTP_STATUS_CODE = { 200: ('OK', 'Success!'), 304: ('Not Modified', 'There was no new data to return.'), 400: ('Bad Request', 'The request was invalid. An accompanying \ error message will explain why. This is the status code \ will be returned during rate limiting.'), 401: ('Unauthorized', 'Authentication credentials were missing \ or incorrect.'), 403: ('Forbidden', 'The request is understood, but it has been \ refused. An accompanying error message will explain why. \ This code is used when requests are being denied due to \ update limits.'), 404: ('Not Found', 'The URI requested is invalid or the resource \ requested, such as a user, does not exists.'), 406: ('Not Acceptable', 'Returned by the Search API when an \ invalid format is specified in the request.'), 410: ('Gone', 'This resource is gone. Used to indicate that an \ API endpoint has been turned off.'), 422: ('Unprocessable Entity', 'Returned when an image uploaded to \ POST account/update_profile_banner is unable to be processed.'), 429: ('Too Many Requests', 'Returned in API v1.1 when a request cannot \ be served due to the application\'s rate limit having been \ exhausted for the resource.'), 500: ('Internal Server Error', 'Something is broken. Please post to the \ group so the Twitter team can investigate.'), 502: ('Bad Gateway', 'Twitter is down or being upgraded.'), 503: ('Service Unavailable', 'The Twitter servers are up, but overloaded \ with requests. Try again later.'), 504: ('Gateway Timeout', 'The Twitter servers are up, but the request \ couldn\'t be serviced due to some failure within our stack. Try \ again later.'), } twython-3.8.2+dfsg.orig/twython/advisory.py0000644000175000017500000000125213641543451020402 0ustar noahfxnoahfx# -*- coding: utf-8 -*- """ twython.advisory ~~~~~~~~~~~~~~~~ This module contains Warning classes for Twython to specifically alert the user about. This mainly is because Python 2.7 > mutes DeprecationWarning and when we deprecate a method or variable in Twython, we want to use to see the Warning but don't want ALL DeprecationWarnings to appear, only TwythonDeprecationWarnings. """ class TwythonDeprecationWarning(DeprecationWarning): """Custom DeprecationWarning to be raised when methods/variables are being deprecated in Twython. Python 2.7 > ignores DeprecationWarning so we want to specifically bubble up ONLY Twython Deprecation Warnings """ pass twython-3.8.2+dfsg.orig/twython/api.py0000644000175000017500000007243713641543451017330 0ustar noahfxnoahfx# -*- coding: utf-8 -*- """ twython.api ~~~~~~~~~~~ This module contains functionality for access to core Twitter API calls, Twitter Authentication, and miscellaneous methods that are useful when dealing with the Twitter API """ import warnings import re import requests from requests.auth import HTTPBasicAuth from requests_oauthlib import OAuth1, OAuth2 from . import __version__ from .advisory import TwythonDeprecationWarning from .compat import json, urlencode, parse_qsl, quote_plus, str, is_py2 from .compat import urlsplit from .endpoints import EndpointsMixin from .exceptions import TwythonError, TwythonAuthError, TwythonRateLimitError from .helpers import _transparent_params warnings.simplefilter('always', TwythonDeprecationWarning) # For Python 2.7 > class Twython(EndpointsMixin, object): def __init__(self, app_key=None, app_secret=None, oauth_token=None, oauth_token_secret=None, access_token=None, token_type='bearer', oauth_version=1, api_version='1.1', client_args=None, auth_endpoint='authenticate'): """Instantiates an instance of Twython. Takes optional parameters for authentication and such (see below). :param app_key: (optional) Your applications key :param app_secret: (optional) Your applications secret key :param oauth_token: (optional) When using **OAuth 1**, combined with oauth_token_secret to make authenticated calls :param oauth_token_secret: (optional) When using **OAuth 1** combined with oauth_token to make authenticated calls :param access_token: (optional) When using **OAuth 2**, provide a valid access token if you have one :param token_type: (optional) When using **OAuth 2**, provide your token type. Default: bearer :param oauth_version: (optional) Choose which OAuth version to use. Default: 1 :param api_version: (optional) Choose which Twitter API version to use. Default: 1.1 :param client_args: (optional) Accepts some requests Session parameters and some requests Request parameters. See http://docs.python-requests.org/en/latest/api/#sessionapi and requests section below it for details. [ex. headers, proxies, verify(SSL verification)] :param auth_endpoint: (optional) Lets you select which authentication endpoint will use your application. This will allow the application to have DM access if the endpoint is 'authorize'. Default: authenticate. """ # API urls, OAuth urls and API version; needed for hitting that there # API. self.api_version = api_version self.api_url = 'https://api.twitter.com/%s' self.app_key = app_key self.app_secret = app_secret self.oauth_token = oauth_token self.oauth_token_secret = oauth_token_secret self.access_token = access_token # OAuth 1 self.request_token_url = self.api_url % 'oauth/request_token' self.access_token_url = self.api_url % 'oauth/access_token' self.authenticate_url = self.api_url % ('oauth/%s' % auth_endpoint) if self.access_token: # If they pass an access token, force OAuth 2 oauth_version = 2 self.oauth_version = oauth_version # OAuth 2 if oauth_version == 2: self.request_token_url = self.api_url % 'oauth2/token' self.client_args = client_args or {} default_headers = {'User-Agent': 'Twython v' + __version__} if 'headers' not in self.client_args: # If they didn't set any headers, set our defaults for them self.client_args['headers'] = default_headers elif 'User-Agent' not in self.client_args['headers']: # If they set headers, but didn't include User-Agent.. set # it for them self.client_args['headers'].update(default_headers) # Generate OAuth authentication object for the request # If no keys/tokens are passed to __init__, auth=None allows for # unauthenticated requests, although I think all v1.1 requests # need auth auth = None if oauth_version == 1: # User Authentication is through OAuth 1 if self.app_key is not None and self.app_secret is not None: auth = OAuth1(self.app_key, self.app_secret, self.oauth_token, self.oauth_token_secret) elif oauth_version == 2 and self.access_token: # Application Authentication is through OAuth 2 token = {'token_type': token_type, 'access_token': self.access_token} auth = OAuth2(self.app_key, token=token) self.client = requests.Session() self.client.auth = auth # Make a copy of the client args and iterate over them # Pop out all the acceptable args at this point because they will # Never be used again. client_args_copy = self.client_args.copy() for k, v in client_args_copy.items(): if k in ('cert', 'hooks', 'max_redirects', 'proxies'): setattr(self.client, k, v) self.client_args.pop(k) # Pop, pop! # Headers are always present, so we unconditionally pop them and merge # them into the session headers. self.client.headers.update(self.client_args.pop('headers')) self._last_call = None def __repr__(self): return '' % (self.app_key) def _request(self, url, method='GET', params=None, api_call=None, json_encoded=False): """Internal request method""" method = method.lower() params = params or {} func = getattr(self.client, method) if isinstance(params, dict) and json_encoded is False: params, files = _transparent_params(params) else: params = params files = list() requests_args = {} for k, v in self.client_args.items(): # Maybe this should be set as a class variable and only done once? if k in ('timeout', 'allow_redirects', 'stream', 'verify'): requests_args[k] = v if method == 'get' or method == 'delete': requests_args['params'] = params else: # Check for json_encoded so we will sent params as "data" or "json" if json_encoded: data_key = 'json' else: data_key = 'data' requests_args.update({ data_key: params, 'files': files, }) try: response = func(url, **requests_args) except requests.RequestException as e: raise TwythonError(str(e)) # create stash for last function intel self._last_call = { 'api_call': api_call, 'api_error': None, 'cookies': response.cookies, 'headers': response.headers, 'status_code': response.status_code, 'url': response.url, 'content': response.text, } # greater than 304 (not modified) is an error if response.status_code > 304: error_message = self._get_error_message(response) self._last_call['api_error'] = error_message ExceptionType = TwythonError if response.status_code == 429: # Twitter API 1.1, always return 429 when # rate limit is exceeded ExceptionType = TwythonRateLimitError elif response.status_code == 401 or 'Bad Authentication data' \ in error_message: # Twitter API 1.1, returns a 401 Unauthorized or # a 400 "Bad Authentication data" for invalid/expired # app keys/user tokens ExceptionType = TwythonAuthError raise ExceptionType( error_message, error_code=response.status_code, retry_after=response.headers.get('X-Rate-Limit-Reset')) content = '' try: if response.status_code == 204: content = response.content else: content = response.json() except ValueError: if response.content != '': raise TwythonError('Response was not valid JSON. \ Unable to decode.') return content def _get_error_message(self, response): """Parse and return the first error message""" error_message = 'An error occurred processing your request.' try: content = response.json() # {"errors":[{"code":34,"message":"Sorry, # that page does not exist"}]} error_message = content['errors'][0]['message'] except TypeError: error_message = content['errors'] except ValueError: # bad json data from Twitter for an error pass except (KeyError, IndexError): # missing data so fallback to default message pass return error_message def request(self, endpoint, method='GET', params=None, version='1.1', json_encoded=False): """Return dict of response received from Twitter's API :param endpoint: (required) Full url or Twitter API endpoint (e.g. search/tweets) :type endpoint: string :param method: (optional) Method of accessing data, either GET, POST or DELETE. (default GET) :type method: string :param params: (optional) Dict of parameters (if any) accepted the by Twitter API endpoint you are trying to access (default None) :type params: dict or None :param version: (optional) Twitter API version to access (default 1.1) :type version: string :param json_encoded: (optional) Flag to indicate if this method should send data encoded as json (default False) :type json_encoded: bool :rtype: dict """ if endpoint.startswith('http://'): raise TwythonError('api.twitter.com is restricted to SSL/TLS traffic.') # In case they want to pass a full Twitter URL # i.e. https://api.twitter.com/1.1/search/tweets.json if endpoint.startswith('https://'): url = endpoint else: url = '%s/%s.json' % (self.api_url % version, endpoint) content = self._request(url, method=method, params=params, api_call=url, json_encoded=json_encoded) return content def get(self, endpoint, params=None, version='1.1'): """Shortcut for GET requests via :class:`request`""" return self.request(endpoint, params=params, version=version) def post(self, endpoint, params=None, version='1.1', json_encoded=False): """Shortcut for POST requests via :class:`request`""" return self.request(endpoint, 'POST', params=params, version=version, json_encoded=json_encoded) def delete(self, endpoint, params=None, version='1.1', json_encoded=False): """Shortcut for delete requests via :class:`request`""" return self.request(endpoint, 'DELETE', params=params, version=version, json_encoded=json_encoded) def get_lastfunction_header(self, header, default_return_value=None): """Returns a specific header from the last API call This will return None if the header is not present :param header: (required) The name of the header you want to get the value of Most useful for the following header information: x-rate-limit-limit, x-rate-limit-remaining, x-rate-limit-class, x-rate-limit-reset """ if self._last_call is None: raise TwythonError('This function must be called after an API call. \ It delivers header information.') return self._last_call['headers'].get(header, default_return_value) def get_authentication_tokens(self, callback_url=None, force_login=False, screen_name=''): """Returns a dict including an authorization URL, ``auth_url``, to direct a user to :param callback_url: (optional) Url the user is returned to after they authorize your app (web clients only) :param force_login: (optional) Forces the user to enter their credentials to ensure the correct users account is authorized. :param screen_name: (optional) If forced_login is set OR user is not currently logged in, Prefills the username input box of the OAuth login screen with the given value :rtype: dict """ if self.oauth_version != 1: raise TwythonError('This method can only be called when your \ OAuth version is 1.0.') request_args = {} if callback_url: request_args['oauth_callback'] = callback_url response = self.client.get(self.request_token_url, params=request_args) if response.status_code == 401: raise TwythonAuthError(response.content, error_code=response.status_code) elif response.status_code != 200: raise TwythonError(response.content, error_code=response.status_code) request_tokens = dict(parse_qsl(response.content.decode('utf-8'))) if not request_tokens: raise TwythonError('Unable to decode request tokens.') oauth_callback_confirmed = request_tokens.get('oauth_callback_confirmed') \ == 'true' auth_url_params = { 'oauth_token': request_tokens['oauth_token'], } if force_login: auth_url_params.update({ 'force_login': force_login, 'screen_name': screen_name }) # Use old-style callback argument if server didn't accept new-style if callback_url and not oauth_callback_confirmed: auth_url_params['oauth_callback'] = self.callback_url request_tokens['auth_url'] = self.authenticate_url + \ '?' + urlencode(auth_url_params) return request_tokens def get_authorized_tokens(self, oauth_verifier): """Returns a dict of authorized tokens after they go through the :class:`get_authentication_tokens` phase. :param oauth_verifier: (required) The oauth_verifier (or a.k.a PIN for non web apps) retrieved from the callback url querystring :rtype: dict """ if self.oauth_version != 1: raise TwythonError('This method can only be called when your \ OAuth version is 1.0.') response = self.client.get(self.access_token_url, params={'oauth_verifier': oauth_verifier}, headers={'Content-Type': 'application/\ json'}) if response.status_code == 401: try: try: # try to get json content = response.json() except AttributeError: # pragma: no cover # if unicode detected content = json.loads(response.content) except ValueError: content = {} raise TwythonError(content.get('error', 'Invalid / expired To \ ken'), error_code=response.status_code) authorized_tokens = dict(parse_qsl(response.content.decode('utf-8'))) if not authorized_tokens: raise TwythonError('Unable to decode authorized tokens.') return authorized_tokens # pragma: no cover def obtain_access_token(self): """Returns an OAuth 2 access token to make OAuth 2 authenticated read-only calls. :rtype: string """ if self.oauth_version != 2: raise TwythonError('This method can only be called when your \ OAuth version is 2.0.') data = {'grant_type': 'client_credentials'} basic_auth = HTTPBasicAuth(self.app_key, self.app_secret) try: response = self.client.post(self.request_token_url, data=data, auth=basic_auth) content = response.content.decode('utf-8') try: content = content.json() except AttributeError: content = json.loads(content) access_token = content['access_token'] except (KeyError, ValueError, requests.exceptions.RequestException): raise TwythonAuthError('Unable to obtain OAuth 2 access token.') else: return access_token @staticmethod def construct_api_url(api_url, **params): """Construct a Twitter API url, encoded, with parameters :param api_url: URL of the Twitter API endpoint you are attempting to construct :param \*\*params: Parameters that are accepted by Twitter for the endpoint you're requesting :rtype: string Usage:: >>> from twython import Twython >>> twitter = Twython() >>> api_url = 'https://api.twitter.com/1.1/search/tweets.json' >>> constructed_url = twitter.construct_api_url(api_url, q='python', result_type='popular') >>> print constructed_url https://api.twitter.com/1.1/search/tweets.json?q=python&result_type=popular """ querystring = [] params, _ = _transparent_params(params or {}) params = requests.utils.to_key_val_list(params) for (k, v) in params: querystring.append( '%s=%s' % (Twython.encode(k), quote_plus(Twython.encode(v))) ) return '%s?%s' % (api_url, '&'.join(querystring)) def search_gen(self, search_query, **params): # pragma: no cover warnings.warn( 'This method is deprecated. You should use Twython.cursor instead. \ [eg. Twython.cursor(Twython.search, q=\'your_query\')]', TwythonDeprecationWarning, stacklevel=2 ) return self.cursor(self.search, q=search_query, **params) def cursor(self, function, return_pages=False, **params): """Returns a generator for results that match a specified query. :param function: Instance of a Twython function (Twython.get_home_timeline, Twython.search) :param \*\*params: Extra parameters to send with your request (usually parameters accepted by the Twitter API endpoint) :rtype: generator Usage:: >>> from twython import Twython >>> twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET) >>> results = twitter.cursor(twitter.search, q='python') >>> for result in results: >>> print result """ if not callable(function): raise TypeError('.cursor() takes a Twython function as its first \ argument. Did you provide the result of a \ function call?') if not hasattr(function, 'iter_mode'): raise TwythonError('Unable to create generator for Twython \ method "%s"' % function.__name__) while True: content = function(**params) if not content: raise StopIteration if hasattr(function, 'iter_key'): results = content.get(function.iter_key) else: results = content if return_pages: yield results else: for result in results: yield result if function.iter_mode == 'cursor' and \ content['next_cursor_str'] == '0': raise StopIteration try: if function.iter_mode == 'id': # Set max_id in params to one less than lowest tweet id if hasattr(function, 'iter_metadata'): # Get supplied next max_id metadata = content.get(function.iter_metadata) if 'next_results' in metadata: next_results = urlsplit(metadata['next_results']) params = dict(parse_qsl(next_results.query)) else: # No more results raise StopIteration else: # Twitter gives tweets in reverse chronological order: params['max_id'] = str(int(content[-1]['id_str']) - 1) elif function.iter_mode == 'cursor': params['cursor'] = content['next_cursor_str'] except (TypeError, ValueError): # pragma: no cover raise TwythonError('Unable to generate next page of search \ results, `page` is not a number.') except (KeyError, AttributeError): #pragma no cover raise TwythonError('Unable to generate next page of search \ results, content has unexpected structure.') @staticmethod def unicode2utf8(text): try: if is_py2 and isinstance(text, str): text = text.encode('utf-8') except: pass return text @staticmethod def encode(text): if is_py2 and isinstance(text, (str)): return Twython.unicode2utf8(text) return str(text) @staticmethod def html_for_tweet(tweet, use_display_url=True, use_expanded_url=False, expand_quoted_status=False): """Return HTML for a tweet (urls, mentions, hashtags, symbols replaced with links) :param tweet: Tweet object from received from Twitter API :param use_display_url: Use display URL to represent link (ex. google.com, github.com). Default: True :param use_expanded_url: Use expanded URL to represent link (e.g. http://google.com). Default False If use_expanded_url is True, it overrides use_display_url. If use_display_url and use_expanded_url is False, short url will be used (t.co/xxxxx) """ if 'retweeted_status' in tweet: tweet = tweet['retweeted_status'] if 'extended_tweet' in tweet: tweet = tweet['extended_tweet'] orig_tweet_text = tweet.get('full_text') or tweet['text'] display_text_range = tweet.get('display_text_range') or [0, len(orig_tweet_text)] display_text_start, display_text_end = display_text_range[0], display_text_range[1] display_text = orig_tweet_text[display_text_start:display_text_end] prefix_text = orig_tweet_text[0:display_text_start] suffix_text = orig_tweet_text[display_text_end:len(orig_tweet_text)] if 'entities' in tweet: # We'll put all the bits of replacement HTML and their starts/ends # in this list: entities = [] # Mentions if 'user_mentions' in tweet['entities']: for entity in tweet['entities']['user_mentions']: temp = {} temp['start'] = entity['indices'][0] temp['end'] = entity['indices'][1] mention_html = '@%(screen_name)s' % {'screen_name': entity['screen_name']} if display_text_start <= temp['start'] <= display_text_end: temp['replacement'] = mention_html temp['start'] -= display_text_start temp['end'] -= display_text_start entities.append(temp) else: # Make the '@username' at the start, before # display_text, into a link: sub_expr = r'(?)' + orig_tweet_text[temp['start']:temp['end']] + '(?!)' prefix_text = re.sub(sub_expr, mention_html, prefix_text) # Hashtags if 'hashtags' in tweet['entities']: for entity in tweet['entities']['hashtags']: temp = {} temp['start'] = entity['indices'][0] - display_text_start temp['end'] = entity['indices'][1] - display_text_start url_html = '#%(hashtag)s' % {'hashtag': entity['text']} temp['replacement'] = url_html entities.append(temp) # Symbols if 'symbols' in tweet['entities']: for entity in tweet['entities']['symbols']: temp = {} temp['start'] = entity['indices'][0] - display_text_start temp['end'] = entity['indices'][1] - display_text_start url_html = '$%(symbol)s' % {'symbol': entity['text']} temp['replacement'] = url_html entities.append(temp) # URLs if 'urls' in tweet['entities']: for entity in tweet['entities']['urls']: temp = {} temp['start'] = entity['indices'][0] - display_text_start temp['end'] = entity['indices'][1] - display_text_start if use_display_url and entity.get('display_url') and not use_expanded_url: shown_url = entity['display_url'] elif use_expanded_url and entity.get('expanded_url'): shown_url = entity['expanded_url'] else: shown_url = entity['url'] url_html = '%s' % (entity['url'], shown_url) if display_text_start <= temp['start'] <= display_text_end: temp['replacement'] = url_html entities.append(temp) else: suffix_text = suffix_text.replace(orig_tweet_text[temp['start']:temp['end']], url_html) if 'media' in tweet['entities'] and len(tweet['entities']['media']) > 0: # We just link to the overall URL for the tweet's media, # rather than to each individual item. # So, we get the URL from the first media item: entity = tweet['entities']['media'][0] temp = {} temp['start'] = entity['indices'][0] temp['end'] = entity['indices'][1] if use_display_url and entity.get('display_url') and not use_expanded_url: shown_url = entity['display_url'] elif use_expanded_url and entity.get('expanded_url'): shown_url = entity['expanded_url'] else: shown_url = entity['url'] url_html = '%s' % (entity['url'], shown_url) if display_text_start <= temp['start'] <= display_text_end: temp['replacement'] = url_html entities.append(temp) else: suffix_text = suffix_text.replace(orig_tweet_text[temp['start']:temp['end']], url_html) # Now do all the replacements, starting from the end, so that the # start/end indices still work: for entity in sorted(entities, key=lambda e: e['start'], reverse=True): display_text = display_text[0:entity['start']] + entity['replacement'] + display_text[entity['end']:] quote_text = '' if expand_quoted_status and tweet.get('is_quote_status') and tweet.get('quoted_status'): quoted_status = tweet['quoted_status'] quote_text += '
%(quote)s' \ '%(quote_user_name)s' \ '@%(quote_user_screen_name)s' \ '
' % \ {'quote': Twython.html_for_tweet(quoted_status, use_display_url, use_expanded_url, False), 'quote_tweet_link': 'https://twitter.com/%s/status/%s' % (quoted_status['user']['screen_name'], quoted_status['id_str']), 'quote_user_name': quoted_status['user']['name'], 'quote_user_screen_name': quoted_status['user']['screen_name']} return '%(prefix)s%(display)s%(suffix)s%(quote)s' % { 'prefix': '%s' % prefix_text if prefix_text else '', 'display': display_text, 'suffix': '%s' % suffix_text if suffix_text else '', 'quote': quote_text } twython-3.8.2+dfsg.orig/twython/helpers.py0000644000175000017500000000157012670232560020204 0ustar noahfxnoahfx# -*- coding: utf-8 -*- """ twython.helpers ~~~~~~~~~~~~~~~ This module contains functions that are repeatedly used throughout the Twython library. """ from .compat import basestring, numeric_types def _transparent_params(_params): params = {} files = {} for k, v in _params.items(): if hasattr(v, 'read') and callable(v.read): files[k] = v # pragma: no cover elif isinstance(v, bool): if v: params[k] = 'true' else: params[k] = 'false' elif isinstance(v, basestring) or isinstance(v, numeric_types): params[k] = v elif isinstance(v, list): try: params[k] = ','.join(v) except TypeError: params[k] = ','.join(map(str, v)) else: continue # pragma: no cover return params, files twython-3.8.2+dfsg.orig/twython/__init__.py0000644000175000017500000000143313641543451020302 0ustar noahfxnoahfx# ______ __ __ # /_ __/_ __ __ __ / /_ / /_ ____ ____ # / / | | /| / // / / // __// __ \ / __ \ / __ \ # / / | |/ |/ // /_/ // /_ / / / // /_/ // / / / # /_/ |__/|__/ \__, / \__//_/ /_/ \____//_/ /_/ # /____/ """ Twython ------- Twython is a library for Python that wraps the Twitter API. It aims to abstract away all the API endpoints, so that additions to the library and/or the Twitter API won't cause any overall problems. Questions, comments? ryan@venodesigns.net """ __author__ = 'Ryan McGrath ' __version__ = '3.7.0' from .api import Twython from .streaming import TwythonStreamer from .exceptions import ( TwythonError, TwythonRateLimitError, TwythonAuthError, TwythonStreamError ) twython-3.8.2+dfsg.orig/LICENSE0000644000175000017500000000206112670232560015455 0ustar noahfxnoahfxThe MIT License Copyright (c) 2013 Ryan McGrath Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. twython-3.8.2+dfsg.orig/twython.egg-info/0000755000175000017500000000000013642213174017657 5ustar noahfxnoahfxtwython-3.8.2+dfsg.orig/twython.egg-info/dependency_links.txt0000644000175000017500000000000113642213173023724 0ustar noahfxnoahfx twython-3.8.2+dfsg.orig/twython.egg-info/SOURCES.txt0000644000175000017500000000515213642213173021545 0ustar noahfxnoahfxHISTORY.md LICENSE MANIFEST.in README.md requirements.txt setup.py docs/Makefile docs/api.rst docs/conf.py docs/index.rst docs/make.bat docs/_static/custom.css docs/_themes/basicstrap/customsidebar.html docs/_themes/basicstrap/layout.html docs/_themes/basicstrap/search.html docs/_themes/basicstrap/searchbox.html docs/_themes/basicstrap/searchresults.html docs/_themes/basicstrap/theme.conf docs/_themes/basicstrap/static/basicstrap.css_t docs/_themes/basicstrap/static/css/basicstrap-base.css docs/_themes/basicstrap/static/css/bootstrap-responsive.css docs/_themes/basicstrap/static/css/bootstrap-responsive.min.css docs/_themes/basicstrap/static/css/bootstrap.css docs/_themes/basicstrap/static/css/bootstrap.min.css docs/_themes/basicstrap/static/css/bootswatch-cerulean.css docs/_themes/basicstrap/static/css/font-awesome-ie7.min.css docs/_themes/basicstrap/static/css/font-awesome.css docs/_themes/basicstrap/static/css/font-awesome.min.css docs/_themes/basicstrap/static/font/FontAwesome.otf docs/_themes/basicstrap/static/font/fontawesome-webfont.eot docs/_themes/basicstrap/static/font/fontawesome-webfont.svg docs/_themes/basicstrap/static/font/fontawesome-webfont.ttf docs/_themes/basicstrap/static/font/fontawesome-webfont.woff docs/_themes/basicstrap/static/img/glyphicons-halflings-white.png docs/_themes/basicstrap/static/img/glyphicons-halflings.png docs/_themes/basicstrap/static/js/bootstrap.js docs/_themes/basicstrap/static/js/bootstrap.min.js docs/_themes/basicstrap/static/js/jquery.min.js docs/usage/advanced_usage.rst docs/usage/basic_usage.rst docs/usage/install.rst docs/usage/special_functions.rst docs/usage/starting_out.rst docs/usage/streaming_api.rst examples/follow_user.py examples/get_direct_messages.py examples/get_user_timeline.py examples/search_results.py examples/stream.py examples/update_profile_image.py examples/update_status.py tests/__init__.py tests/config.py tests/test_auth.py tests/test_core.py tests/test_endpoints.py tests/test_html_for_tweet.py tests/test_streaming.py tests/tweets/basic.json tests/tweets/compat.json tests/tweets/entities_with_prefix.json tests/tweets/extended.json tests/tweets/identical_urls.json tests/tweets/media.json tests/tweets/quoted.json tests/tweets/reply.json tests/tweets/retweet.json tests/tweets/symbols.json twython/__init__.py twython/advisory.py twython/api.py twython/compat.py twython/endpoints.py twython/exceptions.py twython/helpers.py twython.egg-info/PKG-INFO twython.egg-info/SOURCES.txt twython.egg-info/dependency_links.txt twython.egg-info/requires.txt twython.egg-info/top_level.txt twython/streaming/__init__.py twython/streaming/api.py twython/streaming/types.pytwython-3.8.2+dfsg.orig/twython.egg-info/requires.txt0000644000175000017500000000005113642213173022252 0ustar noahfxnoahfxrequests>=2.1.0 requests_oauthlib>=0.4.0 twython-3.8.2+dfsg.orig/twython.egg-info/PKG-INFO0000644000175000017500000005417013642213173020762 0ustar noahfxnoahfxMetadata-Version: 2.1 Name: twython Version: 3.8.2 Summary: Actively maintained, pure Python wrapper for the Twitter API. Supports both normal and streaming Twitter APIs Home-page: https://github.com/ryanmcgrath/twython/tree/master Author: Ryan McGrath Author-email: ryan@venodesigns.net License: MIT Description: # Twython `Twython` is a Python library providing an easy way to access Twitter data. Supports Python 3. It's been battle tested by companies, educational institutions and individuals alike. Try it today! **Note**: As of Twython 3.7.0, there's a general call for maintainers put out. If you find the project useful and want to help out, reach out to Ryan with the info from the bottom of this README. Great open source project to get your feet wet with! ## Features - Query data for: - User information - Twitter lists - Timelines - Direct Messages - and anything found in [the docs](https://developer.twitter.com/en/docs) - Image Uploading: - Update user status with an image - Change user avatar - Change user background image - Change user banner image - OAuth 2 Application Only (read-only) Support - Support for Twitter's Streaming API - Seamless Python 3 support! ## Installation Install Twython via pip: ```bash $ pip install twython ``` Or, if you want the code that is currently on GitHub ```bash git clone git://github.com/ryanmcgrath/twython.git cd twython python setup.py install ``` ## Documentation Documentation is available at https://twython.readthedocs.io/en/latest/ ## Starting Out First, you'll want to head over to https://apps.twitter.com and register an application! After you register, grab your applications `Consumer Key` and `Consumer Secret` from the application details tab. The most common type of authentication is Twitter user authentication using OAuth 1. If you're a web app planning to have users sign up with their Twitter account and interact with their timelines, updating their status, and stuff like that this **is** the authentication for you! First, you'll want to import Twython ```python from twython import Twython ``` ## Obtain Authorization URL Now, you'll want to create a Twython instance with your `Consumer Key` and `Consumer Secret`: - Only pass *callback_url* to *get_authentication_tokens* if your application is a Web Application - Desktop and Mobile Applications **do not** require a callback_url ```python APP_KEY = 'YOUR_APP_KEY' APP_SECRET = 'YOUR_APP_SECRET' twitter = Twython(APP_KEY, APP_SECRET) auth = twitter.get_authentication_tokens(callback_url='http://mysite.com/callback') ``` From the `auth` variable, save the `oauth_token` and `oauth_token_secret` for later use (these are not the final auth tokens). In Django or other web frameworks, you might want to store it to a session variable ```python OAUTH_TOKEN = auth['oauth_token'] OAUTH_TOKEN_SECRET = auth['oauth_token_secret'] ``` Send the user to the authentication url, you can obtain it by accessing ```python auth['auth_url'] ``` ## Handling the Callback If your application is a Desktop or Mobile Application *oauth_verifier* will be the PIN code After they authorize your application to access some of their account details, they'll be redirected to the callback url you specified in `get_authentication_tokens`. You'll want to extract the `oauth_verifier` from the url. Django example: ```python oauth_verifier = request.GET['oauth_verifier'] ``` Now that you have the `oauth_verifier` stored to a variable, you'll want to create a new instance of Twython and grab the final user tokens ```python twitter = Twython( APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET ) final_step = twitter.get_authorized_tokens(oauth_verifier) ``` Once you have the final user tokens, store them in a database for later use:: ```python OAUTH_TOKEN = final_step['oauth_token'] OAUTH_TOKEN_SECRET = final_step['oauth_token_secret'] ``` For OAuth 2 (Application Only, read-only) authentication, see [our documentation](https://twython.readthedocs.io/en/latest/usage/starting_out.html#oauth-2-application-authentication). ## Dynamic Function Arguments Keyword arguments to functions are mapped to the functions available for each endpoint in the Twitter API docs. Doing this allows us to be incredibly flexible in querying the Twitter API, so changes to the API aren't held up from you using them by this library. Basic Usage ----------- **Function definitions (i.e. get_home_timeline()) can be found by reading over twython/endpoints.py** Create a Twython instance with your application keys and the users OAuth tokens ```python from twython import Twython twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET) ``` ## Authenticated Users Home Timeline ```python twitter.get_home_timeline() ``` ## Updating Status This method makes use of dynamic arguments, [read more about them](https://twython.readthedocs.io/en/latest/usage/starting_out.html#dynamic-function-arguments). ```python twitter.update_status(status='See how easy using Twython is!') ``` ## Advanced Usage - [Advanced Twython Usage](https://twython.readthedocs.io/en/latest/usage/advanced_usage.html) - [Streaming with Twython](https://twython.readthedocs.io/en/latest/usage/streaming_api.html) ## Questions, Comments, etc? My hope is that Twython is so simple that you'd never *have* to ask any questions, but if you feel the need to contact me for this (or other) reasons, you can hit me up at ryan@venodesigns.net. Or if I'm to busy to answer, feel free to ping mikeh@ydekproductions.com as well. Follow us on Twitter: - [@ryanmcgrath](https://twitter.com/ryanmcgrath) - [@mikehelmick](https://twitter.com/mikehelmick) ## Want to help? Twython is useful, but ultimately only as useful as the people using it (say that ten times fast!). If you'd like to help, write example code, contribute patches, document things on the wiki, tweet about it. Your help is always appreciated! # History ## 3.8.0 (2020-04-02) - Bump release with latest patches from GitHub. - Fix Direct Messages with patches from @manuelcortez. ## 3.7.0 (2018-07-05) - Fixes for cursoring API endpoints - Improve `html_for_tweet()` parsing - Documentation cleanup - Documentation for cursor's `return_pages` keyword argument - Update links to Twitter API in documentation - Added `create_metadata` endpoint - Raise error for when cursor is not provided a callable ## 3.6.0 (2017-23-08) - Improve replacing of entities with links in `html_for_tweet()` - Update classifiers for PyPI ## 3.5.0 (2017-06-06) - Added support for "symbols" in `Twython.html_for_tweet()` - Added support for extended tweets in `Twython.html_for_tweet()` - You can now check progress of video uploads to Twitter when using `Twython.upload_video()` ## 3.4.0 (2016-30-04) - Added `upload_video` endpoint - Fix quoted status checks in `html_for_tweet` - Fix `html_for_tweet` method response when hashtag/mention is a substring of another ## 3.3.0 (2015-18-07) - Added support for muting users - Fix typos in documentation - Updated documentation examples - Added dynamic filtering to streamer ## 3.2.0 (2014-10-30) - PEP8'd some code - Added `lookup_status` function to `endpoints.py` - Added keyword argument to `cursor` to return full pages rather than individual results - `cursor` now uses while loop rather than recursion - Fixed issue where Twython was unnecessarily disabling compression - Using `responses` to mock API calls in tests - Fixed some typos in documentation - Added `retry_after` attribute to `TwythonRateLimitError` - Added `upload_media` method to `Twython` in favor of `update_with_media` - Deprecating `update_with_media` per Twitter API 1.1 (https://dev.twitter.com/rest/reference/post/statuses/update_with_media) - Unpin `requests` and `requests-oauthlib` in `requirements.txt` ## 3.1.2 (2013-12-05) - Fixed Changelog (HISTORY.rst) ## 3.1.1 (2013-12-05) - Update `requests` version to 2.1.0. - Fixed: Streaming issue where `Exceptions` in handlers or `on_success` which subclass `ValueError` would previously be caught and reported as a JSON decoding problem, and `on_error()` would be called (with status_code=200) - Fixed issue where XML was returned when bad tokens were passed to `get_authorized_tokens` - Fixed import for `setup` causing installation to fail on some devices (eg. Nokia N9/MeeGo) ## 3.1.0 (2013-09-25) - Added ``html_for_tweet`` static method. This method accepts a tweet object returned from a Twitter API call and will return a string with urls, mentions and hashtags in the tweet replaced with HTML. - Pass ``client_args`` to the streaming ``__init__``, much like in core Twython (you can pass headers, timeout, hooks, proxies, etc.). - Streamer has new parameter ``handlers`` which accepts a list of strings related to functions that are apart of the Streaming class and start with "on\_". i.e. ['delete'] is passed, when 'delete' is received from a stream response; ``on_delete`` will be called. - When an actual request error happens and a ``RequestException`` is raised, it is caught and a ``TwythonError`` is raised instead for convenience. - Added "cursor"-like functionality. Endpoints with the attribute ``iter_mode`` will be able to be passed to ``Twython.cursor`` and returned as a generator. - ``Twython.search_gen`` has been deprecated. Please use ``twitter.cursor(twitter.search, q='your_query')`` instead, where ``twitter`` is your ``Twython`` instance. - Added methods ``get_list_memberships``, ``get_twitter_configuration``, ``get_supported_languages``, ``get_privacy_policy``, ``get_tos`` - Added ``auth_endpoint`` parameter to ``Twython.__init__`` for cases when the right parameters weren't being shown during the authentication step. - Fixed streaming issue where results wouldn't be returned for streams that weren't so active (See https://github.com/ryanmcgrath/twython/issues/202#issuecomment-19915708) - Streaming API now uses ``_transparent_params`` so when passed ``True`` or ``False`` or an array, etc. Twython formats it to meet Twitter parameter standards (i.e. ['ryanmcgrath', 'mikehelmick', 'twitterapi'] would convert to string 'ryanmcgrath,mikehelmick,twitterapi') ## 3.0.0 (2013-06-18) - Changed ``twython/twython.py`` to ``twython/api.py`` in attempt to make structure look a little neater - Removed all camelCase function access (anything like ``getHomeTimeline`` is now ``get_home_timeline``) - Removed ``shorten_url``. With the ``requests`` library, shortening a URL on your own is simple enough - ``twitter_token``, ``twitter_secret`` and ``callback_url`` are no longer passed to ``Twython.__init__`` - ``twitter_token`` and ``twitter_secret`` have been replaced with ``app_key`` and ``app_secret`` respectively - ``callback_url`` is now passed through ``Twython.get_authentication_tokens`` - Update ``test_twython.py`` docstrings per http://www.python.org/dev/peps/pep-0257/ - Removed ``get_list_memberships``, method is Twitter API 1.0 deprecated - Developers can now pass an array as a parameter to Twitter API methods and they will be automatically joined by a comma and converted to a string - ``endpoints.py`` now contains ``EndpointsMixin`` (rather than the previous ``api_table`` dict) for Twython, which enables Twython to use functions declared in the Mixin. - Added OAuth 2 authentication (Application Only) for when you want to make read-only calls to Twitter without having to go through the whole user authentication ritual (see docs for usage) - Added ``obtain_access_token`` to obtain an OAuth 2 Application Only read-only access token - ``construct_api_url`` now accepts keyword arguments like other Twython methods (e.g. instead of passing ``{'q': 'twitter', 'result_type': 'recent'}``, pass ``q='twitter', result_type='recent'``) - Pass ``client_args`` to the Twython ``__init__`` to manipulate request variables. ``client_args`` accepts a dictionary of keywords and values that accepted by ``requests`` (`Session API `_) [ex. headers, proxies, verify(SSL verification)] and the "request" section directly below it. - Added ``get_application_rate_limit_status`` API method for returning the current rate limits for the specified source - Added ``invalidate_token`` API method which allows registed apps to revoke an access token presenting its client credentials - ``get_lastfunction_header`` now accepts a ``default_return_value`` parameter. This means that if you pass a second value (ex. ``Twython.get_lastfunction_header('x-rate-limit-remaining', 0)``) and the value is not found, it returns your default value ## 2.10.1 (2013-05-29) - More test coverage! - Fix ``search_gen`` - Fixed ``get_lastfunction_header`` to actually do what its docstring says, returns ``None`` if header is not found - Updated some internal API code, ``__init__`` didn't need to have ``self.auth`` and ``self.headers`` because they were never used anywhere else but the ``__init__`` - Added ``disconnect`` method to ``TwythonStreamer``, allowing users to disconnect as they desire - Updated ``TwythonStreamError`` docstring, also allow importing it from ``twython`` - No longer raise ``TwythonStreamError`` when stream line can't be decoded. Instead, sends signal to ``TwythonStreamer.on_error`` - Allow for (int, long, float) params to be passed to Twython Twitter API functions in Python 2, and (int, float) in Python 3 ## 2.10.0 (2013-05-21) - Added ``get_retweeters_ids`` method - Fixed ``TwythonDeprecationWarning`` on camelCase functions if the camelCase was the same as the PEP8 function (i.e. ``Twython.retweet`` did not change) - Fixed error message bubbling when error message returned from Twitter was not an array (i.e. if you try to retweet something twice, the error is not found at index 0) - Added "transparent" parameters for making requests, meaning users can pass bool values (True, False) to Twython methods and we convert your params in the background to satisfy the Twitter API. Also, file objects can now be passed seamlessly (see examples in README and in /examples dir for details) - Callback URL is optional in ``get_authentication_tokens`` to accomedate those using OOB authorization (non web clients) - Not part of the python package, but tests are now available along with Travis CI hooks - Added ``__repr__`` definition for Twython, when calling only returning - Cleaned up ``Twython.construct_api_url``, uses "transparent" parameters (see 4th bullet in this version for explaination) - Update ``requests`` and ``requests-oauthlib`` requirements, fixing posting files AND post data together, making authenticated requests in general in Python 3.3 ## 2.9.1 (2013-05-04) - "PEP8" all the functions. Switch functions from camelCase() to underscore_funcs(). (i.e. ``updateStatus()`` is now ``update_status()``) ## 2.9.0 (2013-05-04) - Fixed streaming issue #144, added ``TwythonStreamer`` to aid users in a friendly streaming experience (streaming examples in ``examples`` and README's have been updated as well) - ``Twython`` now requires ``requests-oauthlib`` 0.3.1, fixes #154 (unable to upload media when sending POST data with the file) ## 2.8.0 (2013-04-29) - Added a ``HISTORY.rst`` to start tracking history of changes - Updated ``twitter_endpoints.py`` to ``endpoints.py`` for cleanliness - Removed twython3k directory, no longer needed - Added ``compat.py`` for compatability with Python 2.6 and greater - Added some ascii art, moved description of Twython and ``__author__`` to ``__init__.py`` - Added ``version.py`` to store the current Twython version, instead of repeating it twice -- it also had to go into it's own file because of dependencies of ``requests`` and ``requests-oauthlib``, install would fail because those libraries weren't installed yet (on fresh install of Twython) - Removed ``find_packages()`` from ``setup.py``, only one package (we can just define it) - added quick publish method for Ryan and I: ``python setup.py publish`` is faster to type and easier to remember than ``python setup.py sdist upload`` - Removed ``base_url`` from ``endpoints.py`` because we're just repeating it in ``Twython.__init__`` - ``Twython.get_authentication_tokens()`` now takes ``callback_url`` argument rather than passing the ``callback_url`` through ``Twython.__init__``, ``callback_url`` is only used in the ``get_authentication_tokens`` method and nowhere else (kept in init though for backwards compatability) - Updated README to better reflect current Twython codebase - Added ``warnings.simplefilter('default')`` line in ``twython.py`` for Python 2.7 and greater to display Deprecation Warnings in console - Added Deprecation Warnings for usage of ``twitter_token``, ``twitter_secret`` and ``callback_url`` in ``Twython.__init__`` - Headers now always include the User-Agent as Twython vXX unless User-Agent is overwritten - Removed senseless TwythonError thrown if method is not GET or POST, who cares -- if the user passes something other than GET or POST just let Twitter return the error that they messed up - Removed conversion to unicode of (int, bool) params passed to a requests. ``requests`` isn't greedy about variables that can't be converted to unicode anymore - Removed `bulkUserLookup` (please use `lookupUser` instead), removed `getProfileImageUrl` (will be completely removed from Twitter API on May 7th, 2013) - Updated shortenUrl to actually work for those using it, but it is being deprecated since `requests` makes it easy for developers to implement their own url shortening in their app (see https://github.com/ryanmcgrath/twython/issues/184) - Twython Deprecation Warnings will now be seen in shell when using Python 2.7 and greater - Twython now takes ``ssl_verify`` parameter, defaults True. Set False if you're having development server issues - Removed internal ``_media_update`` function, we could have always just used ``self.post`` ## 2.7.3 (2013-04-12) - Fixed issue where Twython Exceptions were not being logged correctly ## 2.7.2 (2013-04-08) - Fixed ``AttributeError`` when trying to decode the JSON response via ``Response.json()`` ## 2.7.1 (2013-04-08) - Removed ``simplejson`` dependency - Fixed ``destroyDirectMessage``, ``createBlock``, ``destroyBlock`` endpoints in ``twitter_endpoints.py`` - Added ``getProfileBannerSizes`` method to ``twitter_endpoints.py`` - Made oauth_verifier argument required in ``get_authorized_tokens`` - Update ``updateProfileBannerImage`` to use v1.1 endpoint ## 2.7.0 (2013-04-04) - New ``showOwnedLists`` method ## 2.7.0 (2013-03-31) - Added missing slash to ``getMentionsTimeline`` in ``twitter_endpoints.py`` ## 2.6.0 (2013-03-29) - Updated ``twitter_endpoints.py`` to better reflect order of API endpoints on the Twitter API v1.1 docs site Keywords: twitter search api tweet twython stream Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: Communications :: Chat Classifier: Topic :: Internet Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Description-Content-Type: text/markdown twython-3.8.2+dfsg.orig/twython.egg-info/top_level.txt0000644000175000017500000000001013642213173022377 0ustar noahfxnoahfxtwython twython-3.8.2+dfsg.orig/requirements.txt0000644000175000017500000000016012670232560017732 0ustar noahfxnoahfxcoverage==3.6.0 requests>=2.1.0 requests_oauthlib>=0.4.0 python-coveralls==2.1.0 nose-cov==1.6 responses==0.3.0 twython-3.8.2+dfsg.orig/PKG-INFO0000644000175000017500000005417013642213174015555 0ustar noahfxnoahfxMetadata-Version: 2.1 Name: twython Version: 3.8.2 Summary: Actively maintained, pure Python wrapper for the Twitter API. Supports both normal and streaming Twitter APIs Home-page: https://github.com/ryanmcgrath/twython/tree/master Author: Ryan McGrath Author-email: ryan@venodesigns.net License: MIT Description: # Twython `Twython` is a Python library providing an easy way to access Twitter data. Supports Python 3. It's been battle tested by companies, educational institutions and individuals alike. Try it today! **Note**: As of Twython 3.7.0, there's a general call for maintainers put out. If you find the project useful and want to help out, reach out to Ryan with the info from the bottom of this README. Great open source project to get your feet wet with! ## Features - Query data for: - User information - Twitter lists - Timelines - Direct Messages - and anything found in [the docs](https://developer.twitter.com/en/docs) - Image Uploading: - Update user status with an image - Change user avatar - Change user background image - Change user banner image - OAuth 2 Application Only (read-only) Support - Support for Twitter's Streaming API - Seamless Python 3 support! ## Installation Install Twython via pip: ```bash $ pip install twython ``` Or, if you want the code that is currently on GitHub ```bash git clone git://github.com/ryanmcgrath/twython.git cd twython python setup.py install ``` ## Documentation Documentation is available at https://twython.readthedocs.io/en/latest/ ## Starting Out First, you'll want to head over to https://apps.twitter.com and register an application! After you register, grab your applications `Consumer Key` and `Consumer Secret` from the application details tab. The most common type of authentication is Twitter user authentication using OAuth 1. If you're a web app planning to have users sign up with their Twitter account and interact with their timelines, updating their status, and stuff like that this **is** the authentication for you! First, you'll want to import Twython ```python from twython import Twython ``` ## Obtain Authorization URL Now, you'll want to create a Twython instance with your `Consumer Key` and `Consumer Secret`: - Only pass *callback_url* to *get_authentication_tokens* if your application is a Web Application - Desktop and Mobile Applications **do not** require a callback_url ```python APP_KEY = 'YOUR_APP_KEY' APP_SECRET = 'YOUR_APP_SECRET' twitter = Twython(APP_KEY, APP_SECRET) auth = twitter.get_authentication_tokens(callback_url='http://mysite.com/callback') ``` From the `auth` variable, save the `oauth_token` and `oauth_token_secret` for later use (these are not the final auth tokens). In Django or other web frameworks, you might want to store it to a session variable ```python OAUTH_TOKEN = auth['oauth_token'] OAUTH_TOKEN_SECRET = auth['oauth_token_secret'] ``` Send the user to the authentication url, you can obtain it by accessing ```python auth['auth_url'] ``` ## Handling the Callback If your application is a Desktop or Mobile Application *oauth_verifier* will be the PIN code After they authorize your application to access some of their account details, they'll be redirected to the callback url you specified in `get_authentication_tokens`. You'll want to extract the `oauth_verifier` from the url. Django example: ```python oauth_verifier = request.GET['oauth_verifier'] ``` Now that you have the `oauth_verifier` stored to a variable, you'll want to create a new instance of Twython and grab the final user tokens ```python twitter = Twython( APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET ) final_step = twitter.get_authorized_tokens(oauth_verifier) ``` Once you have the final user tokens, store them in a database for later use:: ```python OAUTH_TOKEN = final_step['oauth_token'] OAUTH_TOKEN_SECRET = final_step['oauth_token_secret'] ``` For OAuth 2 (Application Only, read-only) authentication, see [our documentation](https://twython.readthedocs.io/en/latest/usage/starting_out.html#oauth-2-application-authentication). ## Dynamic Function Arguments Keyword arguments to functions are mapped to the functions available for each endpoint in the Twitter API docs. Doing this allows us to be incredibly flexible in querying the Twitter API, so changes to the API aren't held up from you using them by this library. Basic Usage ----------- **Function definitions (i.e. get_home_timeline()) can be found by reading over twython/endpoints.py** Create a Twython instance with your application keys and the users OAuth tokens ```python from twython import Twython twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET) ``` ## Authenticated Users Home Timeline ```python twitter.get_home_timeline() ``` ## Updating Status This method makes use of dynamic arguments, [read more about them](https://twython.readthedocs.io/en/latest/usage/starting_out.html#dynamic-function-arguments). ```python twitter.update_status(status='See how easy using Twython is!') ``` ## Advanced Usage - [Advanced Twython Usage](https://twython.readthedocs.io/en/latest/usage/advanced_usage.html) - [Streaming with Twython](https://twython.readthedocs.io/en/latest/usage/streaming_api.html) ## Questions, Comments, etc? My hope is that Twython is so simple that you'd never *have* to ask any questions, but if you feel the need to contact me for this (or other) reasons, you can hit me up at ryan@venodesigns.net. Or if I'm to busy to answer, feel free to ping mikeh@ydekproductions.com as well. Follow us on Twitter: - [@ryanmcgrath](https://twitter.com/ryanmcgrath) - [@mikehelmick](https://twitter.com/mikehelmick) ## Want to help? Twython is useful, but ultimately only as useful as the people using it (say that ten times fast!). If you'd like to help, write example code, contribute patches, document things on the wiki, tweet about it. Your help is always appreciated! # History ## 3.8.0 (2020-04-02) - Bump release with latest patches from GitHub. - Fix Direct Messages with patches from @manuelcortez. ## 3.7.0 (2018-07-05) - Fixes for cursoring API endpoints - Improve `html_for_tweet()` parsing - Documentation cleanup - Documentation for cursor's `return_pages` keyword argument - Update links to Twitter API in documentation - Added `create_metadata` endpoint - Raise error for when cursor is not provided a callable ## 3.6.0 (2017-23-08) - Improve replacing of entities with links in `html_for_tweet()` - Update classifiers for PyPI ## 3.5.0 (2017-06-06) - Added support for "symbols" in `Twython.html_for_tweet()` - Added support for extended tweets in `Twython.html_for_tweet()` - You can now check progress of video uploads to Twitter when using `Twython.upload_video()` ## 3.4.0 (2016-30-04) - Added `upload_video` endpoint - Fix quoted status checks in `html_for_tweet` - Fix `html_for_tweet` method response when hashtag/mention is a substring of another ## 3.3.0 (2015-18-07) - Added support for muting users - Fix typos in documentation - Updated documentation examples - Added dynamic filtering to streamer ## 3.2.0 (2014-10-30) - PEP8'd some code - Added `lookup_status` function to `endpoints.py` - Added keyword argument to `cursor` to return full pages rather than individual results - `cursor` now uses while loop rather than recursion - Fixed issue where Twython was unnecessarily disabling compression - Using `responses` to mock API calls in tests - Fixed some typos in documentation - Added `retry_after` attribute to `TwythonRateLimitError` - Added `upload_media` method to `Twython` in favor of `update_with_media` - Deprecating `update_with_media` per Twitter API 1.1 (https://dev.twitter.com/rest/reference/post/statuses/update_with_media) - Unpin `requests` and `requests-oauthlib` in `requirements.txt` ## 3.1.2 (2013-12-05) - Fixed Changelog (HISTORY.rst) ## 3.1.1 (2013-12-05) - Update `requests` version to 2.1.0. - Fixed: Streaming issue where `Exceptions` in handlers or `on_success` which subclass `ValueError` would previously be caught and reported as a JSON decoding problem, and `on_error()` would be called (with status_code=200) - Fixed issue where XML was returned when bad tokens were passed to `get_authorized_tokens` - Fixed import for `setup` causing installation to fail on some devices (eg. Nokia N9/MeeGo) ## 3.1.0 (2013-09-25) - Added ``html_for_tweet`` static method. This method accepts a tweet object returned from a Twitter API call and will return a string with urls, mentions and hashtags in the tweet replaced with HTML. - Pass ``client_args`` to the streaming ``__init__``, much like in core Twython (you can pass headers, timeout, hooks, proxies, etc.). - Streamer has new parameter ``handlers`` which accepts a list of strings related to functions that are apart of the Streaming class and start with "on\_". i.e. ['delete'] is passed, when 'delete' is received from a stream response; ``on_delete`` will be called. - When an actual request error happens and a ``RequestException`` is raised, it is caught and a ``TwythonError`` is raised instead for convenience. - Added "cursor"-like functionality. Endpoints with the attribute ``iter_mode`` will be able to be passed to ``Twython.cursor`` and returned as a generator. - ``Twython.search_gen`` has been deprecated. Please use ``twitter.cursor(twitter.search, q='your_query')`` instead, where ``twitter`` is your ``Twython`` instance. - Added methods ``get_list_memberships``, ``get_twitter_configuration``, ``get_supported_languages``, ``get_privacy_policy``, ``get_tos`` - Added ``auth_endpoint`` parameter to ``Twython.__init__`` for cases when the right parameters weren't being shown during the authentication step. - Fixed streaming issue where results wouldn't be returned for streams that weren't so active (See https://github.com/ryanmcgrath/twython/issues/202#issuecomment-19915708) - Streaming API now uses ``_transparent_params`` so when passed ``True`` or ``False`` or an array, etc. Twython formats it to meet Twitter parameter standards (i.e. ['ryanmcgrath', 'mikehelmick', 'twitterapi'] would convert to string 'ryanmcgrath,mikehelmick,twitterapi') ## 3.0.0 (2013-06-18) - Changed ``twython/twython.py`` to ``twython/api.py`` in attempt to make structure look a little neater - Removed all camelCase function access (anything like ``getHomeTimeline`` is now ``get_home_timeline``) - Removed ``shorten_url``. With the ``requests`` library, shortening a URL on your own is simple enough - ``twitter_token``, ``twitter_secret`` and ``callback_url`` are no longer passed to ``Twython.__init__`` - ``twitter_token`` and ``twitter_secret`` have been replaced with ``app_key`` and ``app_secret`` respectively - ``callback_url`` is now passed through ``Twython.get_authentication_tokens`` - Update ``test_twython.py`` docstrings per http://www.python.org/dev/peps/pep-0257/ - Removed ``get_list_memberships``, method is Twitter API 1.0 deprecated - Developers can now pass an array as a parameter to Twitter API methods and they will be automatically joined by a comma and converted to a string - ``endpoints.py`` now contains ``EndpointsMixin`` (rather than the previous ``api_table`` dict) for Twython, which enables Twython to use functions declared in the Mixin. - Added OAuth 2 authentication (Application Only) for when you want to make read-only calls to Twitter without having to go through the whole user authentication ritual (see docs for usage) - Added ``obtain_access_token`` to obtain an OAuth 2 Application Only read-only access token - ``construct_api_url`` now accepts keyword arguments like other Twython methods (e.g. instead of passing ``{'q': 'twitter', 'result_type': 'recent'}``, pass ``q='twitter', result_type='recent'``) - Pass ``client_args`` to the Twython ``__init__`` to manipulate request variables. ``client_args`` accepts a dictionary of keywords and values that accepted by ``requests`` (`Session API `_) [ex. headers, proxies, verify(SSL verification)] and the "request" section directly below it. - Added ``get_application_rate_limit_status`` API method for returning the current rate limits for the specified source - Added ``invalidate_token`` API method which allows registed apps to revoke an access token presenting its client credentials - ``get_lastfunction_header`` now accepts a ``default_return_value`` parameter. This means that if you pass a second value (ex. ``Twython.get_lastfunction_header('x-rate-limit-remaining', 0)``) and the value is not found, it returns your default value ## 2.10.1 (2013-05-29) - More test coverage! - Fix ``search_gen`` - Fixed ``get_lastfunction_header`` to actually do what its docstring says, returns ``None`` if header is not found - Updated some internal API code, ``__init__`` didn't need to have ``self.auth`` and ``self.headers`` because they were never used anywhere else but the ``__init__`` - Added ``disconnect`` method to ``TwythonStreamer``, allowing users to disconnect as they desire - Updated ``TwythonStreamError`` docstring, also allow importing it from ``twython`` - No longer raise ``TwythonStreamError`` when stream line can't be decoded. Instead, sends signal to ``TwythonStreamer.on_error`` - Allow for (int, long, float) params to be passed to Twython Twitter API functions in Python 2, and (int, float) in Python 3 ## 2.10.0 (2013-05-21) - Added ``get_retweeters_ids`` method - Fixed ``TwythonDeprecationWarning`` on camelCase functions if the camelCase was the same as the PEP8 function (i.e. ``Twython.retweet`` did not change) - Fixed error message bubbling when error message returned from Twitter was not an array (i.e. if you try to retweet something twice, the error is not found at index 0) - Added "transparent" parameters for making requests, meaning users can pass bool values (True, False) to Twython methods and we convert your params in the background to satisfy the Twitter API. Also, file objects can now be passed seamlessly (see examples in README and in /examples dir for details) - Callback URL is optional in ``get_authentication_tokens`` to accomedate those using OOB authorization (non web clients) - Not part of the python package, but tests are now available along with Travis CI hooks - Added ``__repr__`` definition for Twython, when calling only returning - Cleaned up ``Twython.construct_api_url``, uses "transparent" parameters (see 4th bullet in this version for explaination) - Update ``requests`` and ``requests-oauthlib`` requirements, fixing posting files AND post data together, making authenticated requests in general in Python 3.3 ## 2.9.1 (2013-05-04) - "PEP8" all the functions. Switch functions from camelCase() to underscore_funcs(). (i.e. ``updateStatus()`` is now ``update_status()``) ## 2.9.0 (2013-05-04) - Fixed streaming issue #144, added ``TwythonStreamer`` to aid users in a friendly streaming experience (streaming examples in ``examples`` and README's have been updated as well) - ``Twython`` now requires ``requests-oauthlib`` 0.3.1, fixes #154 (unable to upload media when sending POST data with the file) ## 2.8.0 (2013-04-29) - Added a ``HISTORY.rst`` to start tracking history of changes - Updated ``twitter_endpoints.py`` to ``endpoints.py`` for cleanliness - Removed twython3k directory, no longer needed - Added ``compat.py`` for compatability with Python 2.6 and greater - Added some ascii art, moved description of Twython and ``__author__`` to ``__init__.py`` - Added ``version.py`` to store the current Twython version, instead of repeating it twice -- it also had to go into it's own file because of dependencies of ``requests`` and ``requests-oauthlib``, install would fail because those libraries weren't installed yet (on fresh install of Twython) - Removed ``find_packages()`` from ``setup.py``, only one package (we can just define it) - added quick publish method for Ryan and I: ``python setup.py publish`` is faster to type and easier to remember than ``python setup.py sdist upload`` - Removed ``base_url`` from ``endpoints.py`` because we're just repeating it in ``Twython.__init__`` - ``Twython.get_authentication_tokens()`` now takes ``callback_url`` argument rather than passing the ``callback_url`` through ``Twython.__init__``, ``callback_url`` is only used in the ``get_authentication_tokens`` method and nowhere else (kept in init though for backwards compatability) - Updated README to better reflect current Twython codebase - Added ``warnings.simplefilter('default')`` line in ``twython.py`` for Python 2.7 and greater to display Deprecation Warnings in console - Added Deprecation Warnings for usage of ``twitter_token``, ``twitter_secret`` and ``callback_url`` in ``Twython.__init__`` - Headers now always include the User-Agent as Twython vXX unless User-Agent is overwritten - Removed senseless TwythonError thrown if method is not GET or POST, who cares -- if the user passes something other than GET or POST just let Twitter return the error that they messed up - Removed conversion to unicode of (int, bool) params passed to a requests. ``requests`` isn't greedy about variables that can't be converted to unicode anymore - Removed `bulkUserLookup` (please use `lookupUser` instead), removed `getProfileImageUrl` (will be completely removed from Twitter API on May 7th, 2013) - Updated shortenUrl to actually work for those using it, but it is being deprecated since `requests` makes it easy for developers to implement their own url shortening in their app (see https://github.com/ryanmcgrath/twython/issues/184) - Twython Deprecation Warnings will now be seen in shell when using Python 2.7 and greater - Twython now takes ``ssl_verify`` parameter, defaults True. Set False if you're having development server issues - Removed internal ``_media_update`` function, we could have always just used ``self.post`` ## 2.7.3 (2013-04-12) - Fixed issue where Twython Exceptions were not being logged correctly ## 2.7.2 (2013-04-08) - Fixed ``AttributeError`` when trying to decode the JSON response via ``Response.json()`` ## 2.7.1 (2013-04-08) - Removed ``simplejson`` dependency - Fixed ``destroyDirectMessage``, ``createBlock``, ``destroyBlock`` endpoints in ``twitter_endpoints.py`` - Added ``getProfileBannerSizes`` method to ``twitter_endpoints.py`` - Made oauth_verifier argument required in ``get_authorized_tokens`` - Update ``updateProfileBannerImage`` to use v1.1 endpoint ## 2.7.0 (2013-04-04) - New ``showOwnedLists`` method ## 2.7.0 (2013-03-31) - Added missing slash to ``getMentionsTimeline`` in ``twitter_endpoints.py`` ## 2.6.0 (2013-03-29) - Updated ``twitter_endpoints.py`` to better reflect order of API endpoints on the Twitter API v1.1 docs site Keywords: twitter search api tweet twython stream Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: Communications :: Chat Classifier: Topic :: Internet Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Description-Content-Type: text/markdown twython-3.8.2+dfsg.orig/examples/0000755000175000017500000000000013642213174016267 5ustar noahfxnoahfxtwython-3.8.2+dfsg.orig/examples/update_profile_image.py0000644000175000017500000000034512670232560023007 0ustar noahfxnoahfxfrom twython import Twython # Requires Authentication as of Twitter API v1.1 twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET) avatar = open('myImage.png', 'rb') twitter.update_profile_image(image=avatar) twython-3.8.2+dfsg.orig/examples/search_results.py0000644000175000017500000000103712670232560021670 0ustar noahfxnoahfxfrom twython import Twython, TwythonError # Requires Authentication as of Twitter API v1.1 twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET) try: search_results = twitter.search(q='WebsDotCom', count=50) except TwythonError as e: print e for tweet in search_results['statuses']: print 'Tweet from @%s Date: %s' % (tweet['user']['screen_nam\ e'].encode('utf-8'), tweet['created_at']) print tweet['text'].encode('utf-8'), '\n' twython-3.8.2+dfsg.orig/examples/follow_user.py0000644000175000017500000000105112670232560021176 0ustar noahfxnoahfxfrom twython import Twython, TwythonError # Optionally accept user data from the command line (or elsewhere). # # Usage: follow_user.py ryanmcgrath import sys if len(sys.argv) >= 2: target = sys.argv[1] else: target = raw_input("User to follow: ") # For Python 3.x use: target = input("User to follow: ") # Requires Authentication as of Twitter API v1.1 twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET) try: twitter.create_friendship(screen_name=target, follow="true") except TwythonError as e: print(e) twython-3.8.2+dfsg.orig/examples/get_user_timeline.py0000644000175000017500000000045613641544346022360 0ustar noahfxnoahfxfrom twython import Twython, TwythonError # Requires Authentication as of Twitter API v1.1 twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET) try: user_timeline = twitter.get_user_timeline(screen_name='ryanmcgrath') except TwythonError as e: print e print(user_timeline) twython-3.8.2+dfsg.orig/examples/update_status.py0000644000175000017500000000041312670232560021524 0ustar noahfxnoahfxfrom twython import Twython, TwythonError # Requires Authentication as of Twitter API v1.1 twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET) try: twitter.update_status(status='See how easy this was?') except TwythonError as e: print e twython-3.8.2+dfsg.orig/examples/stream.py0000644000175000017500000000122012670232560020127 0ustar noahfxnoahfxfrom twython import TwythonStreamer class MyStreamer(TwythonStreamer): def on_success(self, data): if 'text' in data: print data['text'].encode('utf-8') # Want to disconnect after the first result? # self.disconnect() def on_error(self, status_code, data): print status_code, data # Requires Authentication as of Twitter API v1.1 stream = MyStreamer(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET) stream.statuses.filter(track='twitter') # stream.user() # Read the authenticated users home timeline # (what they see on Twitter) in real-time # stream.site(follow='twitter') twython-3.8.2+dfsg.orig/examples/get_direct_messages.py0000644000175000017500000000025413641544516022650 0ustar noahfxnoahfxfrom twython import Twython, TwythonError twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET) get_list = twitter.get_direct_messages() print(get_list) twython-3.8.2+dfsg.orig/HISTORY.md0000644000175000017500000003102513641547065016145 0ustar noahfxnoahfx# History ## 3.8.0 (2020-04-02) - Bump release with latest patches from GitHub. - Fix Direct Messages with patches from @manuelcortez. ## 3.7.0 (2018-07-05) - Fixes for cursoring API endpoints - Improve `html_for_tweet()` parsing - Documentation cleanup - Documentation for cursor's `return_pages` keyword argument - Update links to Twitter API in documentation - Added `create_metadata` endpoint - Raise error for when cursor is not provided a callable ## 3.6.0 (2017-23-08) - Improve replacing of entities with links in `html_for_tweet()` - Update classifiers for PyPI ## 3.5.0 (2017-06-06) - Added support for "symbols" in `Twython.html_for_tweet()` - Added support for extended tweets in `Twython.html_for_tweet()` - You can now check progress of video uploads to Twitter when using `Twython.upload_video()` ## 3.4.0 (2016-30-04) - Added `upload_video` endpoint - Fix quoted status checks in `html_for_tweet` - Fix `html_for_tweet` method response when hashtag/mention is a substring of another ## 3.3.0 (2015-18-07) - Added support for muting users - Fix typos in documentation - Updated documentation examples - Added dynamic filtering to streamer ## 3.2.0 (2014-10-30) - PEP8'd some code - Added `lookup_status` function to `endpoints.py` - Added keyword argument to `cursor` to return full pages rather than individual results - `cursor` now uses while loop rather than recursion - Fixed issue where Twython was unnecessarily disabling compression - Using `responses` to mock API calls in tests - Fixed some typos in documentation - Added `retry_after` attribute to `TwythonRateLimitError` - Added `upload_media` method to `Twython` in favor of `update_with_media` - Deprecating `update_with_media` per Twitter API 1.1 (https://dev.twitter.com/rest/reference/post/statuses/update_with_media) - Unpin `requests` and `requests-oauthlib` in `requirements.txt` ## 3.1.2 (2013-12-05) - Fixed Changelog (HISTORY.rst) ## 3.1.1 (2013-12-05) - Update `requests` version to 2.1.0. - Fixed: Streaming issue where `Exceptions` in handlers or `on_success` which subclass `ValueError` would previously be caught and reported as a JSON decoding problem, and `on_error()` would be called (with status_code=200) - Fixed issue where XML was returned when bad tokens were passed to `get_authorized_tokens` - Fixed import for `setup` causing installation to fail on some devices (eg. Nokia N9/MeeGo) ## 3.1.0 (2013-09-25) - Added ``html_for_tweet`` static method. This method accepts a tweet object returned from a Twitter API call and will return a string with urls, mentions and hashtags in the tweet replaced with HTML. - Pass ``client_args`` to the streaming ``__init__``, much like in core Twython (you can pass headers, timeout, hooks, proxies, etc.). - Streamer has new parameter ``handlers`` which accepts a list of strings related to functions that are apart of the Streaming class and start with "on\_". i.e. ['delete'] is passed, when 'delete' is received from a stream response; ``on_delete`` will be called. - When an actual request error happens and a ``RequestException`` is raised, it is caught and a ``TwythonError`` is raised instead for convenience. - Added "cursor"-like functionality. Endpoints with the attribute ``iter_mode`` will be able to be passed to ``Twython.cursor`` and returned as a generator. - ``Twython.search_gen`` has been deprecated. Please use ``twitter.cursor(twitter.search, q='your_query')`` instead, where ``twitter`` is your ``Twython`` instance. - Added methods ``get_list_memberships``, ``get_twitter_configuration``, ``get_supported_languages``, ``get_privacy_policy``, ``get_tos`` - Added ``auth_endpoint`` parameter to ``Twython.__init__`` for cases when the right parameters weren't being shown during the authentication step. - Fixed streaming issue where results wouldn't be returned for streams that weren't so active (See https://github.com/ryanmcgrath/twython/issues/202#issuecomment-19915708) - Streaming API now uses ``_transparent_params`` so when passed ``True`` or ``False`` or an array, etc. Twython formats it to meet Twitter parameter standards (i.e. ['ryanmcgrath', 'mikehelmick', 'twitterapi'] would convert to string 'ryanmcgrath,mikehelmick,twitterapi') ## 3.0.0 (2013-06-18) - Changed ``twython/twython.py`` to ``twython/api.py`` in attempt to make structure look a little neater - Removed all camelCase function access (anything like ``getHomeTimeline`` is now ``get_home_timeline``) - Removed ``shorten_url``. With the ``requests`` library, shortening a URL on your own is simple enough - ``twitter_token``, ``twitter_secret`` and ``callback_url`` are no longer passed to ``Twython.__init__`` - ``twitter_token`` and ``twitter_secret`` have been replaced with ``app_key`` and ``app_secret`` respectively - ``callback_url`` is now passed through ``Twython.get_authentication_tokens`` - Update ``test_twython.py`` docstrings per http://www.python.org/dev/peps/pep-0257/ - Removed ``get_list_memberships``, method is Twitter API 1.0 deprecated - Developers can now pass an array as a parameter to Twitter API methods and they will be automatically joined by a comma and converted to a string - ``endpoints.py`` now contains ``EndpointsMixin`` (rather than the previous ``api_table`` dict) for Twython, which enables Twython to use functions declared in the Mixin. - Added OAuth 2 authentication (Application Only) for when you want to make read-only calls to Twitter without having to go through the whole user authentication ritual (see docs for usage) - Added ``obtain_access_token`` to obtain an OAuth 2 Application Only read-only access token - ``construct_api_url`` now accepts keyword arguments like other Twython methods (e.g. instead of passing ``{'q': 'twitter', 'result_type': 'recent'}``, pass ``q='twitter', result_type='recent'``) - Pass ``client_args`` to the Twython ``__init__`` to manipulate request variables. ``client_args`` accepts a dictionary of keywords and values that accepted by ``requests`` (`Session API `_) [ex. headers, proxies, verify(SSL verification)] and the "request" section directly below it. - Added ``get_application_rate_limit_status`` API method for returning the current rate limits for the specified source - Added ``invalidate_token`` API method which allows registed apps to revoke an access token presenting its client credentials - ``get_lastfunction_header`` now accepts a ``default_return_value`` parameter. This means that if you pass a second value (ex. ``Twython.get_lastfunction_header('x-rate-limit-remaining', 0)``) and the value is not found, it returns your default value ## 2.10.1 (2013-05-29) - More test coverage! - Fix ``search_gen`` - Fixed ``get_lastfunction_header`` to actually do what its docstring says, returns ``None`` if header is not found - Updated some internal API code, ``__init__`` didn't need to have ``self.auth`` and ``self.headers`` because they were never used anywhere else but the ``__init__`` - Added ``disconnect`` method to ``TwythonStreamer``, allowing users to disconnect as they desire - Updated ``TwythonStreamError`` docstring, also allow importing it from ``twython`` - No longer raise ``TwythonStreamError`` when stream line can't be decoded. Instead, sends signal to ``TwythonStreamer.on_error`` - Allow for (int, long, float) params to be passed to Twython Twitter API functions in Python 2, and (int, float) in Python 3 ## 2.10.0 (2013-05-21) - Added ``get_retweeters_ids`` method - Fixed ``TwythonDeprecationWarning`` on camelCase functions if the camelCase was the same as the PEP8 function (i.e. ``Twython.retweet`` did not change) - Fixed error message bubbling when error message returned from Twitter was not an array (i.e. if you try to retweet something twice, the error is not found at index 0) - Added "transparent" parameters for making requests, meaning users can pass bool values (True, False) to Twython methods and we convert your params in the background to satisfy the Twitter API. Also, file objects can now be passed seamlessly (see examples in README and in /examples dir for details) - Callback URL is optional in ``get_authentication_tokens`` to accomedate those using OOB authorization (non web clients) - Not part of the python package, but tests are now available along with Travis CI hooks - Added ``__repr__`` definition for Twython, when calling only returning - Cleaned up ``Twython.construct_api_url``, uses "transparent" parameters (see 4th bullet in this version for explaination) - Update ``requests`` and ``requests-oauthlib`` requirements, fixing posting files AND post data together, making authenticated requests in general in Python 3.3 ## 2.9.1 (2013-05-04) - "PEP8" all the functions. Switch functions from camelCase() to underscore_funcs(). (i.e. ``updateStatus()`` is now ``update_status()``) ## 2.9.0 (2013-05-04) - Fixed streaming issue #144, added ``TwythonStreamer`` to aid users in a friendly streaming experience (streaming examples in ``examples`` and README's have been updated as well) - ``Twython`` now requires ``requests-oauthlib`` 0.3.1, fixes #154 (unable to upload media when sending POST data with the file) ## 2.8.0 (2013-04-29) - Added a ``HISTORY.rst`` to start tracking history of changes - Updated ``twitter_endpoints.py`` to ``endpoints.py`` for cleanliness - Removed twython3k directory, no longer needed - Added ``compat.py`` for compatability with Python 2.6 and greater - Added some ascii art, moved description of Twython and ``__author__`` to ``__init__.py`` - Added ``version.py`` to store the current Twython version, instead of repeating it twice -- it also had to go into it's own file because of dependencies of ``requests`` and ``requests-oauthlib``, install would fail because those libraries weren't installed yet (on fresh install of Twython) - Removed ``find_packages()`` from ``setup.py``, only one package (we can just define it) - added quick publish method for Ryan and I: ``python setup.py publish`` is faster to type and easier to remember than ``python setup.py sdist upload`` - Removed ``base_url`` from ``endpoints.py`` because we're just repeating it in ``Twython.__init__`` - ``Twython.get_authentication_tokens()`` now takes ``callback_url`` argument rather than passing the ``callback_url`` through ``Twython.__init__``, ``callback_url`` is only used in the ``get_authentication_tokens`` method and nowhere else (kept in init though for backwards compatability) - Updated README to better reflect current Twython codebase - Added ``warnings.simplefilter('default')`` line in ``twython.py`` for Python 2.7 and greater to display Deprecation Warnings in console - Added Deprecation Warnings for usage of ``twitter_token``, ``twitter_secret`` and ``callback_url`` in ``Twython.__init__`` - Headers now always include the User-Agent as Twython vXX unless User-Agent is overwritten - Removed senseless TwythonError thrown if method is not GET or POST, who cares -- if the user passes something other than GET or POST just let Twitter return the error that they messed up - Removed conversion to unicode of (int, bool) params passed to a requests. ``requests`` isn't greedy about variables that can't be converted to unicode anymore - Removed `bulkUserLookup` (please use `lookupUser` instead), removed `getProfileImageUrl` (will be completely removed from Twitter API on May 7th, 2013) - Updated shortenUrl to actually work for those using it, but it is being deprecated since `requests` makes it easy for developers to implement their own url shortening in their app (see https://github.com/ryanmcgrath/twython/issues/184) - Twython Deprecation Warnings will now be seen in shell when using Python 2.7 and greater - Twython now takes ``ssl_verify`` parameter, defaults True. Set False if you're having development server issues - Removed internal ``_media_update`` function, we could have always just used ``self.post`` ## 2.7.3 (2013-04-12) - Fixed issue where Twython Exceptions were not being logged correctly ## 2.7.2 (2013-04-08) - Fixed ``AttributeError`` when trying to decode the JSON response via ``Response.json()`` ## 2.7.1 (2013-04-08) - Removed ``simplejson`` dependency - Fixed ``destroyDirectMessage``, ``createBlock``, ``destroyBlock`` endpoints in ``twitter_endpoints.py`` - Added ``getProfileBannerSizes`` method to ``twitter_endpoints.py`` - Made oauth_verifier argument required in ``get_authorized_tokens`` - Update ``updateProfileBannerImage`` to use v1.1 endpoint ## 2.7.0 (2013-04-04) - New ``showOwnedLists`` method ## 2.7.0 (2013-03-31) - Added missing slash to ``getMentionsTimeline`` in ``twitter_endpoints.py`` ## 2.6.0 (2013-03-29) - Updated ``twitter_endpoints.py`` to better reflect order of API endpoints on the Twitter API v1.1 docs site twython-3.8.2+dfsg.orig/setup.cfg0000644000175000017500000000004613642213174016272 0ustar noahfxnoahfx[egg_info] tag_build = tag_date = 0 twython-3.8.2+dfsg.orig/setup.py0000755000175000017500000000313013642213110016151 0ustar noahfxnoahfx#!/usr/bin/env python import os import sys try: from setuptools import setup except ImportError: from distutils.core import setup __author__ = 'Ryan McGrath ' __version__ = '3.8.2' packages = [ 'twython', 'twython.streaming' ] if sys.argv[-1] == 'publish': os.system('python setup.py sdist upload') sys.exit() setup( name='twython', version=__version__, install_requires=['requests>=2.1.0', 'requests_oauthlib>=0.4.0'], author='Ryan McGrath', author_email='ryan@venodesigns.net', license='MIT', url='https://github.com/ryanmcgrath/twython/tree/master', keywords='twitter search api tweet twython stream', description='Actively maintained, pure Python wrapper for the Twitter API. Supports both normal and streaming Twitter APIs', long_description=open('README.md', encoding='utf-8').read() + '\n\n' +open('HISTORY.md', encoding='utf-8').read(), long_description_content_type='text/markdown', include_package_data=True, packages=packages, classifiers=[ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Communications :: Chat', 'Topic :: Internet', 'Programming Language :: Python', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', ] ) twython-3.8.2+dfsg.orig/docs/0000755000175000017500000000000013642213174015401 5ustar noahfxnoahfxtwython-3.8.2+dfsg.orig/docs/Makefile0000644000175000017500000001515612670232560017051 0ustar noahfxnoahfx# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Twython.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Twython.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/Twython" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Twython" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." twython-3.8.2+dfsg.orig/docs/index.rst0000644000175000017500000000252113641543451017245 0ustar noahfxnoahfx.. Twython documentation master file, created by sphinx-quickstart on Thu May 30 22:31:25 2013. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Twython ======= | Actively maintained, pure Python wrapper for the Twitter API. Supports both normal and streaming Twitter APIs Features -------- - Query data for: - User information - Twitter lists - Timelines - Direct Messages - and anything found in `the Twitter API docs `_. - Image Uploading: - Update user status with an image - Change user avatar - Change user background image - Change user banner image - OAuth 2 Application Only (read-only) Support - Support for Twitter's Streaming API - Seamless Python 3 support! Usage ----- .. I know it isn't necessary to start a new tree for every section, but I think it looks a bit cleaner that way! .. toctree:: :maxdepth: 4 usage/install .. toctree:: :maxdepth: 4 usage/starting_out .. toctree:: :maxdepth: 4 usage/basic_usage .. toctree:: :maxdepth: 4 usage/advanced_usage .. toctree:: :maxdepth: 4 usage/streaming_api .. toctree:: :maxdepth: 2 usage/special_functions Twython API Documentation ------------------------- .. toctree:: :maxdepth: 2 api twython-3.8.2+dfsg.orig/docs/usage/0000755000175000017500000000000013642213174016505 5ustar noahfxnoahfxtwython-3.8.2+dfsg.orig/docs/usage/streaming_api.rst0000644000175000017500000000306313641543451022066 0ustar noahfxnoahfx.. _streaming-api: Streaming API ============= This section will cover how to use Twython and interact with the Twitter Streaming API. Streaming Documentation: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/streaming-message-types .. important:: The Streaming API requires that you have OAuth 1 authentication credentials. If you don't have credentials, head over to the :ref:`authentication section ` and find out how! Setting Up Your Streamer ------------------------ .. note:: When stream data is sent back to Twython, we send the data through signals (i.e. ``on_success``, ``on_error``, etc.) Make sure you import ``TwythonStreamer`` .. code-block:: python from twython import TwythonStreamer Now set up how you want to handle the signals. .. code-block:: python class MyStreamer(TwythonStreamer): def on_success(self, data): if 'text' in data: print(data['text']) def on_error(self, status_code, data): print(status_code) # Want to stop trying to get data because of the error? # Uncomment the next line! # self.disconnect() More signals that you can extend on can be found in the Developer Interface section under :ref:`Streaming Interface ` Filtering Public Statuses ------------------------- .. code-block:: python stream = MyStreamer(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET) stream.statuses.filter(track='twitter') With the code above, data should be flowing in. twython-3.8.2+dfsg.orig/docs/usage/basic_usage.rst0000644000175000017500000000552313641543451021514 0ustar noahfxnoahfx.. _basic-usage: Basic Usage =========== This section will cover how to use Twython and interact with some basic Twitter API calls Before you make any API calls, make sure you :ref:`authenticated the user ` (or :ref:`app `)! .. note:: All sections on this page will assume you're using a Twython instance ******************************************************************************* Authenticated Calls ------------------- OAuth 1 ~~~~~~~ Create a Twython instance with your application keys and the users OAuth tokens .. code-block:: python from twython import Twython twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET) User Information ^^^^^^^^^^^^^^^^ Documentation: https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-account-verify_credentials .. code-block:: python twitter.verify_credentials() Authenticated Users Home Timeline ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Documentation: https://developer.twitter.com/en/docs/tweets/timelines/api-reference/get-statuses-home_timeline .. code-block:: python twitter.get_home_timeline() Updating Status ^^^^^^^^^^^^^^^ This method makes use of dynamic arguments, :ref:`read more about them ` Documentation: https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-update .. code-block:: python twitter.update_status(status='See how easy using Twython is!') OAuth 2 ~~~~~~~ Create a Twython instance with your application key and access token .. code-block:: python from twython import Twython twitter = Twython(APP_KEY, access_token=ACCESS_TOKEN) .. _howtosearch: Searching --------- .. note:: Searching can be done whether you're authenticated via OAuth 1 or OAuth 2 Documentation: https://developer.twitter.com/en/docs/tweets/search/api-reference/get-search-tweets .. code-block:: python twitter.search(q='python') .. _dynamicargexplaination: .. important:: To help explain :ref:`dynamic function arguments ` a little more, you can see that the previous call used the keyword argument ``q``, that is because Twitter specifies in their `search documentation `_ that the search call accepts the parameter "q". You can pass mutiple keyword arguments. The search documentation also specifies that the call accepts the parameter "result_type" .. code-block:: python twitter.search(q='python', result_type='popular') ******************************************************************************* So, now, you're pretty well versed on making authenticated calls to Twitter using Twython. Check out the :ref:`advanced usage ` section, for some functions that may be a little more complicated. twython-3.8.2+dfsg.orig/docs/usage/install.rst0000644000175000017500000000252412670232560020710 0ustar noahfxnoahfx.. _install: Installation ============ Information on how to properly install Twython ******************************************************************************* Pip or Easy Install ------------------- Install Twython via `pip `_ .. code-block:: bash $ pip install twython or, with `easy_install `_ .. code-block:: bash $ easy_install twython But, hey... `that's up to you `_. Source Code ----------- Twython is actively maintained on GitHub Feel free to clone the repository .. code-block:: bash git clone git://github.com/ryanmcgrath/twython.git `tarball `_ .. code-block:: bash $ curl -OL https://github.com/ryanmcgrath/twython/tarball/master `zipball `_ .. code-block:: bash $ curl -OL https://github.com/ryanmcgrath/twython/zipball/master Now that you have the source code, install it into your site-packages directory .. code-block:: bash $ python setup.py install ******************************************************************************* So Twython is installed! Now, head over to the :ref:`starting out ` section.twython-3.8.2+dfsg.orig/docs/usage/advanced_usage.rst0000644000175000017500000001272013641543451022175 0ustar noahfxnoahfx.. _advanced-usage: Advanced Usage ============== This section will cover how to use Twython and interact with some more advanced API calls Before you make any API calls, make sure you :ref:`authenticated the user ` (or :ref:`app `)! .. note:: All sections on this page will assume you're using a Twython instance ******************************************************************************* Create a Twython instance with your application keys and the users OAuth tokens .. code-block:: python from twython import Twython twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET) Updating Status with Image -------------------------- This uploads an image as a media object and associates it with a status update. .. code-block:: python photo = open('/path/to/file/image.jpg', 'rb') response = twitter.upload_media(media=photo) twitter.update_status(status='Checkout this cool image!', media_ids=[response['media_id']]) Documentation: * https://developer.twitter.com/en/docs/api-reference-index * https://developer.twitter.com/en/docs/media/upload-media/overview Updating Status with Video -------------------------- This uploads a video as a media object and associates it with a status update. .. code-block:: python video = open('/path/to/file/video.mp4', 'rb') response = twitter.upload_video(media=video, media_type='video/mp4') twitter.update_status(status='Checkout this cool video!', media_ids=[response['media_id']]) Documentation: * https://developer.twitter.com/en/docs/api-reference-index * https://developer.twitter.com/en/docs/media/upload-media/overview Posting a Status with an Editing Image -------------------------------------- This example resizes an image, then uploads it as a media object and associates it with a status update. .. code-block:: python # Assume you are working with a JPEG from PIL import Image try: # Python 3 from io import StringIO except ImportError: # Python 2 from StringIO import StringIO photo = Image.open('/path/to/file/image.jpg') basewidth = 320 wpercent = (basewidth / float(photo.size[0])) height = int((float(photo.size[1]) * float(wpercent))) photo = photo.resize((basewidth, height), Image.ANTIALIAS) image_io = StringIO.StringIO() photo.save(image_io, format='JPEG') # If you do not seek(0), the image will be at the end of the file and # unable to be read image_io.seek(0) response = twitter.upload_media(media=image_io) twitter.update_status(status='Checkout this cool image!', media_ids=[response['media_id']]) Search Generator ---------------- So, if you're pretty into Python, you probably know about `generators `_ That being said, Twython offers a generator for search results and can be accessed by using the following code: .. code-block:: python from twython import Twython twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET) results = twitter.cursor(twitter.search, q='python') for result in results: print(result) Manipulate the Request (headers, proxies, etc.) ----------------------------------------------- There are times when you may want to turn SSL verification off, send custom headers, or add proxies for the request to go through. Twython uses the `requests `_ library to make API calls to Twitter. ``requests`` accepts a few parameters to allow developers to manipulate the acutal HTTP request. Here is an example of sending custom headers to a Twitter API request: .. code-block:: python from twython import Twython client_args = { 'headers': { 'User-Agent': 'My App Name' } } twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET, client_args=client_args) Here is an example of sending the request through proxies: .. code-block:: python from twython import Twython client_args = { 'proxies': { 'http': 'http://10.0.10.1:8000', 'https': 'https://10.0.10.1:8001', } } twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET, client_args=client_args) or both (and set a timeout variable): .. code-block:: python from twython import Twython client_args = { 'headers': { 'User-Agent': 'My App Name' }, 'proxies': { 'http': 'http://10.0.10.1:8000', 'https': 'https://10.0.10.1:8001', } 'timeout': 300, } twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET, client_args=client_args) Access Headers of Previous Call ------------------------------- There are times when you may want to check headers from the previous call. If you wish to access headers (ex. x-rate-limit-remaining, x-rate-limit-reset, content-type), you'll use the ``get_lastfunction_header`` method. .. code-block:: python from twython import Twython twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET) twitter.get_home_timeline() twitter.get_lastfunction_header('x-rate-limit-remaining') So now you can authenticate, update your status (with or without an image), search Twitter, and a few other things! Good luck! twython-3.8.2+dfsg.orig/docs/usage/starting_out.rst0000644000175000017500000001271513641543451021772 0ustar noahfxnoahfx.. _starting-out: Starting Out ============ This section is going to help you understand creating a Twitter Application, authenticating a user, and making basic API calls ******************************************************************************* Beginning --------- First, you'll want to head over to https://apps.twitter.com/ and register an application! After you register, grab your applications ``Consumer Key`` and ``Consumer Secret`` from the application details tab. Now you're ready to start authentication! Authentication -------------- Twython offers support for both OAuth 1 and OAuth 2 authentication. The difference: - :ref:`OAuth 1 ` is for user authenticated calls (tweeting, following people, sending DMs, etc.) - :ref:`OAuth 2 ` is for application authenticated calls (when you don't want to authenticate a user and make read-only calls to Twitter, i.e. searching, reading a public users timeline) .. _oauth1: OAuth 1 (User Authentication) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. important:: Again, if your web app is planning on using interacting with users, this **IS** the authentication type for you. If you're not interested in authenticating a user and plan on making read-only calls, check out the :ref:`OAuth 2 ` section. First, you'll want to import Twython .. code-block:: python from twython import Twython Now, you'll want to create a Twython instance with your ``Consumer Key`` and ``Consumer Secret`` Obtain Authorization URL ^^^^^^^^^^^^^^^^^^^^^^^^ .. note:: Only pass *callback_url* to *get_authentication_tokens* if your application is a Web Application Desktop and Mobile Applications **do not** require a callback_url .. code-block:: python APP_KEY = 'YOUR_APP_KEY' APP_SECRET = 'YOUR_APP_SECRET' twitter = Twython(APP_KEY, APP_SECRET) auth = twitter.get_authentication_tokens(callback_url='http://mysite.com/callback') From the ``auth`` variable, save the ``oauth_token_secret`` for later use (these are not the final auth tokens). In Django or other web frameworks, you might want to store it to a session variable .. code-block:: python OAUTH_TOKEN = auth['oauth_token'] OAUTH_TOKEN_SECRET = auth['oauth_token_secret'] Send the user to the authentication url, you can obtain it by accessing .. code-block:: python auth['auth_url'] Handling the Callback ^^^^^^^^^^^^^^^^^^^^^ .. note:: If your application is a Desktop or Mobile Application *oauth_verifier* will be the PIN code After they authorize your application to access some of their account details, they'll be redirected to the callback url you specified in ``get_autentication_tokens`` You'll want to extract the ``oauth_verifier`` from the url. Django example: .. code-block:: python oauth_verifier = request.GET['oauth_verifier'] Now that you have the ``oauth_verifier`` stored to a variable, you'll want to create a new instance of Twython and grab the final user tokens .. code-block:: python twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET) final_step = twitter.get_authorized_tokens(oauth_verifier) Once you have the final user tokens, store them in a database for later use! .. code-block:: python OAUTH_TOKEN = final_step['oauth_token'] OAUTH_TOKEN_SECRET = final_step['oauth_token_secret'] .. _oauth2: OAuth 2 (Application Authentication) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. attention:: Just a reminder, this authentication type is for when you don't want to authenticate and interact with users and make read-only calls to Twitter OAuth 2 authentication is 100x easier than OAuth 1. Let's say you *just* made your application and have your ``Consumer Key`` and ``Consumer Secret`` First, you'll want to import Twython .. code-block:: python from twython import Twython Obtain an OAuth 2 Access Token ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: python APP_KEY = 'YOUR_APP_KEY' APP_SECRET = 'YOUR_APP_SECRET' twitter = Twython(APP_KEY, APP_SECRET, oauth_version=2) ACCESS_TOKEN = twitter.obtain_access_token() Save ``ACCESS_TOKEN`` in a database or something for later use! Use the Access Token ^^^^^^^^^^^^^^^^^^^^ .. code-block:: python APP_KEY = 'YOUR_APP_KEY' ACCESS_TOKEN = 'YOUR_ACCESS_TOKEN' twitter = Twython(APP_KEY, access_token=ACCESS_TOKEN) Now that you have your OAuth 2 access_token, maybe you'll want to perform a :ref:`search ` or something The Twython API Table --------------------- The Twython package contains a file ``endpoints.py`` which holds a Mixin of all Twitter API endpoints. This is so Twython's core ``api.py`` isn't cluttered with 50+ methods. .. _dynamicfunctionarguments: Dynamic Function Arguments -------------------------- Keyword arguments to functions are mapped to the functions available for each endpoint in the Twitter API docs. Doing this allows us to be incredibly flexible in querying the Twitter API, so changes to the API aren't held up from you using them by this library. What Twython Returns -------------------- Twython returns native Python objects. We convert the JSON sent to us from Twitter to an object so you don't have to. ******************************************************************************* Now that you have a little idea of the type of data you'll be receiving, briefed on how arguments are handled, and your application tokens and user oauth tokens (or access token if you're using OAuth 2), check out the :ref:`basic usage ` section. twython-3.8.2+dfsg.orig/docs/usage/special_functions.rst0000644000175000017500000001013713641543451022754 0ustar noahfxnoahfx.. special-functions: Special Functions ================= This section covers methods to are part of Twython but not necessarily connected to the Twitter API. ******************************************************************************* Cursor ------ This function returns a generator for Twitter API endpoints that are able to be pagintated in some way (either by cursor or since_id parameter) The Old Way ^^^^^^^^^^^ .. code-block:: python from twython import Twython twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET) results = twitter.search(q='twitter') if results.get('statuses'): for result in results['statuses']: print(result['id_str']) The New Way ^^^^^^^^^^^ .. code-block:: python from twython import Twython twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET) results = twitter.cursor(twitter.search, q='twitter') for result in results: print(result['id_str']) Another example: .. code-block:: python results = twitter.cursor(twitter.get_mentions_timeline) for result in results: print(result['id_str']) Items vs Pages ^^^^^^^^^^^^^^ By default, the cursor yields one item at a time. If instead you prefer to work with entire pages of results, specify ``return_pages=True`` as a keyword argument. .. code-block:: python results = twitter.cursor(twitter.get_mentions_timeline, return_pages=True) # page is a list for page in results: for result in page: print(result['id_str']) HTML for Tweet -------------- This function takes a tweet object received from the Twitter API and returns an string formatted in HTML with the links, user mentions and hashtags replaced. .. code-block:: python from twython import Twython twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET) user_tweets = twitter.get_user_timeline(screen_name='mikehelmick', include_rts=True) for tweet in user_tweets: tweet['text'] = Twython.html_for_tweet(tweet) print(tweet['text']) The above code takes all the tweets from a specific users timeline, loops over them and replaces the value of ``tweet['text']`` with HTML. So: http://t.co/FCmXyI6VHd is #cool, lol! @mikehelmick shd #checkitout. Love, @__twython__ $IBM https://t.co/67pwRvY6z9 http://t.co/N6InAO4B71 will be replaced with: google.com is #cool, lol! @mikehelmick shd #checkitout. Love, @__twython__ $IBM github.com pic.twitter.com/N6InAO4B71 .. note:: When converting the string to HTML we add a class to each HTML tag so that you can maninpulate the DOM later on. - For urls that are replaced we add ``class="twython-url"`` to the anchor tag - For media urls that are replaced we add ``class="twython-media"`` to the anchor tag - For user mentions that are replaced we add ``class="twython-mention"`` to the anchor tag - For hashtags that are replaced we add ``class="twython-hashtag"`` to the anchor tag - For symbols that are replaced we add ``class="twython-symbol"`` to the anchor tag This function accepts two parameters: ``use_display_url`` and ``use_expanded_url`` By default, ``use_display_url`` is ``True``. Meaning the link displayed in the tweet text will appear as (ex. google.com, github.com) If ``use_expanded_url`` is ``True``, it overrides ``use_display_url``. The urls will then be displayed as (ex. http://google.com, https://github.com) If ``use_display_url`` and ``use_expanded_url`` are ``False``, short url will be used (t.co/xxxxx) twython-3.8.2+dfsg.orig/docs/api.rst0000644000175000017500000000166312670232560016712 0ustar noahfxnoahfx.. _api: Developer Interface =================== .. module:: twython This page of the documentation will cover all methods and classes available to the developer. Twython, currently, has two main interfaces: - Twitter's Core API (updating statuses, getting timelines, direct messaging, etc) - Twitter's Streaming API Core Interface -------------- .. autoclass:: Twython :special-members: __init__ :inherited-members: .. _streaming_interface: Streaming Interface ------------------- .. autoclass:: TwythonStreamer :special-members: __init__ :inherited-members: Streaming Types ~~~~~~~~~~~~~~~ .. autoclass:: twython.streaming.types.TwythonStreamerTypes :inherited-members: .. autoclass:: twython.streaming.types.TwythonStreamerTypesStatuses :inherited-members: Exceptions ---------- .. autoexception:: twython.TwythonError .. autoexception:: twython.TwythonAuthError .. autoexception:: twython.TwythonRateLimitErrortwython-3.8.2+dfsg.orig/docs/_static/0000755000175000017500000000000013642213174017027 5ustar noahfxnoahfxtwython-3.8.2+dfsg.orig/docs/_static/custom.css0000644000175000017500000000064612670232560021061 0ustar noahfxnoahfx.section { margin-bottom: 30px !important; } .tip { color: #3a87ad; /* Basicstrap CSS was messed up so override it */ } @media (min-width: 1200px) { .collapse .pull-right{ margin-right: 115px !important; } } .literal { background: #f5f5f5; padding: 2px 3px 3px; border: 1px solid #ccc; color: #11729B; -webkit-border-radius: 3px; border-radius: 3px; margin: 0 3px; } twython-3.8.2+dfsg.orig/docs/make.bat0000644000175000017500000001505712670232560017016 0ustar noahfxnoahfx@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Twython.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Twython.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end twython-3.8.2+dfsg.orig/docs/conf.py0000644000175000017500000002004313641554607016707 0ustar noahfxnoahfx# -*- coding: utf-8 -*- # # Twython documentation build configuration file, created by # sphinx-quickstart on Thu May 30 22:31:25 2013. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) sys.path.insert(0, os.path.abspath('..')) import twython # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'Twython' copyright = u'2013, Ryan McGrath' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '3.8.0' # The full version, including alpha/beta/rc tags. release = '3.8.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'Twythondoc' # -- Options for LaTeX output -------------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'Twython.tex', u'Twython Documentation', u'Ryan McGrath', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'twython', u'Twython Documentation', [u'Ryan McGrath'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'Twython', u'Twython Documentation', u'Ryan McGrath', 'Twython', 'One line description of project.', 'Miscellaneous'), ] # Activate the theme. sys.path.append(os.path.abspath('_themes')) html_theme_path = ['_themes'] html_theme = 'basicstrap' html_theme_options = { 'inner_theme': True, 'inner_theme_name': 'bootswatch-cerulean', } # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False twython-3.8.2+dfsg.orig/docs/_themes/0000755000175000017500000000000013642213174017025 5ustar noahfxnoahfxtwython-3.8.2+dfsg.orig/docs/_themes/basicstrap/0000755000175000017500000000000013647066407021172 5ustar noahfxnoahfxtwython-3.8.2+dfsg.orig/docs/_themes/basicstrap/layout.html0000755000175000017500000002624412670232560023376 0ustar noahfxnoahfx{# basicstrap/layout.html ~~~~~~~~~~~~~~~~~~~~~~~~~ Master layout template for Sphinx themes. on Twitter Bootstrap :copyright: Copyright 2012 by tell-k. :license: MIT Licence, see LICENSE for details. #} {%- block doctype -%} {%- endblock %} {%- set reldelim1 = reldelim1 is not defined and ' »' or reldelim1 %} {%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %} {%- set render_sidebar = (not embedded) and (not theme_nosidebar|tobool) and (sidebars != []) %} {%- set url_root = pathto('', 1) %} {# XXX necessary? #} {%- if url_root == '#' %}{% set url_root = '' %}{% endif %} {%- if not embedded and docstitle %} {%- set titlesuffix = " — "|safe + docstitle|e %} {%- else %} {%- set titlesuffix = "" %} {%- endif %} Fork me on GitHub {%- macro relbar() %} {%- endmacro %} {%- macro sidebar(for_mobile=False) %} {%- if render_sidebar %}
{%- if (for_mobile|tobool) and (not theme_noresponsive|tobool) %} Open Table Of Contents {%- endif %}
{%- endif %} {%- endmacro %} {% set script_files = script_files + ['_static/js/bootstrap.min.js'] %} {%- macro script() %} {%- for scriptfile in script_files %} {%- if scriptfile == '_static/jquery.js' %} {%- else %} {%- endif %} {%- endfor %} {%- endmacro %} {%- macro css() %} {%- if (theme_googlewebfont|tobool) %} {%- endif %} {%- if (theme_inner_theme|tobool) %} {%- else %} {%- endif %} {%- for cssfile in css_files %} {%- endfor %} {%- if (not theme_noresponsive|tobool) %} {%- endif %} {%- endmacro %} {{ metatags }} {%- block htmltitle %} {{ title|striptags|e }}{{ titlesuffix }} {%- endblock %} {{ css() }} {%- if not embedded %} {{ script() }} {%- if use_opensearch %} {%- endif %} {%- if favicon %} {%- endif %} {%- endif %} {%- block linktags %} {%- if hasdoc('about') %} {%- endif %} {%- if hasdoc('genindex') %} {%- endif %} {%- if hasdoc('search') %} {%- endif %} {%- if hasdoc('copyright') %} {%- endif %} {%- if parents %} {%- endif %} {%- if next %} {%- endif %} {%- if prev %} {%- endif %} {%- endblock %} {%- block extrahead %} {% endblock %} {%- block header %} {% endblock %}
{% if not theme_noresponsive|tobool %}
{{ sidebar(for_mobile=True) }}
{% endif %}
{%- block content %} {%- block sidebar1 %} {% if (not theme_rightsidebar|tobool) %} {{ sidebar() }} {% endif %} {% endblock %}
{%- block document %}
{%- if render_sidebar %}
{%- endif %}
{% block body %} {% endblock %}
{%- if render_sidebar %}
{%- endif %}
{%- endblock %}
{%- block sidebar2 %} {% if (theme_rightsidebar|tobool) %} {{ sidebar() }} {% endif %} {% endblock %} {%- endblock %}{# /content block #}
{%- block relbar2 %}{{ relbar() }}{% endblock %}
{%- block footer %}
{%- if show_copyright %} {%- if hasdoc('copyright') %} {% trans path=pathto('copyright'), copyright=copyright|e %}© Copyright {{ copyright }}.{% endtrans %} {%- else %} {% trans copyright=copyright|e %}© Copyright {{ copyright }}.{% endtrans %} {%- endif %} {%- endif %} {%- if last_updated %} {% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %} {%- endif %} {%- if show_sphinx %} {% trans sphinx_version=sphinx_version|e %}Created using Sphinx {{ sphinx_version }}.{% endtrans %} {%- endif %}
{%- endblock %}
twython-3.8.2+dfsg.orig/docs/_themes/basicstrap/searchresults.html0000755000175000017500000000216512670232560024744 0ustar noahfxnoahfx{# basicstrap/searchresults.html ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Template for the body of the search results page. :copyright: Copyright 2012 by tell-k. :license: MIT Licence, see LICENSE for details. #}

Search

From here you can search these documents. Enter your search words into the box below and click "search".

{%- if search_performed %}

Search Results

{%- if not search_results %}

Your search did not match any results.

{%- endif %} {%- endif %}
{%- if search_results %} {%- endif %}
twython-3.8.2+dfsg.orig/docs/_themes/basicstrap/customsidebar.html0000644000175000017500000000031213641554651024715 0ustar noahfxnoahfx

{{ _('Links') }}

twython-3.8.2+dfsg.orig/docs/_themes/basicstrap/searchbox.html0000755000175000017500000000150112670232560024024 0ustar noahfxnoahfx{# basicstrap/searchbox.html ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Sphinx sidebar template: quick search box. :copyright: Copyright 2012 by tell-k. :license: MIT Licence, see LICENSE for details. #} {%- if pagename != "search" %} {%- endif %} twython-3.8.2+dfsg.orig/docs/_themes/basicstrap/search.html0000755000175000017500000000356412670232560023326 0ustar noahfxnoahfx{# basicstrap/search.html ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Template for the search page. :copyright: Copyright 2012 by tell-k. :license: MIT Licence, see LICENSE for details. #} {% extends "layout.html" %} {% set title = _('Search') %} {% set script_files = script_files + ['_static/searchtools.js'] %} {% block extrahead %} {{ super() }} {% endblock %} {% block body %}

{{ _('Search') }}

{% trans %}Please activate JavaScript to enable the search functionality.{% endtrans %}

{% trans %}From here you can search these documents. Enter your search words into the box below and click "search". Note that the search function will automatically search for all of the words. Pages containing fewer words won't appear in the result list.{% endtrans %}

{% if search_performed %}

{{ _('Search Results') }}

{% if not search_results %}

{{ _('Your search did not match any results.') }}

{% endif %} {% endif %}
{% if search_results %}
    {% for href, caption, context in search_results %}
  • {{ caption }}
    {{ context|e }}
  • {% endfor %}
{% endif %}
{% endblock %} twython-3.8.2+dfsg.orig/docs/_themes/basicstrap/theme.conf0000755000175000017500000000103112670232560023127 0ustar noahfxnoahfx[theme] inherit = basic stylesheet = basicstrap.css pygments_style = friendly [options] lang = en nosidebar = false rightsidebar = false sidebar_span = 3 nav_fixed = false content_fixed = false row_fixed = false noresponsive = false nav_width = 900px content_width = 900px googlewebfont = false googlewebfont_url = http://fonts.googleapis.com/css?family=Text+Me+One googlewebfont_style = font-family: 'Text Me One', sans-serif; header_inverse = false relbar_inverse = false inner_theme = false inner_theme_name = bootswatch-amelia twython-3.8.2+dfsg.orig/MANIFEST.in0000644000175000017500000000030713641600012016175 0ustar noahfxnoahfxinclude README.md HISTORY.md LICENSE requirements.txt recursive-include docs * prune docs/_build recursive-include examples *.py recursive-include tests *.py recursive-include tests/tweets *.json twython-3.8.2+dfsg.orig/tests/0000755000175000017500000000000013642213174015613 5ustar noahfxnoahfxtwython-3.8.2+dfsg.orig/tests/config.py0000644000175000017500000000157213641551325017441 0ustar noahfxnoahfx# -*- coding: utf-8 -*- import os import sys import unittest app_key = os.environ.get('APP_KEY') app_secret = os.environ.get('APP_SECRET') oauth_token = os.environ.get('OAUTH_TOKEN') oauth_token_secret = os.environ.get('OAUTH_TOKEN_SECRET') access_token = os.environ.get('ACCESS_TOKEN') screen_name = os.environ.get('SCREEN_NAME', '__twython__') # Protected Account you ARE following and they ARE following you protected_twitter_1 = os.environ.get('PROTECTED_TWITTER_1', 'TwythonSecure1') # Protected Account you ARE NOT following protected_twitter_2 = os.environ.get('PROTECTED_TWITTER_2', 'TwythonSecure2') # Test Ids test_tweet_id = os.environ.get('TEST_TWEET_ID', '318577428610031617') test_list_slug = os.environ.get('TEST_LIST_SLUG', 'team') test_list_owner_screen_name = os.environ.get('TEST_LIST_OWNER_SCREEN_NAME', 'twitterapi') twython-3.8.2+dfsg.orig/tests/test_streaming.py0000644000175000017500000000330712670232560021220 0ustar noahfxnoahfxfrom twython import TwythonStreamer, TwythonStreamError from .config import ( app_key, app_secret, oauth_token, oauth_token_secret, unittest ) class TwythonStreamTestCase(unittest.TestCase): def setUp(self): class MyStreamer(TwythonStreamer): def on_success(self, data): self.disconnect() def on_error(self, status_code, data): raise TwythonStreamError(data) self.api = MyStreamer(app_key, app_secret, oauth_token, oauth_token_secret) client_args = { 'headers': { 'User-Agent': '__twython__ Stream Test' } } # Initialize with header for coverage checking for User-Agent self.api_with_header = MyStreamer(app_key, app_secret, oauth_token, oauth_token_secret, client_args=client_args) @unittest.skip('skipping non-updated test') def test_stream_status_filter(self): self.api.statuses.filter(track='twitter') @unittest.skip('skipping non-updated test') def test_stream_status_sample(self): self.api.statuses.sample() @unittest.skip('skipping non-updated test') def test_stream_status_firehose(self): self.assertRaises(TwythonStreamError, self.api.statuses.firehose, track='twitter') @unittest.skip('skipping non-updated test') def test_stream_site(self): self.assertRaises(TwythonStreamError, self.api.site, follow='twitter') @unittest.skip('skipping non-updated test') def test_stream_user(self): self.api.user(track='twitter') twython-3.8.2+dfsg.orig/tests/tweets/0000755000175000017500000000000013642213174017126 5ustar noahfxnoahfxtwython-3.8.2+dfsg.orig/tests/tweets/identical_urls.json0000644000175000017500000000124213641543451023024 0ustar noahfxnoahfx{ "entities":{ "hashtags":[ ], "user_mentions":[ ], "symbols":[ ], "urls":[ { "display_url":"buff.ly/2sEhrgO", "expanded_url":"http://buff.ly/2sEhrgO", "indices":[ 42, 65 ], "url":"https://t.co/W0uArTMk9N" }, { "display_url":"buff.ly/2sEhrgO", "expanded_url":"http://buff.ly/2sEhrgO", "indices":[ 101, 124 ], "url":"https://t.co/W0uArTMk9N" } ] }, "full_text":"Use Cases, Trials and Making 5G a Reality https://t.co/W0uArTMk9N #5G #innovation via @5GWorldSeries https://t.co/W0uArTMk9N" } twython-3.8.2+dfsg.orig/tests/tweets/basic.json0000644000175000017500000001021613641543451021105 0ustar noahfxnoahfx{ "contributors":null, "truncated":false, "text":"http://t.co/FCmXyI6VHd is a #cool site, lol! @mikehelmick shd #checkitout. Love, @__twython__ https://t.co/67pwRvY6z9 http://t.co/N6InAO4B71", "in_reply_to_status_id":null, "id":349683012054683648, "favorite_count":0, "source":"Twitter Web Client", "retweeted":false, "coordinates":null, "entities":{ "symbols":[ ], "user_mentions":[ { "id":29251354, "indices":[ 45, 57 ], "id_str":"29251354", "screen_name":"mikehelmick", "name":"Mike Helmick" }, { "id":1431865928, "indices":[ 81, 93 ], "id_str":"1431865928", "screen_name":"__twython__", "name":"Twython" } ], "hashtags":[ { "indices":[ 28, 33 ], "text":"cool" }, { "indices":[ 62, 73 ], "text":"checkitout" } ], "urls":[ { "url":"http://t.co/FCmXyI6VHd", "indices":[ 0, 22 ], "expanded_url":"http://google.com", "display_url":"google.com" }, { "url":"https://t.co/67pwRvY6z9", "indices":[ 94, 117 ], "expanded_url":"https://github.com", "display_url":"github.com" } ], "media":[ { "id":537884378513162240, "id_str":"537884378513162240", "indices":[ 118, 140 ], "media_url":"http://pbs.twimg.com/media/B3by_g-CQAAhrO5.jpg", "media_url_https":"https://pbs.twimg.com/media/B3by_g-CQAAhrO5.jpg", "url":"http://t.co/N6InAO4B71", "display_url":"pic.twitter.com/N6InAO4B71", "expanded_url":"http://twitter.com/pingofglitch/status/537884380060844032/photo/1", "type":"photo", "sizes":{ "large":{ "w":1024, "h":640, "resize":"fit" }, "thumb":{ "w":150, "h":150, "resize":"crop" }, "medium":{ "w":600, "h":375, "resize":"fit" }, "small":{ "w":340, "h":212, "resize":"fit" } } } ] }, "in_reply_to_screen_name":null, "id_str":"349683012054683648", "retweet_count":0, "in_reply_to_user_id":null, "favorited":false, "user":{ "follow_request_sent":false, "profile_use_background_image":true, "default_profile_image":true, "id":1431865928, "verified":false, "profile_text_color":"333333", "profile_image_url_https":"https://si0.twimg.com/sticky/default_profile_images/default_profile_3_normal.png", "profile_sidebar_fill_color":"DDEEF6", "entities":{ "description":{ "urls":[ ] } }, "followers_count":1, "profile_sidebar_border_color":"C0DEED", "id_str":"1431865928", "profile_background_color":"3D3D3D", "listed_count":0, "profile_background_image_url_https":"https://si0.twimg.com/images/themes/theme1/bg.png", "utc_offset":null, "statuses_count":2, "description":"", "friends_count":1, "location":"", "profile_link_color":"0084B4", "profile_image_url":"http://a0.twimg.com/sticky/default_profile_images/default_profile_3_normal.png", "following":false, "geo_enabled":false, "profile_background_image_url":"http://a0.twimg.com/images/themes/theme1/bg.png", "screen_name":"__twython__", "lang":"en", "profile_background_tile":false, "favourites_count":0, "name":"Twython", "notifications":false, "url":null, "created_at":"Thu May 16 01:11:09 +0000 2013", "contributors_enabled":false, "time_zone":null, "protected":false, "default_profile":false, "is_translator":false }, "geo":null, "in_reply_to_user_id_str":null, "possibly_sensitive":false, "lang":"en", "created_at":"Wed Jun 26 00:18:21 +0000 2013", "in_reply_to_status_id_str":null, "place":null } twython-3.8.2+dfsg.orig/tests/tweets/retweet.json0000644000175000017500000000401313641543451021501 0ustar noahfxnoahfx{ "coordinates":null, "source":"web", "in_reply_to_user_id_str":null, "truncated":false, "in_reply_to_user_id":null, "favorite_count":0, "user":{ "name":"Phil Gyford Test", "screen_name":"philgyfordtest" }, "favorited":false, "retweeted_status":{ "coordinates":null, "source":"Twitter Web Client", "in_reply_to_user_id_str":null, "truncated":false, "in_reply_to_user_id":null, "favorite_count":21, "user":{ "name":"Samuel Pepys", "screen_name":"samuelpepys" }, "favorited":false, "id":917459832885653506, "contributors":null, "in_reply_to_screen_name":null, "geo":null, "in_reply_to_status_id_str":null, "id_str":"917459832885653506", "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ ] }, "in_reply_to_status_id":null, "text":"My aunt and uncle in a very ill humour one with another, but I made shift with much ado to keep them from scolding.", "retweet_count":3, "place":null, "lang":"en", "created_at":"Mon Oct 09 18:40:44 +0000 2017", "is_quote_status":false, "retweeted":false }, "id":917712989649801216, "contributors":null, "in_reply_to_screen_name":null, "geo":null, "in_reply_to_status_id_str":null, "id_str":"917712989649801216", "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ { "id_str":"14475268", "indices":[ 3, 15 ], "name":"Samuel Pepys", "id":14475268, "screen_name":"samuelpepys" } ], "urls":[ ] }, "in_reply_to_status_id":null, "text":"RT @samuelpepys: My aunt and uncle in a very ill humour one with another, but I made shift with much ado to keep them from scolding.", "retweet_count":3, "place":null, "lang":"en", "created_at":"Tue Oct 10 11:26:41 +0000 2017", "is_quote_status":false, "retweeted":false } twython-3.8.2+dfsg.orig/tests/tweets/extended.json0000644000175000017500000001307313641543451021630 0ustar noahfxnoahfx{ "full_text":"Say more about what's happening! Rolling out now: photos, videos, GIFs, polls, and Quote Tweets no longer count toward your 140 characters. https://t.co/I9pUC0NdZC", "truncated":false, "is_quote_status":false, "in_reply_to_status_id":null, "id":777915304261193728, "favorite_count":13856, "contributors":null, "source":"Twitter Web Client", "retweeted":false, "coordinates":null, "entities":{ "symbols":[ ], "user_mentions":[ ], "hashtags":[ ], "urls":[ ], "media":[ { "expanded_url":"https://twitter.com/twitter/status/777915304261193728/photo/1", "sizes":{ "small":{ "h":340, "w":340, "resize":"fit" }, "large":{ "h":700, "w":700, "resize":"fit" }, "medium":{ "h":600, "w":600, "resize":"fit" }, "thumb":{ "h":150, "w":150, "resize":"crop" } }, "url":"https://t.co/I9pUC0NdZC", "media_url_https":"https://pbs.twimg.com/tweet_video_thumb/Csu1TzEVMAAAEv7.jpg", "id_str":"777914712382058496", "indices":[ 140, 163 ], "media_url":"http://pbs.twimg.com/tweet_video_thumb/Csu1TzEVMAAAEv7.jpg", "type":"photo", "id":777914712382058496, "display_url":"pic.twitter.com/I9pUC0NdZC" } ] }, "in_reply_to_screen_name":null, "id_str":"777915304261193728", "display_text_range":[ 0, 139 ], "retweet_count":14767, "in_reply_to_user_id":null, "favorited":false, "user":{ "follow_request_sent":false, "has_extended_profile":false, "profile_use_background_image":true, "id":783214, "verified":true, "profile_text_color":"333333", "profile_image_url_https":"https://pbs.twimg.com/profile_images/767879603977191425/29zfZY6I_normal.jpg", "profile_sidebar_fill_color":"F6F6F6", "is_translator":false, "geo_enabled":true, "entities":{ "url":{ "urls":[ { "url":"http://t.co/5iRhy7wTgu", "indices":[ 0, 22 ], "expanded_url":"http://blog.twitter.com/", "display_url":"blog.twitter.com" } ] }, "description":{ "urls":[ { "url":"https://t.co/qq1HEzvnrA", "indices":[ 84, 107 ], "expanded_url":"http://support.twitter.com", "display_url":"support.twitter.com" } ] } }, "followers_count":56827498, "protected":false, "location":"San Francisco, CA", "default_profile_image":false, "id_str":"783214", "lang":"en", "utc_offset":-25200, "statuses_count":3161, "description":"Your official source for news, updates and tips from Twitter, Inc. Need help? Visit https://t.co/qq1HEzvnrA.", "friends_count":145, "profile_link_color":"226699", "profile_image_url":"http://pbs.twimg.com/profile_images/767879603977191425/29zfZY6I_normal.jpg", "notifications":false, "profile_background_image_url_https":"https://pbs.twimg.com/profile_background_images/657090062/l1uqey5sy82r9ijhke1i.png", "profile_background_color":"ACDED6", "profile_banner_url":"https://pbs.twimg.com/profile_banners/783214/1471929200", "profile_background_image_url":"http://pbs.twimg.com/profile_background_images/657090062/l1uqey5sy82r9ijhke1i.png", "name":"Twitter", "is_translation_enabled":false, "profile_background_tile":true, "favourites_count":2332, "screen_name":"twitter", "url":"http://t.co/5iRhy7wTgu", "created_at":"Tue Feb 20 14:35:54 +0000 2007", "contributors_enabled":false, "time_zone":"Pacific Time (US & Canada)", "profile_sidebar_border_color":"FFFFFF", "default_profile":false, "following":false, "listed_count":90445 }, "geo":null, "in_reply_to_user_id_str":null, "possibly_sensitive":false, "possibly_sensitive_appealable":false, "lang":"en", "created_at":"Mon Sep 19 17:00:36 +0000 2016", "in_reply_to_status_id_str":null, "place":null, "extended_entities":{ "media":[ { "expanded_url":"https://twitter.com/twitter/status/777915304261193728/photo/1", "display_url":"pic.twitter.com/I9pUC0NdZC", "url":"https://t.co/I9pUC0NdZC", "media_url_https":"https://pbs.twimg.com/tweet_video_thumb/Csu1TzEVMAAAEv7.jpg", "video_info":{ "aspect_ratio":[ 1, 1 ], "variants":[ { "url":"https://pbs.twimg.com/tweet_video/Csu1TzEVMAAAEv7.mp4", "bitrate":0, "content_type":"video/mp4" } ] }, "id_str":"777914712382058496", "sizes":{ "small":{ "h":340, "w":340, "resize":"fit" }, "large":{ "h":700, "w":700, "resize":"fit" }, "medium":{ "h":600, "w":600, "resize":"fit" }, "thumb":{ "h":150, "w":150, "resize":"crop" } }, "indices":[ 140, 163 ], "type":"animated_gif", "id":777914712382058496, "media_url":"http://pbs.twimg.com/tweet_video_thumb/Csu1TzEVMAAAEv7.jpg" } ] } } twython-3.8.2+dfsg.orig/tests/tweets/media.json0000644000175000017500000001206613641543451021110 0ustar noahfxnoahfx{ "contributors":null, "truncated":false, "is_quote_status":false, "in_reply_to_status_id":null, "id":905105588279013377, "favorite_count":10, "full_text":"I made some D3.js charts showing the years covered by books in a series compared to their publishing dates https://t.co/2yUmmn3TOc https://t.co/OwNc6uJklg", "source":"Twitter Web Client", "retweeted":false, "coordinates":null, "entities":{ "symbols":[ ], "user_mentions":[ ], "hashtags":[ ], "urls":[ { "url":"https://t.co/2yUmmn3TOc", "indices":[ 107, 130 ], "expanded_url":"http://www.gyford.com/phil/writing/2017/09/05/book-series-charts.php", "display_url":"gyford.com/phil/writing/2\u2026" } ], "media":[ { "expanded_url":"https://twitter.com/philgyford/status/905105588279013377/photo/1", "display_url":"pic.twitter.com/OwNc6uJklg", "url":"https://t.co/OwNc6uJklg", "media_url_https":"https://pbs.twimg.com/media/DI-UuNlWAAA_cvz.jpg", "id_str":"905105571765944320", "sizes":{ "small":{ "h":256, "resize":"fit", "w":680 }, "large":{ "h":376, "resize":"fit", "w":1000 }, "medium":{ "h":376, "resize":"fit", "w":1000 }, "thumb":{ "h":150, "resize":"crop", "w":150 } }, "indices":[ 131, 154 ], "type":"photo", "id":905105571765944320, "media_url":"http://pbs.twimg.com/media/DI-UuNlWAAA_cvz.jpg" } ] }, "in_reply_to_screen_name":null, "in_reply_to_user_id":null, "display_text_range":[ 0, 130 ], "retweet_count":1, "id_str":"905105588279013377", "favorited":false, "user":{ "screen_name":"philgyford", "name":"Phil Gyford" }, "geo":null, "in_reply_to_user_id_str":null, "possibly_sensitive":false, "possibly_sensitive_appealable":false, "lang":"en", "created_at":"Tue Sep 05 16:29:22 +0000 2017", "in_reply_to_status_id_str":null, "place":null, "extended_entities":{ "media":[ { "expanded_url":"https://twitter.com/philgyford/status/905105588279013377/photo/1", "display_url":"pic.twitter.com/OwNc6uJklg", "url":"https://t.co/OwNc6uJklg", "media_url_https":"https://pbs.twimg.com/media/DI-UuNlWAAA_cvz.jpg", "id_str":"905105571765944320", "sizes":{ "small":{ "h":256, "resize":"fit", "w":680 }, "large":{ "h":376, "resize":"fit", "w":1000 }, "medium":{ "h":376, "resize":"fit", "w":1000 }, "thumb":{ "h":150, "resize":"crop", "w":150 } }, "indices":[ 131, 154 ], "type":"photo", "id":905105571765944320, "media_url":"http://pbs.twimg.com/media/DI-UuNlWAAA_cvz.jpg" }, { "expanded_url":"https://twitter.com/philgyford/status/905105588279013377/photo/1", "display_url":"pic.twitter.com/OwNc6uJklg", "url":"https://t.co/OwNc6uJklg", "media_url_https":"https://pbs.twimg.com/media/DI-UuQbXUAQ1WlR.jpg", "id_str":"905105572529393668", "sizes":{ "large":{ "h":399, "resize":"fit", "w":1000 }, "small":{ "h":271, "resize":"fit", "w":680 }, "medium":{ "h":399, "resize":"fit", "w":1000 }, "thumb":{ "h":150, "resize":"crop", "w":150 } }, "indices":[ 131, 154 ], "type":"photo", "id":905105572529393668, "media_url":"http://pbs.twimg.com/media/DI-UuQbXUAQ1WlR.jpg" }, { "expanded_url":"https://twitter.com/philgyford/status/905105588279013377/photo/1", "display_url":"pic.twitter.com/OwNc6uJklg", "url":"https://t.co/OwNc6uJklg", "media_url_https":"https://pbs.twimg.com/media/DI-UuTIXcAA-t1_.jpg", "id_str":"905105573255016448", "sizes":{ "small":{ "h":195, "resize":"fit", "w":680 }, "large":{ "h":287, "resize":"fit", "w":1000 }, "medium":{ "h":287, "resize":"fit", "w":1000 }, "thumb":{ "h":150, "resize":"crop", "w":150 } }, "indices":[ 131, 154 ], "type":"photo", "id":905105573255016448, "media_url":"http://pbs.twimg.com/media/DI-UuTIXcAA-t1_.jpg" } ] } } twython-3.8.2+dfsg.orig/tests/tweets/quoted.json0000644000175000017500000000422713641543451021332 0ustar noahfxnoahfx{ "contributors":null, "truncated":false, "text":"Here\u2019s a quoted tweet. https://t.co/3neKzof0gT", "is_quote_status":true, "in_reply_to_status_id":null, "id":917706313785905157, "favorite_count":0, "source":"Twitter Web Client", "quoted_status_id":917699069916729344, "retweeted":false, "coordinates":null, "quoted_status":{ "contributors":null, "truncated":false, "text":"The quoted tweet text.", "is_quote_status":false, "in_reply_to_status_id":null, "id":917699069916729344, "favorite_count":1, "source":"Twitter Web Client", "retweeted":false, "coordinates":null, "entities":{ "symbols":[ ], "user_mentions":[ ], "hashtags":[ ], "urls":[ ] }, "in_reply_to_screen_name":null, "in_reply_to_user_id":null, "retweet_count":0, "id_str":"917699069916729344", "favorited":false, "user":{ "screen_name":"philgyford", "name":"Phil Gyford" }, "geo":null, "in_reply_to_user_id_str":null, "lang":"ht", "created_at":"Tue Oct 10 10:31:22 +0000 2017", "in_reply_to_status_id_str":null, "place":null }, "entities":{ "symbols":[ ], "user_mentions":[ ], "hashtags":[ ], "urls":[ { "url":"https://t.co/3neKzof0gT", "indices":[ 23, 46 ], "expanded_url":"https://twitter.com/philgyford/status/917699069916729344", "display_url":"twitter.com/philgyford/sta\u2026" } ] }, "in_reply_to_screen_name":null, "in_reply_to_user_id":null, "retweet_count":0, "id_str":"917706313785905157", "favorited":false, "user":{ "screen_name":"philgyfordtest", "name":"Phil Gyford Test" }, "geo":null, "in_reply_to_user_id_str":null, "possibly_sensitive":false, "possibly_sensitive_appealable":false, "lang":"en", "created_at":"Tue Oct 10 11:00:10 +0000 2017", "quoted_status_id_str":"917699069916729344", "in_reply_to_status_id_str":null, "place":null } twython-3.8.2+dfsg.orig/tests/tweets/entities_with_prefix.json0000644000175000017500000000346313641543451024266 0ustar noahfxnoahfx{ "created_at":"Sat Jan 06 18:56:35 +0000 2018", "id":949716340755091458, "id_str":"949716340755091458", "full_text":"@philgyford This is a test for @visionphil that includes a link https://t.co/sKw4J3A8SZ and #hashtag and X for good measure AND that is longer than 140 characters. https://t.co/jnQdy7Zg7u", "truncated":false, "display_text_range":[ 12, 187 ], "entities":{ "hashtags":[ { "text":"hashtag", "indices":[ 92, 100 ] } ], "symbols":[ ], "user_mentions":[ { "screen_name":"philgyford", "name":"Phil Gyford", "id":12552, "id_str":"12552", "indices":[ 0, 11 ] }, { "screen_name":"visionphil", "name":"Vision Phil", "id":104456050, "id_str":"104456050", "indices":[ 31, 42 ] } ], "urls":[ { "url":"https://t.co/sKw4J3A8SZ", "expanded_url":"http://example.org", "display_url":"example.org", "indices":[ 64, 87 ] }, { "url":"https://t.co/jnQdy7Zg7u", "expanded_url":"http://example.com", "display_url":"example.com", "indices":[ 164, 187 ] } ] }, "source":"Tweetbot for Mac", "in_reply_to_status_id":948561036889722880, "in_reply_to_status_id_str":"948561036889722880", "in_reply_to_user_id":12552, "in_reply_to_user_id_str":"12552", "in_reply_to_screen_name":"philgyford", "user":{ "id":2030131, "id_str":"2030131" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":0, "favorite_count":0, "favorited":false, "retweeted":false, "possibly_sensitive":false, "lang":"en" } twython-3.8.2+dfsg.orig/tests/tweets/compat.json0000644000175000017500000000235213641543451021311 0ustar noahfxnoahfx{ "contributors":null, "truncated":true, "text":"Say more about what's happening! Rolling out now: photos, videos, GIFs, polls, and Quote Tweets no longer count tow\u2026 https://t.co/SRmsuks2ru", "is_quote_status":false, "in_reply_to_status_id":null, "id":777915304261193728, "favorite_count":13856, "source":"Twitter Web Client", "retweeted":false, "coordinates":null, "entities":{ "symbols":[ ], "user_mentions":[ ], "hashtags":[ ], "urls":[ { "url":"https://t.co/SRmsuks2ru", "indices":[ 117, 140 ], "expanded_url":"https://twitter.com/i/web/status/777915304261193728", "display_url":"twitter.com/i/web/status/7\u2026" } ] }, "in_reply_to_screen_name":null, "id_str":"777915304261193728", "retweet_count":14767, "in_reply_to_user_id":null, "favorited":false, "user":{ "name":"Twitter", "screen_name":"twitter" }, "geo":null, "in_reply_to_user_id_str":null, "possibly_sensitive":false, "possibly_sensitive_appealable":false, "lang":"en", "created_at":"Mon Sep 19 17:00:36 +0000 2016", "in_reply_to_status_id_str":null, "place":null } twython-3.8.2+dfsg.orig/tests/tweets/symbols.json0000644000175000017500000000215513641543451021517 0ustar noahfxnoahfx{ "text":"Some symbols: $AAPL and $PEP and $ANOTHER and $A.", "contributors":null, "geo":null, "favorited":true, "in_reply_to_user_id_str":null, "user":{ "screen_name":"philgyfordtest", "name":"Phil Gyford Test" }, "in_reply_to_user_id":null, "retweeted":false, "coordinates":null, "place":null, "in_reply_to_status_id":null, "lang":"en", "in_reply_to_status_id_str":null, "truncated":false, "retweet_count":0, "is_quote_status":false, "id":662694880657989632, "id_str":"662694880657989632", "in_reply_to_screen_name":null, "favorite_count":1, "entities":{ "hashtags":[ ], "user_mentions":[ ], "symbols":[ { "indices":[ 14, 19 ], "text":"AAPL" }, { "indices":[ 24, 28 ], "text":"PEP" }, { "indices":[ 46, 48 ], "text":"A" } ], "urls":[ ] }, "created_at":"Fri Nov 06 18:15:46 +0000 2015", "source":"Twitter Web Client" } twython-3.8.2+dfsg.orig/tests/tweets/reply.json0000644000175000017500000000231213641543451021155 0ustar noahfxnoahfx{ "display_text_range":[ 12, 114 ], "in_reply_to_status_id_str":"742374355531923456", "source":"Twitter Web Client", "geo":null, "full_text":"@philgyford Here\u2019s a test tweet that goes on as much as possible and includes an image. Hi to my fans in testland! https://t.co/tzhyk2QWSr", "extended_entities":{ "media":[ ] }, "id_str":"300", "in_reply_to_status_id":742374355531923456, "id":300, "in_reply_to_screen_name":"philgyford", "retweet_count":0, "user":{ }, "created_at":"Mon Jun 13 15:48:06 +0000 2016", "lang":"en", "favorite_count":0, "coordinates":null, "place":null, "contributors":null, "in_reply_to_user_id":12552, "in_reply_to_user_id_str":"12552", "retweeted":false, "favorited":false, "truncated":false, "entities":{ "user_mentions":[ { "id_str":"12552", "id":12552, "screen_name":"philgyford", "name":"Phil Gyford", "indices":[ 0, 11 ] } ], "media":[ ], "hashtags":[ ], "symbols":[ ], "urls":[ ] }, "is_quote_status":false, "possibly_sensitive":false } twython-3.8.2+dfsg.orig/tests/test_core.py0000644000175000017500000003167413641543451020172 0ustar noahfxnoahfx# -*- coding: utf-8 -*- from twython import Twython, TwythonError, TwythonAuthError, TwythonRateLimitError from .config import unittest import responses import requests from twython.compat import is_py2 if is_py2: from StringIO import StringIO else: from io import StringIO try: import unittest.mock as mock except ImportError: import mock class TwythonAPITestCase(unittest.TestCase): def setUp(self): self.api = Twython('', '', '', '') def get_url(self, endpoint): """Convenience function for mapping from endpoint to URL""" return '%s/%s.json' % (self.api.api_url % self.api.api_version, endpoint) def register_response(self, method, url, body='{}', match_querystring=False, status=200, adding_headers=None, stream=False, content_type='application/json; charset=utf-8'): """Wrapper function for responses for simpler unit tests""" # responses uses BytesIO to hold the body so it needs to be in bytes if not is_py2: body = bytes(body, 'UTF-8') responses.add(method, url, body, match_querystring, status, adding_headers, stream, content_type) @responses.activate def test_request_should_handle_full_endpoint(self): """Test that request() accepts a full URL for the endpoint argument""" url = 'https://api.twitter.com/1.1/search/tweets.json' self.register_response(responses.GET, url) self.api.request(url) self.assertEqual(1, len(responses.calls)) self.assertEqual(url, responses.calls[0].request.url) @responses.activate def test_request_should_handle_relative_endpoint(self): """Test that request() accepts a twitter endpoint name for the endpoint argument""" url = 'https://api.twitter.com/1.1/search/tweets.json' self.register_response(responses.GET, url) self.api.request('search/tweets', version='1.1') self.assertEqual(1, len(responses.calls)) self.assertEqual(url, responses.calls[0].request.url) @responses.activate def test_request_should_post_request_regardless_of_case(self): """Test that request() accepts the HTTP method name regardless of case""" url = 'https://api.twitter.com/1.1/statuses/update.json' self.register_response(responses.POST, url) self.api.request(url, method='POST') self.api.request(url, method='post') self.assertEqual(2, len(responses.calls)) self.assertEqual('POST', responses.calls[0].request.method) self.assertEqual('POST', responses.calls[1].request.method) @responses.activate def test_request_should_throw_exception_with_invalid_http_method(self): """Test that request() throws an exception when an invalid HTTP method is passed""" # TODO(cash): should Twython catch the AttributeError and throw a TwythonError self.assertRaises(AttributeError, self.api.request, endpoint='search/tweets', method='INVALID') @responses.activate def test_request_should_encode_boolean_as_lowercase_string(self): """Test that request() encodes a boolean parameter as a lowercase string""" endpoint = 'search/tweets' url = self.get_url(endpoint) self.register_response(responses.GET, url) self.api.request(endpoint, params={'include_entities': True}) self.api.request(endpoint, params={'include_entities': False}) self.assertEqual(url + '?include_entities=true', responses.calls[0].request.url) self.assertEqual(url + '?include_entities=false', responses.calls[1].request.url) @responses.activate def test_request_should_handle_string_or_number_parameter(self): """Test that request() encodes a numeric or string parameter correctly""" endpoint = 'search/tweets' url = self.get_url(endpoint) self.register_response(responses.GET, url) self.api.request(endpoint, params={'lang': 'es'}) self.api.request(endpoint, params={'count': 50}) self.assertEqual(url + '?lang=es', responses.calls[0].request.url) self.assertEqual(url + '?count=50', responses.calls[1].request.url) @responses.activate def test_request_should_encode_list_of_strings_as_string(self): """Test that request() encodes a list of strings as a comma-separated string""" endpoint = 'search/tweets' url = self.get_url(endpoint) location = ['37.781157', '-122.39872', '1mi'] self.register_response(responses.GET, url) self.api.request(endpoint, params={'geocode': location}) # requests url encodes the parameters so , is %2C self.assertEqual(url + '?geocode=37.781157%2C-122.39872%2C1mi', responses.calls[0].request.url) @responses.activate def test_request_should_encode_numeric_list_as_string(self): """Test that request() encodes a list of numbers as a comma-separated string""" endpoint = 'search/tweets' url = self.get_url(endpoint) location = [37.781157, -122.39872, '1mi'] self.register_response(responses.GET, url) self.api.request(endpoint, params={'geocode': location}) self.assertEqual(url + '?geocode=37.781157%2C-122.39872%2C1mi', responses.calls[0].request.url) @responses.activate def test_request_should_ignore_bad_parameter(self): """Test that request() ignores unexpected parameter types""" endpoint = 'search/tweets' url = self.get_url(endpoint) self.register_response(responses.GET, url) self.api.request(endpoint, params={'geocode': self}) self.assertEqual(url, responses.calls[0].request.url) @responses.activate def test_request_should_handle_file_as_parameter(self): """Test that request() pulls a file out of params for requests lib""" endpoint = 'account/update_profile_image' url = self.get_url(endpoint) self.register_response(responses.POST, url) mock_file = StringIO("Twython test image") self.api.request(endpoint, method='POST', params={'image': mock_file}) self.assertIn(b'filename="image"', responses.calls[0].request.body) self.assertIn(b"Twython test image", responses.calls[0].request.body) @responses.activate def test_request_should_put_params_in_body_when_post(self): """Test that request() passes params as data when the request is a POST""" endpoint = 'statuses/update' url = self.get_url(endpoint) self.register_response(responses.POST, url) self.api.request(endpoint, method='POST', params={'status': 'this is a test'}) self.assertIn(b'status=this+is+a+test', responses.calls[0].request.body) self.assertNotIn('status=this+is+a+test', responses.calls[0].request.url) @responses.activate def test_get_uses_get_method(self): """Test Twython generic GET request works""" endpoint = 'account/verify_credentials' url = self.get_url(endpoint) self.register_response(responses.GET, url) self.api.get(endpoint) self.assertEqual(1, len(responses.calls)) self.assertEqual(url, responses.calls[0].request.url) @responses.activate def test_post_uses_post_method(self): """Test Twython generic POST request works""" endpoint = 'statuses/update' url = self.get_url(endpoint) self.register_response(responses.POST, url) self.api.post(endpoint, params={'status': 'I love Twython!'}) self.assertEqual(1, len(responses.calls)) self.assertEqual(url, responses.calls[0].request.url) def test_raise_twython_error_on_request_exception(self): """Test if TwythonError is raised by a RequestException""" with mock.patch.object(requests.Session, 'get') as get_mock: # mocking an ssl cert error get_mock.side_effect = requests.RequestException("hostname 'example.com' doesn't match ...") self.assertRaises(TwythonError, self.api.get, 'https://example.com') @responses.activate def test_request_should_get_convert_json_to_data(self): """Test that Twython converts JSON data to a Python object""" endpoint = 'statuses/show' url = self.get_url(endpoint) self.register_response(responses.GET, url, body='{"id": 210462857140252672}') data = self.api.request(endpoint, params={'id': 210462857140252672}) self.assertEqual({'id': 210462857140252672}, data) @responses.activate def test_request_should_raise_exception_with_invalid_json(self): """Test that Twython handles invalid JSON (though Twitter should not return it)""" endpoint = 'statuses/show' url = self.get_url(endpoint) self.register_response(responses.GET, url, body='{"id: 210462857140252672}') self.assertRaises(TwythonError, self.api.request, endpoint, params={'id': 210462857140252672}) @responses.activate def test_request_should_handle_401(self): """Test that Twython raises an auth error on 401 error""" endpoint = 'statuses/home_timeline' url = self.get_url(endpoint) self.register_response(responses.GET, url, body='{"errors":[{"message":"Error"}]}', status=401) self.assertRaises(TwythonAuthError, self.api.request, endpoint) @responses.activate def test_request_should_handle_400_for_missing_auth_data(self): """Test that Twython raises an auth error on 400 error when no oauth data sent""" endpoint = 'statuses/home_timeline' url = self.get_url(endpoint) self.register_response(responses.GET, url, body='{"errors":[{"message":"Bad Authentication data"}]}', status=400) self.assertRaises(TwythonAuthError, self.api.request, endpoint) @responses.activate def test_request_should_handle_400_that_is_not_auth_related(self): """Test that Twython raises a normal error on 400 error when unrelated to authorization""" endpoint = 'statuses/home_timeline' url = self.get_url(endpoint) self.register_response(responses.GET, url, body='{"errors":[{"message":"Bad request"}]}', status=400) self.assertRaises(TwythonError, self.api.request, endpoint) @responses.activate def test_request_should_handle_rate_limit(self): """Test that Twython raises an rate limit error on 429""" endpoint = 'statuses/home_timeline' url = self.get_url(endpoint) self.register_response(responses.GET, url, body='{"errors":[{"message":"Rate Limit"}]}', status=429) self.assertRaises(TwythonRateLimitError, self.api.request, endpoint) @responses.activate def test_get_lastfunction_header_should_return_header(self): """Test getting last specific header of the last API call works""" endpoint = 'statuses/home_timeline' url = self.get_url(endpoint) self.register_response(responses.GET, url, adding_headers={'x-rate-limit-remaining': '37'}) self.api.get(endpoint) value = self.api.get_lastfunction_header('x-rate-limit-remaining') self.assertEqual('37', value) value2 = self.api.get_lastfunction_header('does-not-exist') self.assertIsNone(value2) value3 = self.api.get_lastfunction_header('not-there-either', '96') self.assertEqual('96', value3) def test_get_lastfunction_header_should_raise_error_when_no_previous_call(self): """Test attempting to get a header when no API call was made raises a TwythonError""" self.assertRaises(TwythonError, self.api.get_lastfunction_header, 'no-api-call-was-made') @responses.activate def test_sends_correct_accept_encoding_header(self): """Test that Twython accepts compressed data.""" endpoint = 'statuses/home_timeline' url = self.get_url(endpoint) self.register_response(responses.GET, url) self.api.get(endpoint) self.assertEqual(b'gzip, deflate', responses.calls[0].request.headers['Accept-Encoding']) # Static methods def test_construct_api_url(self): """Test constructing a Twitter API url works as we expect""" url = 'https://api.twitter.com/1.1/search/tweets.json' constructed_url = self.api.construct_api_url(url, q='#twitter') self.assertEqual(constructed_url, 'https://api.twitter.com/1.1/search/tweets.json?q=%23twitter') def test_encode(self): """Test encoding UTF-8 works""" self.api.encode('Twython is awesome!') def test_cursor_requires_twython_function(self): """Test that cursor() raises when called without a Twython function""" def init_and_iterate_cursor(*args, **kwargs): cursor = self.api.cursor(*args, **kwargs) return next(cursor) non_function = object() non_twython_function = lambda x: x self.assertRaises(TypeError, init_and_iterate_cursor, non_function) self.assertRaises(TwythonError, init_and_iterate_cursor, non_twython_function) twython-3.8.2+dfsg.orig/tests/test_html_for_tweet.py0000644000175000017500000001673613641543451022266 0ustar noahfxnoahfx# -*- coding: utf-8 -*- import json import os from twython import Twython, TwythonError from .config import unittest class TestHtmlForTweetTestCase(unittest.TestCase): def setUp(self): self.api = Twython('', '', '', '') def load_tweet(self, name): f = open(os.path.join( os.path.dirname(__file__), 'tweets', '%s.json' % name )) tweet = json.load(f) f.close() return tweet def test_basic(self): """Test HTML for Tweet returns what we want""" tweet_object = self.load_tweet('basic') tweet_text = self.api.html_for_tweet(tweet_object) self.assertEqual(tweet_text, 'google.com is a #cool site, lol! @mikehelmick shd #checkitout. Love, @__twython__ github.com pic.twitter.com/N6InAO4B71') def test_reply(self): """Test HTML for Tweet links the replied-to username.""" tweet_object = self.load_tweet('reply') tweet_text = self.api.html_for_tweet(tweet_object) self.assertEqual(tweet_text, u'@philgyford Here’s a test tweet that goes on as much as possible and includes an image. Hi to my fans in testland! https://t.co/tzhyk2QWSr') def test_expanded_url(self): """Test using expanded url in HTML for Tweet displays full urls""" tweet_object = self.load_tweet('basic') tweet_text = self.api.html_for_tweet(tweet_object, use_expanded_url=True) # Make sure full url is in HTML self.assertTrue('http://google.com' in tweet_text) def test_short_url(self): """Test using expanded url in HTML for Tweet displays full urls""" tweet_object = self.load_tweet('basic') tweet_text = self.api.html_for_tweet(tweet_object, False) # Make sure HTML doesn't contain the display OR expanded url self.assertTrue('http://google.com' not in tweet_text) self.assertTrue('google.com' not in tweet_text) def test_identical_urls(self): """If the 'url's for different url entities are identical, they should link correctly.""" tweet_object = self.load_tweet('identical_urls') tweet_text = self.api.html_for_tweet(tweet_object) self.assertEqual(tweet_text, u'Use Cases, Trials and Making 5G a Reality buff.ly/2sEhrgO #5G #innovation via @5GWorldSeries buff.ly/2sEhrgO') def test_symbols(self): tweet_object = self.load_tweet('symbols') tweet_text = self.api.html_for_tweet(tweet_object) # Should only link symbols listed in entities: self.assertTrue('$AAPL' in tweet_text) self.assertTrue('$ANOTHER' not in tweet_text) def test_no_symbols(self): """Should still work if tweet object has no symbols list""" tweet = self.load_tweet('symbols') # Save a copy: symbols = tweet['entities']['symbols'] del tweet['entities']['symbols'] tweet_text = self.api.html_for_tweet(tweet) self.assertTrue('symbols: $AAPL and' in tweet_text) self.assertTrue('and $ANOTHER and $A.' in tweet_text) def test_compatmode(self): tweet_object = self.load_tweet('compat') tweet_text = self.api.html_for_tweet(tweet_object) # link to compat web status link self.assertTrue( u'twitter.com/i/web/status/7…' in tweet_text) def test_extendedmode(self): tweet_object = self.load_tweet('extended') tweet_text = self.api.html_for_tweet(tweet_object) # full tweet rendered with suffix self.assertEqual(tweet_text, 'Say more about what\'s happening! Rolling out now: photos, videos, GIFs, polls, and Quote Tweets no longer count toward your 140 characters. pic.twitter.com/I9pUC0NdZC') def test_entities_with_prefix(self): """ If there is a username mention at the start of a tweet it's in the "prefix" and so isn't part of the main tweet display text. But its length is still counted in the indices of any subsequent mentions, urls, hashtags, etc. """ self.maxDiff = 2200 tweet_object = self.load_tweet('entities_with_prefix') tweet_text = self.api.html_for_tweet(tweet_object) self.assertEqual(tweet_text, u'@philgyford This is a test for @visionphil that includes a link example.org and #hashtag and X for good measure AND that is longer than 140 characters. example.com') def test_media(self): tweet_object = self.load_tweet('media') tweet_text = self.api.html_for_tweet(tweet_object) self.assertEqual( u"""I made some D3.js charts showing the years covered by books in a series compared to their publishing dates gyford.com/phil/writing/2\u2026 pic.twitter.com/OwNc6uJklg""", tweet_text) def test_quoted(self): "With expand_quoted_status=True it should include a quoted tweet." tweet_object = self.load_tweet('quoted') tweet_text = self.api.html_for_tweet(tweet_object, expand_quoted_status=True) self.assertEqual( u"""Here\u2019s a quoted tweet. twitter.com/philgyford/sta\u2026
The quoted tweet text.Phil Gyford@philgyford
""", tweet_text) def test_retweet(self): "With expand_quoted_status=True it should include a quoted tweet." tweet_object = self.load_tweet('retweet') tweet_text = self.api.html_for_tweet(tweet_object) self.assertEqual( u"""My aunt and uncle in a very ill humour one with another, but I made shift with much ado to keep them from scolding.""", tweet_text) twython-3.8.2+dfsg.orig/tests/test_auth.py0000644000175000017500000000657212670232560020177 0ustar noahfxnoahfxfrom twython import Twython, TwythonError, TwythonAuthError from .config import app_key, app_secret, screen_name, unittest class TwythonAuthTestCase(unittest.TestCase): def setUp(self): self.api = Twython(app_key, app_secret) self.bad_api = Twython('BAD_APP_KEY', 'BAD_APP_SECRET') self.bad_api_invalid_tokens = Twython('BAD_APP_KEY', 'BAD_APP_SECRET', 'BAD_OT', 'BAD_OTS') self.oauth2_api = Twython(app_key, app_secret, oauth_version=2) self.oauth2_bad_api = Twython('BAD_APP_KEY', 'BAD_APP_SECRET', oauth_version=2) @unittest.skip('skipping non-updated test') def test_get_authentication_tokens(self): """Test getting authentication tokens works""" self.api.get_authentication_tokens(callback_url='http://google.com/', force_login=True, screen_name=screen_name) @unittest.skip('skipping non-updated test') def test_get_authentication_tokens_bad_tokens(self): """Test getting authentication tokens with bad tokens raises TwythonAuthError""" self.assertRaises(TwythonAuthError, self.bad_api.get_authentication_tokens, callback_url='http://google.com/') @unittest.skip('skipping non-updated test') def test_get_authorized_tokens_bad_tokens(self): """Test getting final tokens fails with wrong tokens""" self.assertRaises(TwythonError, self.bad_api.get_authorized_tokens, 'BAD_OAUTH_VERIFIER') @unittest.skip('skipping non-updated test') def test_get_authorized_tokens_invalid_or_expired_tokens(self): """Test getting final token fails when invalid or expired tokens have been passed""" self.assertRaises(TwythonError, self.bad_api_invalid_tokens.get_authorized_tokens, 'BAD_OAUTH_VERIFIER') @unittest.skip('skipping non-updated test') def test_get_authentication_tokens_raises_error_when_oauth2(self): """Test when API is set for OAuth 2, get_authentication_tokens raises a TwythonError""" self.assertRaises(TwythonError, self.oauth2_api.get_authentication_tokens) @unittest.skip('skipping non-updated test') def test_get_authorization_tokens_raises_error_when_oauth2(self): """Test when API is set for OAuth 2, get_authorized_tokens raises a TwythonError""" self.assertRaises(TwythonError, self.oauth2_api.get_authorized_tokens, 'BAD_OAUTH_VERIFIER') @unittest.skip('skipping non-updated test') def test_obtain_access_token(self): """Test obtaining an Application Only OAuth 2 access token succeeds""" self.oauth2_api.obtain_access_token() @unittest.skip('skipping non-updated test') def test_obtain_access_token_bad_tokens(self): """Test obtaining an Application Only OAuth 2 access token using bad app tokens fails""" self.assertRaises(TwythonAuthError, self.oauth2_bad_api.obtain_access_token) @unittest.skip('skipping non-updated test') def test_obtain_access_token_raises_error_when_oauth1(self): """Test when API is set for OAuth 1, obtain_access_token raises a TwythonError""" self.assertRaises(TwythonError, self.api.obtain_access_token) twython-3.8.2+dfsg.orig/tests/test_endpoints.py0000644000175000017500000005250113641543451021235 0ustar noahfxnoahfxfrom twython import Twython, TwythonError, TwythonAuthError from .config import ( app_key, app_secret, oauth_token, oauth_token_secret, protected_twitter_1, protected_twitter_2, screen_name, test_tweet_id, test_list_slug, test_list_owner_screen_name, access_token, unittest ) import time class TwythonEndpointsTestCase(unittest.TestCase): def setUp(self): client_args = { 'headers': { 'User-Agent': '__twython__ Test' }, 'allow_redirects': False } # This is so we can hit coverage that Twython sets # User-Agent for us if none is supplied oauth2_client_args = { 'headers': {} } self.api = Twython(app_key, app_secret, oauth_token, oauth_token_secret, client_args=client_args) self.oauth2_api = Twython(app_key, access_token=access_token, client_args=oauth2_client_args) # Timelines @unittest.skip('skipping non-updated test') def test_get_mentions_timeline(self): """Test returning mentions timeline for authenticated user succeeds""" self.api.get_mentions_timeline() @unittest.skip('skipping non-updated test') def test_get_user_timeline(self): """Test returning timeline for authenticated user and random user succeeds""" self.api.get_user_timeline() # Authenticated User Timeline self.api.get_user_timeline(screen_name='twitter') # Random User Timeline @unittest.skip('skipping non-updated test') def test_get_protected_user_timeline_following(self): """Test returning a protected user timeline who you are following succeeds""" self.api.get_user_timeline(screen_name=protected_twitter_1) @unittest.skip('skipping non-updated test') def test_get_protected_user_timeline_not_following(self): """Test returning a protected user timeline who you are not following fails and raise a TwythonAuthError""" self.assertRaises(TwythonAuthError, self.api.get_user_timeline, screen_name=protected_twitter_2) @unittest.skip('skipping non-updated test') def test_retweeted_of_me(self): """Test that getting recent tweets by authenticated user that have been retweeted by others succeeds""" self.api.retweeted_of_me() @unittest.skip('skipping non-updated test') def test_get_home_timeline(self): """Test returning home timeline for authenticated user succeeds""" self.api.get_home_timeline() # Tweets @unittest.skip('skipping non-updated test') def test_get_retweets(self): """Test getting retweets of a specific tweet succeeds""" self.api.get_retweets(id=test_tweet_id) @unittest.skip('skipping non-updated test') def test_show_status(self): """Test returning a single status details succeeds""" self.api.show_status(id=test_tweet_id) @unittest.skip('skipping non-updated test') def test_update_and_destroy_status(self): """Test updating and deleting a status succeeds""" status = self.api.update_status(status='Test post just to get \ deleted :( %s' % int(time.time())) self.api.destroy_status(id=status['id_str']) @unittest.skip('skipping non-updated test') def test_get_oembed_tweet(self): """Test getting info to embed tweet on Third Party site succeeds""" self.api.get_oembed_tweet(id='99530515043983360') @unittest.skip('skipping non-updated test') def test_get_retweeters_ids(self): """Test getting ids for people who retweeted a tweet succeeds""" self.api.get_retweeters_ids(id='99530515043983360') # Search @unittest.skip('skipping non-updated test') def test_search(self): """Test searching tweets succeeds""" self.api.search(q='twitter') # Direct Messages @unittest.skip('skipping non-updated test') def test_get_direct_messages(self): """Test getting the authenticated users direct messages succeeds""" self.api.get_direct_messages() @unittest.skip('skipping non-updated test') def test_get_sent_messages(self): """Test getting the authenticated users direct messages they've sent succeeds""" self.api.get_sent_messages() @unittest.skip('skipping non-updated test') def test_send_get_and_destroy_direct_message(self): """Test sending, getting, then destory a direct message succeeds""" message = self.api.send_direct_message(screen_name=protected_twitter_1, text='Hey d00d! %s\ ' % int(time.time())) self.api.get_direct_message(id=message['id_str']) self.api.destroy_direct_message(id=message['id_str']) @unittest.skip('skipping non-updated test') def test_send_direct_message_to_non_follower(self): """Test sending a direct message to someone who doesn't follow you fails""" self.assertRaises(TwythonError, self.api.send_direct_message, screen_name=protected_twitter_2, text='Yo, man! \ %s' % int(time.time())) # Friends & Followers @unittest.skip('skipping non-updated test') def test_get_user_ids_of_blocked_retweets(self): """Test that collection of user_ids that the authenticated user does not want to receive retweets from succeeds""" self.api.get_user_ids_of_blocked_retweets(stringify_ids=True) @unittest.skip('skipping non-updated test') def test_get_friends_ids(self): """Test returning ids of users the authenticated user and then a random user is following succeeds""" self.api.get_friends_ids() self.api.get_friends_ids(screen_name='twitter') @unittest.skip('skipping non-updated test') def test_get_followers_ids(self): """Test returning ids of users the authenticated user and then a random user are followed by succeeds""" self.api.get_followers_ids() self.api.get_followers_ids(screen_name='twitter') @unittest.skip('skipping non-updated test') def test_lookup_friendships(self): """Test returning relationships of the authenticating user to the comma-separated list of up to 100 screen_names or user_ids provided succeeds""" self.api.lookup_friendships(screen_name='twitter,ryanmcgrath') @unittest.skip('skipping non-updated test') def test_get_incoming_friendship_ids(self): """Test returning incoming friendship ids succeeds""" self.api.get_incoming_friendship_ids() @unittest.skip('skipping non-updated test') def test_get_outgoing_friendship_ids(self): """Test returning outgoing friendship ids succeeds""" self.api.get_outgoing_friendship_ids() @unittest.skip('skipping non-updated test') def test_create_friendship(self): """Test creating a friendship succeeds""" self.api.create_friendship(screen_name='justinbieber') @unittest.skip('skipping non-updated test') def test_destroy_friendship(self): """Test destroying a friendship succeeds""" self.api.destroy_friendship(screen_name='justinbieber') @unittest.skip('skipping non-updated test') def test_update_friendship(self): """Test updating friendships succeeds""" self.api.update_friendship(screen_name=protected_twitter_1, retweets='true') self.api.update_friendship(screen_name=protected_twitter_1, retweets=False) @unittest.skip('skipping non-updated test') def test_show_friendships(self): """Test showing specific friendship succeeds""" self.api.show_friendship(target_screen_name=protected_twitter_1) @unittest.skip('skipping non-updated test') def test_get_friends_list(self): """Test getting list of users authenticated user then random user is following succeeds""" self.api.get_friends_list() self.api.get_friends_list(screen_name='twitter') @unittest.skip('skipping non-updated test') def test_get_followers_list(self): """Test getting list of users authenticated user then random user are followed by succeeds""" self.api.get_followers_list() self.api.get_followers_list(screen_name='twitter') # Users @unittest.skip('skipping non-updated test') def test_get_account_settings(self): """Test getting the authenticated user account settings succeeds""" self.api.get_account_settings() @unittest.skip('skipping non-updated test') def test_verify_credentials(self): """Test representation of the authenticated user call succeeds""" self.api.verify_credentials() @unittest.skip('skipping non-updated test') def test_update_account_settings(self): """Test updating a user account settings succeeds""" self.api.update_account_settings(lang='en') @unittest.skip('skipping non-updated test') def test_update_delivery_service(self): """Test updating delivery settings fails because we don't have a mobile number on the account""" self.assertRaises(TwythonError, self.api.update_delivery_service, device='none') @unittest.skip('skipping non-updated test') def test_update_profile(self): """Test updating profile succeeds""" self.api.update_profile(include_entities='true') @unittest.skip('skipping non-updated test') def test_update_profile_colors(self): """Test updating profile colors succeeds""" self.api.update_profile_colors(profile_background_color='3D3D3D') @unittest.skip('skipping non-updated test') def test_list_blocks(self): """Test listing users who are blocked by the authenticated user succeeds""" self.api.list_blocks() @unittest.skip('skipping non-updated test') def test_list_block_ids(self): """Test listing user ids who are blocked by the authenticated user succeeds""" self.api.list_block_ids() @unittest.skip('skipping non-updated test') def test_create_block(self): """Test blocking a user succeeds""" self.api.create_block(screen_name='justinbieber') @unittest.skip('skipping non-updated test') def test_destroy_block(self): """Test unblocking a user succeeds""" self.api.destroy_block(screen_name='justinbieber') @unittest.skip('skipping non-updated test') def test_lookup_user(self): """Test listing a number of user objects succeeds""" self.api.lookup_user(screen_name='twitter,justinbieber') @unittest.skip('skipping non-updated test') def test_show_user(self): """Test showing one user works""" self.api.show_user(screen_name='twitter') @unittest.skip('skipping non-updated test') def test_search_users(self): """Test that searching for users succeeds""" self.api.search_users(q='Twitter API') @unittest.skip('skipping non-updated test') def test_get_contributees(self): """Test returning list of accounts the specified user can contribute to succeeds""" self.api.get_contributees(screen_name='TechCrunch') @unittest.skip('skipping non-updated test') def test_get_contributors(self): """Test returning list of accounts that contribute to the authenticated user fails because we are not a Contributor account""" self.assertRaises(TwythonError, self.api.get_contributors, screen_name=screen_name) @unittest.skip('skipping non-updated test') def test_remove_profile_banner(self): """Test removing profile banner succeeds""" self.api.remove_profile_banner() @unittest.skip('skipping non-updated test') def test_get_profile_banner_sizes(self): """Test getting list of profile banner sizes fails because we have not uploaded a profile banner""" self.assertRaises(TwythonError, self.api.get_profile_banner_sizes) @unittest.skip('skipping non-updated test') def test_list_mutes(self): """Test listing users who are muted by the authenticated user succeeds""" self.api.list_mutes() @unittest.skip('skipping non-updated test') def test_list_mute_ids(self): """Test listing user ids who are muted by the authenticated user succeeds""" self.api.list_mute_ids() @unittest.skip('skipping non-updated test') def test_create_mute(self): """Test muting a user succeeds""" self.api.create_mute(screen_name='justinbieber') @unittest.skip('skipping non-updated test') def test_destroy_mute(self): """Test muting a user succeeds""" self.api.destroy_mute(screen_name='justinbieber') # Suggested Users @unittest.skip('skipping non-updated test') def test_get_user_suggestions_by_slug(self): """Test getting user suggestions by slug succeeds""" self.api.get_user_suggestions_by_slug(slug='twitter') @unittest.skip('skipping non-updated test') def test_get_user_suggestions(self): """Test getting user suggestions succeeds""" self.api.get_user_suggestions() @unittest.skip('skipping non-updated test') def test_get_user_suggestions_statuses_by_slug(self): """Test getting status of suggested users succeeds""" self.api.get_user_suggestions_statuses_by_slug(slug='funny') # Favorites @unittest.skip('skipping non-updated test') def test_get_favorites(self): """Test getting list of favorites for the authenticated user succeeds""" self.api.get_favorites() @unittest.skip('skipping non-updated test') def test_create_and_destroy_favorite(self): """Test creating and destroying a favorite on a tweet succeeds""" self.api.create_favorite(id=test_tweet_id) self.api.destroy_favorite(id=test_tweet_id) # Lists @unittest.skip('skipping non-updated test') def test_show_lists(self): """Test show lists for specified user""" self.api.show_lists(screen_name='twitter') @unittest.skip('skipping non-updated test') def test_get_list_statuses(self): """Test timeline of tweets authored by members of the specified list succeeds""" self.api.get_list_statuses(slug=test_list_slug, owner_screen_name=test_list_owner_screen_name) @unittest.skip('skipping non-updated test') def test_create_update_destroy_list_add_remove_list_members(self): """Test create a list, adding and removing members then deleting the list succeeds""" the_list = self.api.create_list(name='Stuff %s' % int(time.time())) list_id = the_list['id_str'] self.api.update_list(list_id=list_id, name='Stuff Renamed \ %s' % int(time.time())) screen_names = ['johncena', 'xbox'] # Multi add/delete members self.api.create_list_members(list_id=list_id, screen_name=screen_names) self.api.delete_list_members(list_id=list_id, screen_name=screen_names) # Single add/delete member self.api.add_list_member(list_id=list_id, screen_name='justinbieber') self.api.delete_list_member(list_id=list_id, screen_name='justinbieber') self.api.delete_list(list_id=list_id) @unittest.skip('skipping non-updated test') def test_get_list_memberships(self): """Test list of memberhips the authenticated user succeeds""" self.api.get_list_memberships() @unittest.skip('skipping non-updated test') def test_get_list_subscribers(self): """Test list of subscribers of a specific list succeeds""" self.api.get_list_subscribers(slug=test_list_slug, owner_screen_name=test_list_owner_screen_name) @unittest.skip('skipping non-updated test') def test_subscribe_is_subbed_and_unsubscribe_to_list(self): """Test subscribing, is a list sub and unsubbing to list succeeds""" self.api.subscribe_to_list(slug=test_list_slug, owner_screen_name=test_list_owner_screen_name) # Returns 404 if user is not a subscriber self.api.is_list_subscriber(slug=test_list_slug, owner_screen_name=test_list_owner_screen_name, screen_name=screen_name) self.api.unsubscribe_from_list(slug=test_list_slug, owner_screen_name=test_list_owner_screen_name) @unittest.skip('skipping non-updated test') def test_is_list_member(self): """Test returning if specified user is member of a list succeeds""" # Returns 404 if not list member self.api.is_list_member(slug=test_list_slug, owner_screen_name=test_list_owner_screen_name, screen_name='themattharris') @unittest.skip('skipping non-updated test') def test_get_list_members(self): """Test listing members of the specified list succeeds""" self.api.get_list_members(slug=test_list_slug, owner_screen_name=test_list_owner_screen_name) @unittest.skip('skipping non-updated test') def test_get_specific_list(self): """Test getting specific list succeeds""" self.api.get_specific_list(slug=test_list_slug, owner_screen_name=test_list_owner_screen_name) @unittest.skip('skipping non-updated test') def test_get_list_subscriptions(self): """Test collection of the lists the specified user is subscribed to succeeds""" self.api.get_list_subscriptions(screen_name='twitter') @unittest.skip('skipping non-updated test') def test_show_owned_lists(self): """Test collection of lists the specified user owns succeeds""" self.api.show_owned_lists(screen_name='twitter') # Saved Searches @unittest.skip('skipping non-updated test') def test_get_saved_searches(self): """Test getting list of saved searches for authenticated user succeeds""" self.api.get_saved_searches() @unittest.skip('skipping non-updated test') def test_create_get_destroy_saved_search(self): """Test getting list of saved searches for authenticated user succeeds""" saved_search = self.api.create_saved_search(query='#Twitter') saved_search_id = saved_search['id_str'] self.api.show_saved_search(id=saved_search_id) self.api.destroy_saved_search(id=saved_search_id) # Places & Geo @unittest.skip('skipping non-updated test') def test_get_geo_info(self): """Test getting info about a geo location succeeds""" self.api.get_geo_info(place_id='df51dec6f4ee2b2c') @unittest.skip('skipping non-updated test') def test_reverse_geo_code(self): """Test reversing geocode succeeds""" self.api.reverse_geocode(lat='37.76893497', long='-122.42284884') @unittest.skip('skipping non-updated test') def test_search_geo(self): """Test search for places that can be attached to a statuses/update succeeds""" self.api.search_geo(query='Toronto') @unittest.skip('skipping non-updated test') def test_get_similar_places(self): """Test locates places near the given coordinates which are similar in name succeeds""" self.api.get_similar_places(lat='37', long='-122', name='Twitter HQ') # Trends @unittest.skip('skipping non-updated test') def test_get_place_trends(self): """Test getting the top 10 trending topics for a specific WOEID succeeds""" self.api.get_place_trends(id=1) @unittest.skip('skipping non-updated test') def test_get_available_trends(self): """Test returning locations that Twitter has trending topic information for succeeds""" self.api.get_available_trends() @unittest.skip('skipping non-updated test') def test_get_closest_trends(self): """Test getting the locations that Twitter has trending topic information for, closest to a specified location succeeds""" self.api.get_closest_trends(lat='37', long='-122') # Help @unittest.skip('skipping non-updated test') def test_get_twitter_configuration(self): """Test getting Twitter's configuration succeeds""" self.api.get_twitter_configuration() @unittest.skip('skipping non-updated test') def test_get_supported_languages(self): """Test getting languages supported by Twitter succeeds""" self.api.get_supported_languages() @unittest.skip('skipping non-updated test') def test_privacy_policy(self): """Test getting Twitter's Privacy Policy succeeds""" self.api.get_privacy_policy() @unittest.skip('skipping non-updated test') def test_get_tos(self): """Test getting the Twitter Terms of Service succeeds""" self.api.get_tos() @unittest.skip('skipping non-updated test') def test_get_application_rate_limit_status(self): """Test getting application rate limit status succeeds""" self.oauth2_api.get_application_rate_limit_status() twython-3.8.2+dfsg.orig/tests/__init__.py0000644000175000017500000000000012670232560017712 0ustar noahfxnoahfx