Set up default document.
authorpinkrabbit412 <pinkrabbit412@daum.net>
Wed, 30 Oct 2019 19:13:05 +0000 (04:13 +0900)
committerpinkrabbit412 <pinkrabbit412@daum.net>
Wed, 30 Oct 2019 19:13:05 +0000 (04:13 +0900)
in ./docs/

14 files changed:
docs/Makefile [new file with mode: 0644]
docs/api.rst [new file with mode: 0644]
docs/auth_tutorial.rst [new file with mode: 0644]
docs/code_snippet.rst [new file with mode: 0644]
docs/conf.py
docs/cursor_tutorial.rst [new file with mode: 0644]
docs/extended_tweets.rst [new file with mode: 0644]
docs/getting_started.rst [new file with mode: 0644]
docs/index.rst [new file with mode: 0644]
docs/install.rst [new file with mode: 0644]
docs/make.bat [new file with mode: 0644]
docs/parameters.rst [new file with mode: 0644]
docs/running_tests.rst [new file with mode: 0644]
docs/streaming_how_to.rst [new file with mode: 0644]

diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644 (file)
index 0000000..5d97e1a
--- /dev/null
@@ -0,0 +1,99 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = _build
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
+
+help:
+       @echo "Please use \`make <target>' where <target> is one of"
+       @echo "  html      to make standalone HTML files"
+       @echo "  dirhtml   to make HTML files named index.html in directories"
+       @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 "  latex     to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+       @echo "  changes   to make an overview of all changed/added/deprecated items"
+       @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:
+       mkdir -p $(BUILDDIR)/html
+       $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+       @echo
+       @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+       mkdir -p $(BUILDDIR)/dirhtml
+       $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+       @echo
+       @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+pickle:
+       mkdir -p $(BUILDDIR)/pickle
+       $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+       @echo
+       @echo "Build finished; now you can process the pickle files."
+
+json:
+       mkdir -p $(BUILDDIR)/json
+       $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+       @echo
+       @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+       mkdir -p $(BUILDDIR)/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:
+       mkdir -p $(BUILDDIR)/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/tweepy.qhcp"
+       @echo "To view the help file:"
+       @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/tweepy.qhc"
+
+latex:
+       mkdir -p $(BUILDDIR)/latex
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo
+       @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+       @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
+             "run these through (pdf)latex."
+
+changes:
+       mkdir -p $(BUILDDIR)/changes
+       $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+       @echo
+       @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+       mkdir -p $(BUILDDIR)/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:
+       mkdir -p $(BUILDDIR)/doctest
+       $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+       @echo "Testing of doctests in the sources finished, look at the " \
+             "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/docs/api.rst b/docs/api.rst
new file mode 100644 (file)
index 0000000..6c9e9c0
--- /dev/null
@@ -0,0 +1,1205 @@
+.. _api_reference:
+
+.. include:: parameters.rst
+
+API Reference
+=============
+
+This page contains some basic documentation for the Tweepy module.
+
+
+:mod:`tweepy.api` --- Twitter API wrapper
+=========================================
+
+.. class:: API([auth_handler=None], [host='api.twitter.com'], \
+               [search_host='search.twitter.com'], [cache=None], \
+               [api_root='/1'], [search_root=''], [retry_count=0], \
+               [retry_delay=0], [retry_errors=None], [timeout=60], \
+               [parser=ModelParser], [compression=False], \
+               [wait_on_rate_limit=False], [wait_on_rate_limit_notify=False], \
+               [proxy=None])
+
+   This class provides a wrapper for the API as provided by Twitter.
+   The functions provided in this class are listed below.
+
+   :param auth_handler: authentication handler to be used
+   :param host: general API host
+   :param search_host: search API host
+   :param cache: cache backend to use
+   :param api_root: general API path root
+   :param search_root: search API path root
+   :param retry_count: default number of retries to attempt when error occurs
+   :param retry_delay: number of seconds to wait between retries
+   :param retry_errors: which HTTP status codes to retry
+   :param timeout: The maximum amount of time to wait for a response from
+                   Twitter
+   :param parser: The object to use for parsing the response from Twitter
+   :param compression: Whether or not to use GZIP compression for requests
+   :param wait_on_rate_limit: Whether or not to automatically wait for rate
+                              limits to replenish
+   :param wait_on_rate_limit_notify: Whether or not to print a notification
+                                     when Tweepy is waiting for rate limits to
+                                     replenish
+   :param proxy: The full url to an HTTPS proxy to use for connecting to
+                 Twitter.
+
+
+Timeline methods
+----------------
+
+.. method:: API.home_timeline([since_id], [max_id], [count], [page])
+
+   Returns the 20 most recent statuses, including retweets, posted by the
+   authenticating user and that user's friends. This is the equivalent of
+   /timeline/home on the Web.
+
+   :param since_id: |since_id|
+   :param max_id: |max_id|
+   :param count: |count|
+   :param page: |page|
+   :rtype: list of :class:`Status` objects
+
+
+.. method:: API.statuses_lookup(id_, [include_entities], [trim_user], [map_], \
+                                [include_ext_alt_text], [include_card_uri])
+
+   Returns full Tweet objects for up to 100 tweets per request, specified by
+   the ``id_`` parameter.
+
+   :param id\_: A list of Tweet IDs to lookup, up to 100
+   :param include_entities: |include_entities|
+   :param trim_user: |trim_user|
+   :param map\_: A boolean indicating whether or not to include tweets that
+                 cannot be shown. Defaults to False.
+   :param include_ext_alt_text: |include_ext_alt_text|
+   :param include_card_uri: |include_card_uri|
+   :rtype: list of :class:`Status` objects
+
+
+.. method:: API.user_timeline([id/user_id/screen_name], [since_id], [max_id], \
+                              [count], [page])
+
+   Returns the 20 most recent statuses posted from the authenticating user or
+   the user specified. It's also possible to request another user's timeline
+   via the id parameter.
+
+   :param id: |uid|
+   :param user_id: |user_id|
+   :param screen_name: |screen_name|
+   :param since_id: |since_id|
+   :param max_id: |max_id|
+   :param count: |count|
+   :param page: |page|
+   :rtype: list of :class:`Status` objects
+
+
+.. method:: API.retweets_of_me([since_id], [max_id], [count], [page])
+
+   Returns the 20 most recent tweets of the authenticated user that have been
+   retweeted by others.
+
+   :param since_id: |since_id|
+   :param max_id: |max_id|
+   :param count: |count|
+   :param page: |page|
+   :rtype: list of :class:`Status` objects
+
+
+.. method:: API.mentions_timeline([since_id], [max_id], [count])
+
+   Returns the 20 most recent mentions, including retweets.
+
+   :param since_id: |since_id|
+   :param max_id: |max_id|
+   :param count: |count|
+   :rtype: list of :class:`Status` objects
+
+
+Status methods
+--------------
+
+.. method:: API.get_status(id, [trim_user], [include_my_retweet], \
+                           [include_entities], [include_ext_alt_text], \
+                           [include_card_uri])
+
+   Returns a single status specified by the ID parameter.
+
+   :param id: |sid|
+   :param trim_user: |trim_user|
+   :param include_my_retweet: A boolean indicating if any Tweets returned that
+      have been retweeted by the authenticating user should include an
+      additional current_user_retweet node, containing the ID of the source
+      status for the retweet.
+   :param include_entities: |include_entities|
+   :param include_ext_alt_text: |include_ext_alt_text|
+   :param include_card_uri: |include_card_uri|
+   :rtype: :class:`Status` object
+
+
+.. method:: API.update_status(status, [in_reply_to_status_id], \
+                              [auto_populate_reply_metadata], \
+                              [exclude_reply_user_ids], [attachment_url], \
+                              [media_ids], [possibly_sensitive], [lat], \
+                              [long], [place_id], [display_coordinates], \
+                              [trim_user], [enable_dmcommands], \
+                              [fail_dmcommands], [card_uri])
+
+   Updates the authenticating user's current status, also known as Tweeting.
+
+   For each update attempt, the update text is compared with the authenticating
+   user's recent Tweets. Any attempt that would result in duplication will be
+   blocked, resulting in a 403 error. A user cannot submit the same status
+   twice in a row.
+
+   While not rate limited by the API, a user is limited in the number of Tweets
+   they can create at a time. If the number of updates posted by the user
+   reaches the current allowed limit this method will return an HTTP 403 error.
+
+   :param status: The text of your status update.
+   :param in_reply_to_status_id: The ID of an existing status that the update
+      is in reply to. Note: This parameter will be ignored unless the author of
+      the Tweet this parameter references is mentioned within the status text.
+      Therefore, you must include @username, where username is the author of
+      the referenced Tweet, within the update.
+   :param auto_populate_reply_metadata: If set to true and used with
+      in_reply_to_status_id, leading @mentions will be looked up from the
+      original Tweet, and added to the new Tweet from there. This wil append
+      @mentions into the metadata of an extended Tweet as a reply chain grows,
+      until the limit on @mentions is reached. In cases where the original
+      Tweet has been deleted, the reply will fail.
+   :param exclude_reply_user_ids: When used with auto_populate_reply_metadata,
+      a comma-separated list of user ids which will be removed from the
+      server-generated @mentions prefix on an extended Tweet. Note that the
+      leading @mention cannot be removed as it would break the
+      in-reply-to-status-id semantics. Attempting to remove it will be
+      silently ignored.
+   :param attachment_url: In order for a URL to not be counted in the status
+      body of an extended Tweet, provide a URL as a Tweet attachment. This URL
+      must be a Tweet permalink, or Direct Message deep link. Arbitrary,
+      non-Twitter URLs must remain in the status text. URLs passed to the
+      attachment_url parameter not matching either a Tweet permalink or Direct
+      Message deep link will fail at Tweet creation and cause an exception.
+   :param media_ids: A list of media_ids to associate with the Tweet.
+      You may include up to 4 photos or 1 animated GIF or 1 video in a Tweet.
+   :param possibly_sensitive: If you upload Tweet media that might be
+      considered sensitive content such as nudity, or medical procedures, you
+      must set this value to true.
+   :param lat: The latitude of the location this Tweet refers to. This
+      parameter will be ignored unless it is inside the range -90.0 to +90.0
+      (North is positive) inclusive. It will also be ignored if there is no
+      corresponding long parameter.
+   :param long: The longitude of the location this Tweet refers to. The valid
+      ranges for longitude are -180.0 to +180.0 (East is positive) inclusive.
+      This parameter will be ignored if outside that range, if it is not a
+      number, if geo_enabled is disabled, or if there no corresponding lat
+      parameter.
+   :param place_id: A place in the world.
+   :param display_coordinates: Whether or not to put a pin on the exact
+      coordinates a Tweet has been sent from.
+   :param trim_user: |trim_user|
+   :param enable_dmcommands: When set to true, enables shortcode commands for
+      sending Direct Messages as part of the status text to send a Direct
+      Message to a user. When set to false, disables this behavior and includes
+      any leading characters in the status text that is posted
+   :param fail_dmcommands: When set to true, causes any status text that starts
+      with shortcode commands to return an API error. When set to false, allows
+      shortcode commands to be sent in the status text and acted on by the API.
+   :param card_uri: Associate an ads card with the Tweet using the card_uri
+      value from any ads card response.
+   :rtype: :class:`Status` object
+
+
+.. method:: API.update_with_media(filename, [status], \
+                                  [in_reply_to_status_id], \
+                                  [auto_populate_reply_metadata], [lat], \
+                                  [long], [source], [place_id], [file])
+
+   *Deprecated*: Use :func:`API.media_upload` instead. Update the authenticated
+   user's status. Statuses that are duplicates or too long will be silently
+   ignored.
+
+   :param filename: The filename of the image to upload. This will
+                    automatically be opened unless `file` is specified
+   :param status: The text of your status update.
+   :param in_reply_to_status_id: The ID of an existing status that the update
+                                 is in reply to.
+   :param auto_populate_reply_metadata: Whether to automatically include the
+                                        @mentions in the status metadata.
+   :param lat: The location's latitude that this tweet refers to.
+   :param long: The location's longitude that this tweet refers to.
+   :param source: Source of the update. Only supported by Identi.ca. Twitter
+                  ignores this parameter.
+   :param place_id: Twitter ID of location which is listed in the Tweet if
+                    geolocation is enabled for the user.
+   :param file: A file object, which will be used instead of opening
+                `filename`. `filename` is still required, for MIME type
+                detection and to use as a form field in the POST data
+   :rtype: :class:`Status` object
+
+
+.. method:: API.destroy_status(id)
+
+   Destroy the status specified by the id parameter. The authenticated user
+   must be the author of the status to destroy.
+
+   :param id: |sid|
+   :rtype: :class:`Status` object
+
+
+.. method:: API.retweet(id)
+
+   Retweets a tweet. Requires the id of the tweet you are retweeting.
+
+   :param id: |sid|
+   :rtype: :class:`Status` object
+
+
+.. method:: API.retweeters(id, [cursor], [stringify_ids])
+
+   Returns up to 100 user IDs belonging to users who have retweeted the Tweet
+   specified by the id parameter.
+
+   :param id: |sid|
+   :param cursor: |cursor|
+   :param stringify_ids: Have ids returned as strings instead.
+   :rtype: list of Integers
+
+
+.. method:: API.retweets(id, [count])
+
+   Returns up to 100 of the first retweets of the given tweet.
+
+   :param id: |sid|
+   :param count: Specifies the number of retweets to retrieve.
+   :rtype: list of :class:`Status` objects
+
+
+.. method:: API.unretweet(id)
+
+   Untweets a retweeted status. Requires the id of the retweet to unretweet.
+
+   :param id: |sid|
+   :rtype: :class:`Status` object
+
+
+User methods
+------------
+
+.. method:: API.get_user(id/user_id/screen_name)
+
+   Returns information about the specified user.
+
+   :param id: |uid|
+   :param user_id: |user_id|
+   :param screen_name: |screen_name|
+   :rtype: :class:`User` object
+
+
+.. method:: API.me()
+
+   Returns the authenticated user's information.
+
+   :rtype: :class:`User` object
+
+
+.. method:: API.friends([id/user_id/screen_name], [cursor], [skip_status], \
+                        [include_user_entities])
+
+   Returns an user's friends ordered in which they were added 100 at a time.
+   If no user is specified it defaults to the authenticated user.
+
+   :param id: |uid|
+   :param user_id: |user_id|
+   :param screen_name: |screen_name|
+   :param cursor: |cursor|
+   :param count: |count|
+   :param skip_status: |skip_status|
+   :param include_user_entities: |include_user_entities|
+   :rtype: list of :class:`User` objects
+
+
+.. method:: API.followers([id/screen_name/user_id], [cursor])
+
+   Returns a user's followers ordered in which they were added. If no user is
+   specified by id/screen name, it defaults to the authenticated user.
+
+   :param id: |uid|
+   :param user_id: |user_id|
+   :param screen_name: |screen_name|
+   :param cursor: |cursor|
+   :param count: |count|
+   :param skip_status: |skip_status|
+   :param include_user_entities: |include_user_entities|
+   :rtype: list of :class:`User` objects
+
+
+.. method:: API.lookup_users([user_ids], [screen_names], [include_entities], \
+                             [tweet_mode])
+
+   Returns fully-hydrated user objects for up to 100 users per request.
+
+   There are a few things to note when using this method.
+
+   * You must be following a protected user to be able to see their most recent
+     status update. If you don't follow a protected user their status will be
+     removed.
+   * The order of user IDs or screen names may not match the order of users in
+     the returned array.
+   * If a requested user is unknown, suspended, or deleted, then that user will
+     not be returned in the results list.
+   * If none of your lookup criteria can be satisfied by returning a user
+     object, a HTTP 404 will be thrown.
+
+   :param user_ids: A list of user IDs, up to 100 are allowed in a single
+                    request.
+   :param screen_names: A list of screen names, up to 100 are allowed in a
+                        single request.
+   :param include_entities: |include_entities|
+   :param tweet_mode: Valid request values are compat and extended, which give
+                      compatibility mode and extended mode, respectively for
+                      Tweets that contain over 140 characters.
+   :rtype: list of :class:`User` objects
+
+
+.. method:: API.search_users(q, [count], [page])
+
+   Run a search for users similar to Find People button on Twitter.com; the
+   same results returned by people search on Twitter.com will be returned by
+   using this API (about being listed in the People Search). It is only
+   possible to retrieve the first 1000 matches from this API.
+
+   :param q: The query to run against people search.
+   :param count: Specifies the number of statuses to retrieve.
+                 May not be greater than 20.
+   :param page: |page|
+   :rtype: list of :class:`User` objects
+
+
+Direct Message Methods
+----------------------
+
+.. method:: API.get_direct_message([id], [full_text])
+
+   Returns a specific direct message.
+
+   :param id: |id|
+   :param full_text: |full_text|
+   :rtype: :class:`DirectMessage` object
+
+
+.. method:: API.list_direct_messages([count], [cursor])
+
+   Returns all Direct Message events (both sent and received) within the last
+   30 days. Sorted in reverse-chronological order.
+
+   :param count: |count|
+   :param cursor: |cursor|
+   :rtype: list of :class:`DirectMessage` objects
+
+
+.. method:: API.send_direct_message(recipient_id, text, [quick_reply_type], \
+                                    [attachment_type], [attachment_media_id])
+
+   Sends a new direct message to the specified user from the authenticating
+   user.
+
+   :param recipient_id: The ID of the user who should receive the direct
+                        message.
+   :param text: The text of your Direct Message. Max length of 10,000
+                characters.
+   :param quick_reply_type: The Quick Reply type to present to the user:
+
+                            * options - Array of Options objects (20 max).
+                            * text_input - Text Input object.
+                            * location - Location object.
+   :param attachment_type: The attachment type. Can be media or location.
+   :param attachment_media_id: A media id to associate with the message.
+                               A Direct Message may only reference a single
+                               media_id.
+   :rtype: :class:`DirectMessage` object
+
+
+.. method:: API.destroy_direct_message(id)
+
+   Deletes the direct message specified in the required ID parameter. The
+   authenticating user must be the recipient of the specified direct message.
+   Direct Messages are only removed from the interface of the user context
+   provided. Other members of the conversation can still access the Direct
+   Messages.
+
+   :param id: The id of the Direct Message that should be deleted.
+   :rtype: None
+
+
+Friendship Methods
+------------------
+
+.. method:: API.create_friendship(id/screen_name/user_id, [follow])
+
+   Create a new friendship with the specified user (aka follow).
+
+   :param id: |uid|
+   :param screen_name: |screen_name|
+   :param user_id: |user_id|
+   :param follow: Enable notifications for the target user in addition to
+                  becoming friends.
+   :rtype: :class:`User` object
+
+
+.. method:: API.destroy_friendship(id/screen_name/user_id)
+
+   Destroy a friendship with the specified user (aka unfollow).
+
+   :param id: |uid|
+   :param screen_name: |screen_name|
+   :param user_id: |user_id|
+   :rtype: :class:`User` object
+
+
+.. method:: API.show_friendship(source_id/source_screen_name, \
+                                target_id/target_screen_name)
+
+   Returns detailed information about the relationship between two users.
+
+   :param source_id: The user_id of the subject user.
+   :param source_screen_name: The screen_name of the subject user.
+   :param target_id: The user_id of the target user.
+   :param target_screen_name: The screen_name of the target user.
+   :rtype: :class:`Friendship` object
+
+
+.. method:: API.friends_ids(id/screen_name/user_id, [cursor])
+
+   Returns an array containing the IDs of users being followed by the specified
+   user.
+
+   :param id: |uid|
+   :param screen_name: |screen_name|
+   :param user_id: |user_id|
+   :param cursor: |cursor|
+   :rtype: list of Integers
+
+
+.. method:: API.followers_ids(id/screen_name/user_id)
+
+   Returns an array containing the IDs of users following the specified user.
+
+   :param id: |uid|
+   :param screen_name: |screen_name|
+   :param user_id: |user_id|
+   :param cursor: |cursor|
+   :rtype: list of Integers
+
+
+Account Methods
+---------------
+
+.. method:: API.verify_credentials([include_entities], [skip_status], \
+                                   [include_email])
+
+   Verify the supplied user credentials are valid.
+
+   :param include_entities: |include_entities|
+   :param skip_status: |skip_status|
+   :param include_email: When set to true email will be returned in the user
+                         objects as a string.
+   :rtype: :class:`User` object if credentials are valid, otherwise False
+
+
+.. method:: API.rate_limit_status()
+
+   Returns the current rate limits for methods belonging to the specified
+   resource families. When using application-only auth, this method's response
+   indicates the application-only auth rate limiting context.
+
+   :param resources: A comma-separated list of resource families you want to
+                     know the current rate limit disposition for.
+   :rtype: :class:`JSON` object
+
+
+.. method:: API.update_profile_image(filename)
+
+   Update the authenticating user's profile image. Valid formats: GIF, JPG, or
+   PNG
+
+   :param filename: local path to image file to upload. Not a remote URL!
+   :rtype: :class:`User` object
+
+
+.. method:: API.update_profile_background_image(filename)
+
+   Update authenticating user's background image. Valid formats: GIF, JPG, or
+   PNG
+
+   :param filename: local path to image file to upload. Not a remote URL!
+   :rtype: :class:`User` object
+
+
+.. method:: API.update_profile([name], [url], [location], [description])
+
+   Sets values that users are able to set under the "Account" tab of their
+   settings page.
+
+   :param name: Maximum of 20 characters
+   :param url: Maximum of 100 characters.
+               Will be prepended with "http://" if not present
+   :param location: Maximum of 30 characters
+   :param description: Maximum of 160 characters
+   :rtype: :class:`User` object
+
+
+Favorite Methods
+----------------
+
+.. method:: API.favorites([id], [page])
+
+   Returns the favorite statuses for the authenticating user or user specified
+   by the ID parameter.
+
+   :param id: The ID or screen name of the user to request favorites
+   :param page: |page|
+   :rtype: list of :class:`Status` objects
+
+
+.. method:: API.create_favorite(id)
+
+   Favorites the status specified in the ID parameter as the authenticating
+   user.
+
+   :param id: |sid|
+   :rtype: :class:`Status` object
+
+
+.. method:: API.destroy_favorite(id)
+
+   Un-favorites the status specified in the ID parameter as the authenticating
+   user.
+
+   :param id: |sid|
+   :rtype: :class:`Status` object
+
+
+Block Methods
+-------------
+
+.. method:: API.create_block(id/screen_name/user_id)
+
+   Blocks the user specified in the ID parameter as the authenticating user.
+   Destroys a friendship to the blocked user if it exists.
+
+   :param id: |uid|
+   :param screen_name: |screen_name|
+   :param user_id: |user_id|
+   :rtype: :class:`User` object
+
+
+.. method:: API.destroy_block(id/screen_name/user_id)
+
+   Un-blocks the user specified in the ID parameter for the authenticating
+   user.
+
+   :param id: |uid|
+   :param screen_name: |screen_name|
+   :param user_id: |user_id|
+   :rtype: :class:`User` object
+
+
+.. method:: API.blocks([page])
+
+   Returns an array of user objects that the authenticating user is blocking.
+
+   :param page: |page|
+   :rtype: list of :class:`User` objects
+
+
+.. method:: API.blocks_ids([cursor])
+
+   Returns an array of numeric user ids the authenticating user is blocking.
+
+   :param cursor: |cursor|
+   :rtype: list of Integers
+
+
+Mute Methods
+------------
+
+.. method:: API.create_mute(id/screen_name/user_id)
+
+   Mutes the user specified in the ID parameter for the authenticating user.
+
+   :param id: |uid|
+   :param screen_name: |screen_name|
+   :param user_id: |user_id|
+   :rtype: :class:`User` object
+
+
+.. method:: API.destroy_mute(id/screen_name/user_id)
+
+   Un-mutes the user specified in the ID parameter for the authenticating user.
+
+   :param id: |uid|
+   :param screen_name: |screen_name|
+   :param user_id: |user_id|
+   :rtype: :class:`User` object
+
+
+.. method:: API.mutes([cursor], [include_entities], [skip_status])
+
+   Returns an array of user objects the authenticating user has muted.
+
+   :param cursor: |cursor|
+   :param include_entities: |include_entities|
+   :param skip_status: |skip_status|
+   :rtype: list of :class:`User` objects
+
+
+.. method:: API.mutes_ids([cursor])
+
+   Returns an array of numeric user ids the authenticating user has muted.
+
+   :param cursor: |cursor|
+   :rtype: list of Integers
+
+
+Spam Reporting Methods
+----------------------
+
+.. method:: API.report_spam(id/screen_name/user_id, [perform_block])
+
+   The user specified in the id is blocked by the authenticated user and
+   reported as a spammer.
+
+   :param id: |uid|
+   :param screen_name: |screen_name|
+   :param user_id: |user_id|
+   :param perform_block: A boolean indicating if the reported account should be
+                         blocked. Defaults to True.
+   :rtype: :class:`User` object
+
+
+Saved Searches Methods
+----------------------
+
+.. method:: API.saved_searches()
+
+   Returns the authenticated user's saved search queries.
+
+   :rtype: list of :class:`SavedSearch` objects
+
+
+.. method:: API.get_saved_search(id)
+
+   Retrieve the data for a saved search owned by the authenticating user
+   specified by the given id.
+
+   :param id: The id of the saved search to be retrieved.
+   :rtype: :class:`SavedSearch` object
+
+
+.. method:: API.create_saved_search(query)
+
+   Creates a saved search for the authenticated user.
+
+   :param query: The query of the search the user would like to save.
+   :rtype: :class:`SavedSearch` object
+
+
+.. method:: API.destroy_saved_search(id)
+
+   Destroys a saved search for the authenticated user. The search specified by
+   id must be owned by the authenticating user.
+
+   :param id: The id of the saved search to be deleted.
+   :rtype: :class:`SavedSearch` object
+
+
+Help Methods
+------------
+
+.. method:: API.search(q, [geocode], [lang], [locale], [result_type], \
+                       [count], [until], [since_id], [max_id], \
+                       [include_entities])
+
+   Returns a collection of relevant Tweets matching a specified query.
+   
+   Please note that Twitter's search service and, by extension, the Search API
+   is not meant to be an exhaustive source of Tweets. Not all Tweets will be
+   indexed or made available via the search interface.
+
+   In API v1.1, the response format of the Search API has been improved to
+   return Tweet objects more similar to the objects you’ll find across the REST
+   API and platform. However, perspectival attributes (fields that pertain to
+   the perspective of the authenticating user) are not currently supported on
+   this endpoint.\ [#]_\ [#]_
+
+   :param q: the search query string of 500 characters maximum, including
+      operators. Queries may additionally be limited by complexity.
+   :param geocode: Returns tweets by users located within a given radius of the
+      given latitude/longitude.  The location is preferentially taking from the
+      Geotagging API, but will fall back to their Twitter profile. The
+      parameter value is specified by "latitide,longitude,radius", where radius
+      units must be specified as either "mi" (miles) or "km" (kilometers). Note
+      that you cannot use the near operator via the API to geocode arbitrary
+      locations; however you can use this geocode parameter to search near
+      geocodes directly. A maximum of 1,000 distinct "sub-regions" will be
+      considered when using the radius modifier.
+   :param lang: Restricts tweets to the given language, given by an ISO 639-1
+      code. Language detection is best-effort.
+   :param locale: Specify the language of the query you are sending (only ja is
+      currently effective). This is intended for language-specific consumers
+      and the default should work in the majority of cases.
+   :param result_type: Specifies what type of search results you would prefer
+      to receive. The current default is "mixed." Valid values include:
+
+      * mixed : include both popular and real time results in the response
+      * recent : return only the most recent results in the response
+      * popular : return only the most popular results in the response
+   :param count: |count|
+   :param until: Returns tweets created before the given date. Date should be
+      formatted as YYYY-MM-DD. Keep in mind that the search index has a 7-day
+      limit. In other words, no tweets will be found for a date older than one
+      week.
+   :param since_id: |since_id| There are limits to the number of Tweets which
+      can be accessed through the API. If the limit of Tweets has occurred
+      since the since_id, the since_id will be forced to the oldest ID
+      available.
+   :param max_id: |max_id|
+   :param include_entities: |include_entities|
+   :rtype: :class:`SearchResults` object
+
+
+List Methods
+------------
+
+.. method:: API.create_list(name, [mode], [description])
+
+   Creates a new list for the authenticated user.
+   Note that you can create up to 1000 lists per account.
+
+   :param name: The name of the new list.
+   :param mode: |list_mode|
+   :param description: The description of the list you are creating.
+   :rtype: :class:`List` object
+
+
+.. method:: API.destroy_list([owner_screen_name/owner_id], list_id/slug)
+
+   Deletes the specified list.
+   The authenticated user must own the list to be able to destroy it.
+
+   :param owner_screen_name: |owner_screen_name|
+   :param owner_id: |owner_id|
+   :param list_id: |list_id|
+   :param slug: |slug|
+   :rtype: :class:`List` object
+
+
+.. method:: API.update_list(list_id/slug, [name], [mode], [description], \
+                            [owner_screen_name/owner_id])
+
+   Updates the specified list.
+   The authenticated user must own the list to be able to update it.
+
+   :param list_id: |list_id|
+   :param slug: |slug|
+   :param name: The name for the list.
+   :param mode: |list_mode|
+   :param description: The description to give the list.
+   :param owner_screen_name: |owner_screen_name|
+   :param owner_id: |owner_id|
+   :rtype: :class:`List` object
+
+
+.. method:: API.lists_all([screen_name], [user_id], [reverse])
+
+   Returns all lists the authenticating or specified user subscribes to,
+   including their own. The user is specified using the ``user_id`` or
+   ``screen_name`` parameters. If no user is given, the authenticating user is
+   used.
+
+   A maximum of 100 results will be returned by this call. Subscribed lists are
+   returned first, followed by owned lists. This means that if a user
+   subscribes to 90 lists and owns 20 lists, this method returns 90
+   subscriptions and 10 owned lists. The ``reverse`` method returns owned lists
+   first, so with ``reverse=true``, 20 owned lists and 80 subscriptions would
+   be returned.
+
+   :param screen_name: |screen_name|
+   :param user_id: |user_id|
+   :param reverse: A boolean indicating if you would like owned lists to be
+                   returned first. See description above for information on how
+                   this parameter works.
+   :rtype: list of :class:`List` objects
+
+
+.. method:: API.lists_memberships([screen_name], [user_id], \
+                                  [filter_to_owned_lists], [cursor], [count])
+
+   Returns the lists the specified user has been added to. If ``user_id`` or
+   ``screen_name`` are not provided, the memberships for the authenticating
+   user are returned.
+
+   :param screen_name: |screen_name|
+   :param user_id: |user_id|
+   :param filter_to_owned_lists: A boolean indicating whether to return just
+      lists the authenticating user owns, and the user represented by
+      ``user_id`` or ``screen_name`` is a member of.
+   :param cursor: |cursor|
+   :param count: |count|
+   :rtype: list of :class:`List` objects
+
+
+.. method:: API.lists_subscriptions([screen_name], [user_id], [cursor], \
+                                    [count])
+
+   Obtain a collection of the lists the specified user is subscribed to, 20
+   lists per page by default. Does not include the user's own lists.
+
+   :param screen_name: |screen_name|
+   :param user_id: |user_id|
+   :param cursor: |cursor|
+   :param count: |count|
+   :rtype: list of :class:`List` objects
+
+
+.. method:: API.list_timeline(list_id/slug, [owner_id/owner_screen_name], \
+                              [since_id], [max_id], [count], \
+                              [include_entities], [include_rts])
+
+   Returns a timeline of tweets authored by members of the specified list.
+   Retweets are included by default. Use the ``include_rts=false`` parameter to
+   omit retweets.
+
+   :param list_id: |list_id|
+   :param slug: |slug|
+   :param owner_id: |owner_id|
+   :param owner_screen_name: |owner_screen_name|
+   :param since_id: |since_id|
+   :param max_id: |max_id|
+   :param count: |count|
+   :param include_entities: |include_entities|
+   :param include_rts: A boolean indicating whether the list timeline will
+      contain native retweets (if they exist) in addition to the standard
+      stream of tweets. The output format of retweeted tweets is identical to
+      the representation you see in home_timeline.
+   :rtype: list of :class:`Status` objects
+
+
+.. method:: API.get_list(list_id/slug, [owner_id/owner_screen_name])
+
+   Returns the specified list. Private lists will only be shown if the
+   authenticated user owns the specified list.
+
+   :param list_id: |list_id|
+   :param slug: |slug|
+   :param owner_id: |owner_id|
+   :param owner_screen_name: |owner_screen_name|
+   :rtype: :class:`List` object
+
+
+.. method:: API.add_list_member(list_id/slug, screen_name/user_id, \
+                                [owner_id/owner_screen_name])
+
+   Add a member to a list. The authenticated user must own the list to be able
+   to add members to it. Lists are limited to 5,000 members.
+
+   :param list_id: |list_id|
+   :param slug: |slug|
+   :param screen_name: |screen_name|
+   :param user_id: |user_id|
+   :param owner_id: |owner_id|
+   :param owner_screen_name: |owner_screen_name|
+   :rtype: :class:`List` object
+
+
+.. method:: API.add_list_members(list_id/slug, screen_name/user_id, \
+                                 [owner_id/owner_screen_name])
+
+   Add up to 100 members to a list. The authenticated user must own the list to
+   be able to add members to it. Lists are limited to 5,000 members.
+
+   :param list_id: |list_id|
+   :param slug: |slug|
+   :param screen_name: A comma separated list of screen names, up to 100 are
+                       allowed in a single request
+   :param user_id: A comma separated list of user IDs, up to 100 are allowed in
+                   a single request
+   :param owner_id: |owner_id|
+   :param owner_screen_name: |owner_screen_name|
+   :rtype: :class:`List` object
+
+
+.. method:: API.remove_list_member(list_id/slug, screen_name/user_id, \
+                                   [owner_id/owner_screen_name])
+
+   Removes the specified member from the list. The authenticated user must be
+   the list's owner to remove members from the list.
+
+   :param list_id: |list_id|
+   :param slug: |slug|
+   :param screen_name: |screen_name|
+   :param user_id: |user_id|
+   :param owner_id: |owner_id|
+   :param owner_screen_name: |owner_screen_name|
+   :rtype: :class:`List` object
+
+
+.. method:: API.remove_list_members(list_id/slug, screen_name/user_id, \
+                                    [owner_id/owner_screen_name])
+
+   Remove up to 100 members from a list. The authenticated user must own the
+   list to be able to remove members from it. Lists are limited to 5,000
+   members.
+
+   :param list_id: |list_id|
+   :param slug: |slug|
+   :param screen_name: A comma separated list of screen names, up to 100 are
+                       allowed in a single request
+   :param user_id: A comma separated list of user IDs, up to 100 are allowed in
+                   a single request
+   :param owner_id: |owner_id|
+   :param owner_screen_name: |owner_screen_name|
+   :rtype: :class:`List` object
+
+
+.. method:: API.list_members(list_id/slug, [owner_id/owner_screen_name], \
+                             [cursor])
+
+   Returns the members of the specified list.
+
+   :param list_id: |list_id|
+   :param slug: |slug|
+   :param owner_id: |owner_id|
+   :param owner_screen_name: |owner_screen_name|
+   :param cursor: |cursor|
+   :rtype: list of :class:`User` objects
+
+
+.. method:: API.show_list_member(list_id/slug, screen_name/user_id, \
+                                 [owner_id/owner_screen_name])
+
+   Check if the specified user is a member of the specified list.
+
+   :param list_id: |list_id|
+   :param slug: |slug|
+   :param screen_name: |screen_name|
+   :param user_id: |user_id|
+   :param owner_id: |owner_id|
+   :param owner_screen_name: |owner_screen_name|
+   :rtype: :class:`User` object if user is a member of list
+
+
+.. method:: API.subscribe_list(list_id/slug, [owner_id/owner_screen_name])
+
+   Subscribes the authenticated user to the specified list.
+
+   :param list_id: |list_id|
+   :param slug: |slug|
+   :param owner_id: |owner_id|
+   :param owner_screen_name: |owner_screen_name|
+   :rtype: :class:`List` object
+
+
+.. method:: API.unsubscribe_list(list_id/slug, [owner_id/owner_screen_name])
+
+   Unsubscribes the authenticated user from the specified list.
+
+   :param list_id: |list_id|
+   :param slug: |slug|
+   :param owner_id: |owner_id|
+   :param owner_screen_name: |owner_screen_name|
+   :rtype: :class:`List` object
+
+
+.. method:: API.list_subscribers(list_id/slug, [owner_id/owner_screen_name], \
+                                 [cursor], [count], [include_entities], \
+                                 [skip_status])
+
+   Returns the subscribers of the specified list. Private list subscribers will
+   only be shown if the authenticated user owns the specified list.
+
+   :param list_id: |list_id|
+   :param slug: |slug|
+   :param owner_id: |owner_id|
+   :param owner_screen_name: |owner_screen_name|
+   :param cursor: |cursor|
+   :param count: |count|
+   :param include_entities: |include_entities|
+   :param skip_status: |skip_status|
+   :rtype: list of :class:`User` objects
+
+
+.. method:: API.show_list_subscriber(list_id/slug, screen_name/user_id, \
+                                     [owner_id/owner_screen_name])
+
+   Check if the specified user is a subscriber of the specified list.
+
+   :param list_id: |list_id|
+   :param slug: |slug|
+   :param screen_name: |screen_name|
+   :param user_id: |user_id|
+   :param owner_id: |owner_id|
+   :param owner_screen_name: |owner_screen_name|
+   :rtype: :class:`User` object if user is subscribed to list
+
+
+Trends Methods
+--------------
+
+.. method:: API.trends_available()
+
+   Returns the locations that Twitter has trending topic information for.
+   The response is an array of "locations" that encode the location's WOEID
+   (a Yahoo! Where On Earth ID) and some other human-readable information such
+   as a canonical name and country the location belongs in.
+
+   :rtype: :class:`JSON` object
+
+
+.. method:: API.trends_place(id, [exclude])
+
+   Returns the top 50 trending topics for a specific WOEID,
+   if trending information is available for it.
+
+   The response is an array of “trend” objects that encode the name of the
+   trending topic, the query parameter that can be used to search for the topic
+   on Twitter Search, and the Twitter Search URL.
+
+   This information is cached for 5 minutes. Requesting more frequently than
+   that will not return any more data, and will count against your rate limit
+   usage.
+
+   The tweet_volume for the last 24 hours is also returned for many trends if
+   this is available.
+
+   :param id: The Yahoo! Where On Earth ID of the location to return trending
+              information for. Global information is available by using 1 as
+              the WOEID.
+   :param exclude: Setting this equal to hashtags will remove all hashtags
+                   from the trends list.
+   :rtype: :class:`JSON` object
+
+
+.. method:: API.trends_closest(lat, long)
+
+   Returns the locations that Twitter has trending topic information for,
+   closest to a specified location.
+
+   The response is an array of “locations” that encode the location’s WOEID and
+   some other human-readable information such as a canonical name and country
+   the location belongs in.
+
+   A WOEID is a Yahoo! Where On Earth ID.
+
+   :param lat: If provided with a long parameter the available trend locations
+               will be sorted by distance, nearest to furthest, to the
+               co-ordinate pair. The valid ranges for longitude is -180.0 to
+               +180.0 (West is negative, East is positive) inclusive.
+   :param long: If provided with a lat parameter the available trend locations
+                will be sorted by distance, nearest to furthest, to the
+                co-ordinate pair. The valid ranges for longitude is -180.0 to
+                +180.0 (West is negative, East is positive) inclusive.
+   :rtype: :class:`JSON` object
+
+
+Geo Methods
+-----------
+
+.. method:: API.reverse_geocode([lat], [long], [accuracy], [granularity], \
+                                [max_results])
+
+   Given a latitude and longitude, looks for places (cities and neighbourhoods)
+   whose IDs can be specified in a call to :func:`update_status` to appear as
+   the name of the location. This call provides a detailed response about the
+   location in question; the :func:`nearby_places` function should be preferred
+   for getting a list of places nearby without great detail.
+
+   :param lat: The location's latitude.
+   :param long: The location's longitude.
+   :param accuracy: Specify the "region" in which to search, such as a number
+                    (then this is a radius in meters, but it can also take a
+                    string that is suffixed with ft to specify feet).
+                    If this is not passed in, then it is assumed to be 0m
+   :param granularity: Assumed to be `neighborhood' by default; can also be
+                       `city'.
+   :param max_results: A hint as to the maximum number of results to return.
+                       This is only a guideline, which may not be adhered to.
+
+
+.. method:: API.geo_id(id)
+
+   Given *id* of a place, provide more details about that place.
+
+   :param id: Valid Twitter ID of a location.
+
+
+Utility methods
+---------------
+
+.. method:: API.configuration()
+
+   Returns the current configuration used by Twitter including twitter.com
+   slugs which are not usernames, maximum photo resolutions, and t.co
+   shortened URL length. It is recommended applications request this endpoint
+   when they are loaded, but no more than once a day.
+
+
+Media methods
+-------------
+
+.. method:: API.media_upload(filename, [file])
+
+   Use this endpoint to upload images to Twitter.
+
+   :param filename: The filename of the image to upload. This will
+                    automatically be opened unless ``file`` is specified.
+   :param file: A file object, which will be used instead of opening
+                ``filename``. ``filename`` is still required, for MIME type
+                detection and to use as a form field in the POST data.
+   :rtype: :class:`Media` object
+
+
+.. method:: API.create_media_metadata(media_id, alt_text)
+
+   This endpoint can be used to provide additional information about the
+   uploaded media_id. This feature is currently only supported for images and
+   GIFs. Call this endpoint to attach additional metadata such as image alt
+   text.
+   
+   :param media_id: The ID of the media to add alt text to.
+   :param alt_text: The alt text to add to the image.
+
+
+:mod:`tweepy.error` --- Exceptions
+==================================
+
+The exceptions are available in the ``tweepy`` module directly, which means
+``tweepy.error`` itself does not need to be imported. For example,
+``tweepy.error.TweepError`` is available as ``tweepy.TweepError``.
+
+
+.. exception:: TweepError
+
+   The main exception Tweepy uses. Is raised for a number of things.
+
+   When a ``TweepError`` is raised due to an error Twitter responded with,
+   the error code (`as described in the API documentation
+   <https://developer.twitter.com/en/docs/basics/response-codes>`_) can be
+   accessed at ``TweepError.response.text``. Note, however, that
+   ``TweepError``\ s also may be raised with other things as message
+   (for example plain error reason strings).
+
+
+.. exception:: RateLimitError
+
+   Is raised when an API method fails due to hitting Twitter's rate limit.
+   Makes for easy handling of the rate limit specifically.
+
+   Inherits from :exc:`TweepError`, so ``except TweepError`` will catch a
+   ``RateLimitError`` too.
+
+
+.. rubric:: Footnotes
+
+.. [#] https://web.archive.org/web/20170829051949/https://dev.twitter.com/rest/reference/get/search/tweets
+.. [#] https://twittercommunity.com/t/favorited-reports-as-false-even-if-status-is-already-favorited-by-the-user/11145
diff --git a/docs/auth_tutorial.rst b/docs/auth_tutorial.rst
new file mode 100644 (file)
index 0000000..29cac52
--- /dev/null
@@ -0,0 +1,148 @@
+.. _auth_tutorial:
+
+
+***********************
+Authentication Tutorial
+***********************
+
+Introduction
+============
+
+Tweepy supports both OAuth 1a (application-user) and OAuth 2
+(application-only) authentication. Authentication is handled by the
+tweepy.AuthHandler class.
+
+OAuth 1a Authentication
+=======================
+
+Tweepy tries to make OAuth 1a as painless as possible for you. To begin
+the process we need to register our client application with
+Twitter. Create a new application and once you
+are done you should have your consumer key and secret. Keep these
+two handy, you'll need them.
+
+The next step is creating an OAuthHandler instance. Into this we pass
+our consumer key and secret which was given to us in the previous
+paragraph::
+
+   auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
+
+If you have a web application and are using a callback URL that needs
+to be supplied dynamically you would pass it in like so::
+
+   auth = tweepy.OAuthHandler(consumer_key, consumer_secret,
+   callback_url)
+
+If the callback URL will not be changing, it is best to just configure
+it statically on twitter.com when setting up your application's
+profile.
+
+Unlike basic auth, we must do the OAuth 1a "dance" before we can start
+using the API. We must complete the following steps:
+
+#. Get a request token from twitter
+
+#. Redirect user to twitter.com to authorize our application
+
+#. If using a callback, twitter will redirect the user to
+   us. Otherwise the user must manually supply us with the verifier
+   code.
+
+#. Exchange the authorized request token for an access token.
+
+So let's fetch our request token to begin the dance::
+
+   try:
+       redirect_url = auth.get_authorization_url()
+   except tweepy.TweepError:
+       print('Error! Failed to get request token.')
+
+This call requests the token from twitter and returns to us the
+authorization URL where the user must be redirect to authorize us. Now
+if this is a desktop application we can just hang onto our
+OAuthHandler instance until the user returns back. In a web
+application we will be using a callback request. So we must store the
+request token in the session since we will need it inside the callback
+URL request. Here is a pseudo example of storing the request token in
+a session::
+
+   session.set('request_token', auth.request_token['oauth_token'])
+
+So now we can redirect the user to the URL returned to us earlier from
+the get_authorization_url() method.
+
+If this is a desktop application (or any application not using
+callbacks) we must query the user for the "verifier code" that twitter
+will supply them after they authorize us. Inside a web application
+this verifier value will be supplied in the callback request from
+twitter as a GET query parameter in the URL.
+
+.. code-block :: python
+
+   # Example using callback (web app)
+   verifier = request.GET.get('oauth_verifier')
+
+   # Example w/o callback (desktop)
+   verifier = raw_input('Verifier:')
+
+The final step is exchanging the request token for an access
+token. The access token is the "key" for opening the Twitter API
+treasure box. To fetch this token we do the following::
+
+   # Let's say this is a web app, so we need to re-build the auth handler
+   # first...
+   auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
+   token = session.get('request_token')
+   session.delete('request_token')
+   auth.request_token = { 'oauth_token' : token,
+                            'oauth_token_secret' : verifier }
+
+   try:
+       auth.get_access_token(verifier)
+   except tweepy.TweepError:
+       print('Error! Failed to get access token.')
+
+It is a good idea to save the access token for later use. You do not
+need to re-fetch it each time. Twitter currently does not expire the
+tokens, so the only time it would ever go invalid is if the user
+revokes our application access. To store the access token depends on
+your application. Basically you need to store 2 string values: key and
+secret::
+
+   auth.access_token
+   auth.access_token_secret
+
+You can throw these into a database, file, or where ever you store
+your data. To re-build an OAuthHandler from this stored access token
+you would do this::
+
+   auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
+   auth.set_access_token(key, secret)
+
+So now that we have our OAuthHandler equipped with an access token, we
+are ready for business::
+
+   api = tweepy.API(auth)
+   api.update_status('tweepy + oauth!')
+
+OAuth 2 Authentication
+======================
+
+Tweepy also supports OAuth 2 authentication. OAuth 2 is a method of
+authentication where an application makes API requests without the
+user context. Use this method if you just need read-only access to
+public information.
+
+Like OAuth 1a, we first register our client application and acquire
+a consumer key and secret.
+
+Then we create an AppAuthHandler instance, passing in our consumer
+key and secret::
+
+   auth = tweepy.AppAuthHandler(consumer_key, consumer_secret)
+
+With the bearer token received, we are now ready for business::
+
+   api = tweepy.API(auth)
+   for tweet in tweepy.Cursor(api.search, q='tweepy').items(10):
+       print(tweet.text)
\ No newline at end of file
diff --git a/docs/code_snippet.rst b/docs/code_snippet.rst
new file mode 100644 (file)
index 0000000..f838e2a
--- /dev/null
@@ -0,0 +1,79 @@
+.. _code_snippet:
+
+
+*************
+Code Snippets
+*************
+
+Introduction
+============
+
+Here are some code snippets to help you out with using Tweepy. Feel
+free to contribute your own snippets or improve the ones here!
+
+OAuth
+=====
+
+.. code-block :: python
+
+   auth = tweepy.OAuthHandler("consumer_key", "consumer_secret")
+   
+   # Redirect user to Twitter to authorize
+   redirect_user(auth.get_authorization_url())
+   
+   # Get access token
+   auth.get_access_token("verifier_value")
+   
+   # Construct the API instance
+   api = tweepy.API(auth)
+
+Pagination
+==========
+
+.. code-block :: python
+
+   # Iterate through all of the authenticated user's friends
+   for friend in tweepy.Cursor(api.friends).items():
+       # Process the friend here
+       process_friend(friend)
+   
+   # Iterate through the first 200 statuses in the home timeline
+   for status in tweepy.Cursor(api.home_timeline).items(200):
+       # Process the status here
+       process_status(status)
+
+FollowAll
+=========
+
+This snippet will follow every follower of the authenticated user.
+
+.. code-block :: python
+
+   for follower in tweepy.Cursor(api.followers).items():
+       follower.follow()
+
+Handling the rate limit using cursors
+=====================================
+   
+Since cursors raise ``RateLimitError``\ s in their ``next()`` method,
+handling them can be done by wrapping the cursor in an iterator.
+   
+Running this snippet will print all users you follow that themselves follow
+less than 300 people total - to exclude obvious spambots, for example - and
+will wait for 15 minutes each time it hits the rate limit.
+   
+.. code-block :: python
+   
+   # In this example, the handler is time.sleep(15 * 60),
+   # but you can of course handle it in any way you want.
+   
+   def limit_handled(cursor):
+       while True:
+           try:
+               yield cursor.next()
+           except tweepy.RateLimitError:
+               time.sleep(15 * 60)
+   
+   for follower in limit_handled(tweepy.Cursor(api.followers).items()):
+       if follower.friends_count < 300:
+           print(follower.screen_name)
index 70cd229942395329992f3d07ebf8fac4db5fb3a5..a09d4272fb2a4a550d936ed19250119ea264ebc1 100644 (file)
@@ -56,8 +56,8 @@ release = __version__
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
-locale_dirs = ['_locale']
-#language = None
+locale_dirs = ['locale/']
+language = 'en'
 
 # There are two options for replacing |today|: either, you set today to some
 # non-false value, then it is used:
diff --git a/docs/cursor_tutorial.rst b/docs/cursor_tutorial.rst
new file mode 100644 (file)
index 0000000..9aef25e
--- /dev/null
@@ -0,0 +1,94 @@
+.. _cursor_tutorial:
+
+***************
+Cursor Tutorial
+***************
+
+This tutorial describes details on pagination with Cursor objects.
+
+Introduction
+============
+
+We use pagination a lot in Twitter API development. Iterating through
+timelines, user lists, direct messages, etc. In order to perform
+pagination, we must supply a page/cursor parameter with each of our
+requests. The problem here is this requires a lot of boiler plate code
+just to manage the pagination loop. To help make pagination easier and
+require less code, Tweepy has the Cursor object.
+
+Old way vs Cursor way
+=====================
+
+First let's demonstrate iterating the statuses in the authenticated
+user's timeline. Here is how we would do it the "old way" before the
+Cursor object was introduced::
+
+   page = 1
+   while True:
+       statuses = api.user_timeline(page=page)
+       if statuses:
+           for status in statuses:
+               # process status here
+               process_status(status)
+       else:
+           # All done
+           break
+       page += 1  # next page
+
+As you can see, we must manage the "page" parameter manually in our
+pagination loop. Now here is the version of the code using the Cursor
+object::
+
+   for status in tweepy.Cursor(api.user_timeline).items():
+       # process status here
+       process_status(status)
+
+Now that looks much better! Cursor handles all the pagination work for
+us behind the scenes, so our code can now focus entirely on processing
+the results.
+
+Passing parameters into the API method
+======================================
+
+What if you need to pass in parameters to the API method?
+
+.. code-block :: python
+
+   api.user_timeline(id="twitter")
+
+Since we pass Cursor the callable, we can not pass the parameters
+directly into the method. Instead we pass the parameters into the
+Cursor constructor method::
+
+   tweepy.Cursor(api.user_timeline, id="twitter")
+
+Now Cursor will pass the parameter into the method for us whenever it
+makes a request.
+
+Items or Pages
+==============
+
+So far we have just demonstrated pagination iterating per
+item. What if instead you want to process per page of results? You
+would use the pages() method::
+
+   for page in tweepy.Cursor(api.user_timeline).pages():
+       # page is a list of statuses
+       process_page(page)
+
+
+Limits
+======
+
+What if you only want n items or pages returned? You pass into the
+items() or pages() methods the limit you want to impose.
+
+.. code-block :: python
+
+   # Only iterate through the first 200 statuses
+   for status in tweepy.Cursor(api.user_timeline).items(200):
+       process_status(status)
+
+   # Only iterate through the first 3 pages
+   for page in tweepy.Cursor(api.user_timeline).pages(3):
+       process_page(page)
diff --git a/docs/extended_tweets.rst b/docs/extended_tweets.rst
new file mode 100644 (file)
index 0000000..d47ef66
--- /dev/null
@@ -0,0 +1,125 @@
+.. _extended_tweets:
+.. _Twitter's Tweet updates documentation: https://developer.twitter.com/en/docs/tweets/tweet-updates
+
+***************
+Extended Tweets
+***************
+
+This supplements `Twitter's Tweet updates documentation`_.
+
+Introduction
+============
+
+On May 24, 2016, Twitter
+`announced <https://blog.twitter.com/express-even-more-in-140-characters>`_
+changes to the way that replies and URLs are handled and
+`published plans <https://blog.twitter.com/2016/doing-more-with-140-characters>`_
+around support for these changes in the Twitter API and initial technical
+documentation describing the updates to Tweet objects and API options.\ [#]_
+On September 26, 2017, Twitter
+`started testing <https://blog.twitter.com/official/en_us/topics/product/2017/Giving-you-more-characters-to-express-yourself.html>`_
+280 characters for certain languages,\ [#]_ and on November 7, 2017,
+`announced <https://blog.twitter.com/official/en_us/topics/product/2017/tweetingmadeeasier.html>`_
+that the character limit was being expanded for Tweets in languages where
+cramming was an issue.\ [#]_
+
+Standard API methods
+====================
+
+Any ``tweepy.API`` method that returns a Status object accepts a new
+``tweet_mode`` parameter. Valid values for this parameter are ``compat`` and
+``extended``, which give compatibility mode and extended mode, respectively.
+The default mode (if no parameter is provided) is compatibility mode.
+
+Compatibility mode
+------------------
+
+By default, using compatibility mode, the ``text`` attribute of Status objects
+returned by ``tweepy.API`` methods is truncated to 140 characters, as needed.
+When this truncation occurs, the ``truncated`` attribute of the Status object
+will be ``True``, and only entities that are fully contained within the
+available 140 characters range will be included in the ``entities`` attribute.
+It will also be discernible that the ``text`` attribute of the Status object
+is truncated as it will be suffixed with an ellipsis character, a space, and a
+shortened self-permalink URL to the Tweet.
+
+Extended mode
+-------------
+
+When using extended mode, the ``text`` attribute of Status objects returned by
+``tweepy.API`` methods is replaced by a ``full_text`` attribute, which
+contains the entire untruncated text of the Tweet. The ``truncated`` attribute
+of the Status object will be ``False``, and the ``entities`` attribute will
+contain all entities. Additionally, the Status object will have a
+``display_text_range`` attribute, an array of two Unicode code point indices,
+identifying the inclusive start and exclusive end of the displayable content
+of the Tweet.
+
+Streaming
+=========
+
+By default, the Status objects from streams may contain an ``extended_tweet``
+attribute representing the equivalent field in the raw data/payload for the
+Tweet. This attribute/field will only exist for extended Tweets, containing a
+dictionary of sub-fields. The ``full_text`` sub-field/key of this dictionary
+will contain the full, untruncated text of the Tweet, and the ``entities``
+sub-field/key will contain the full set of entities. If there are extended
+entities, the ``extended_entities`` sub-field/key will contain the full set of
+those. Additionally, the ``display_text_range`` sub-field/key will contain an
+array of two Unicode code point indices, identifying the inclusive start and
+exclusive end of the displayable content of the Tweet.
+
+Handling Retweets
+=================
+
+When using extended mode with a Retweet, the ``full_text`` attribute of the
+Status object may be truncated with an ellipsis character instead of
+containing the full text of the Retweet. However, since the
+``retweeted_status`` attribute (of a Status object that is a Retweet) is
+itself a Status object, the ``full_text`` attribute of the Retweeted Status
+object can be used instead.
+
+This also applies similarly to Status objects/payloads that are Retweets from
+streams. The dictionary from the ``extended_tweet`` attribute/field contains a
+``full_text`` sub-field/key that may be truncated with an ellipsis character.
+Instead, the ``extended_tweet`` attribute/field of the Retweeted Status (from
+the ``retweeted_status`` attribute/field) can be used.
+
+Examples
+========
+
+Given an existing ``tweepy.API`` object and ``id`` for a Tweet, the following
+can be used to print the full text of the Tweet, or if it's a Retweet, the
+full text of the Retweeted Tweet::
+
+   status = api.get_status(id, tweet_mode="extended")
+   try:
+       print(status.retweeted_status.full_text)
+   except AttributeError:  # Not a Retweet
+       print(status.full_text)
+
+If ``status`` is a Retweet, ``status.full_text`` could be truncated.
+
+This Status event handler for a ``StreamListener`` prints the full text of the
+Tweet, or if it's a Retweet, the full text of the Retweeted Tweet::
+
+   def on_status(self, status):
+       if hasattr(status, "retweeted_status"):  # Check if Retweet
+           try:
+               print(status.retweeted_status.extended_tweet["full_text"])
+           except AttributeError:
+               print(status.retweeted_status.text)
+       else:
+           try:
+               print(status.extended_tweet["full_text"])
+           except AttributeError:
+               print(status.text)
+
+If ``status`` is a Retweet, it will not have an ``extended_tweet`` attribute,
+and ``status.text`` could be truncated.
+
+.. rubric:: Footnotes
+
+.. [#] https://twittercommunity.com/t/upcoming-changes-to-simplify-replies-and-links-in-tweets/67497
+.. [#] https://twittercommunity.com/t/testing-280-characters-for-certain-languages/94126
+.. [#] https://twittercommunity.com/t/updating-the-character-limit-and-the-twitter-text-library/96425
diff --git a/docs/getting_started.rst b/docs/getting_started.rst
new file mode 100644 (file)
index 0000000..c084fde
--- /dev/null
@@ -0,0 +1,64 @@
+.. _getting_started:
+
+
+***************
+Getting started
+***************
+
+Introduction
+============
+
+If you are new to Tweepy, this is the place to begin. The goal of this
+tutorial is to get you set-up and rolling with Tweepy. We won't go
+into too much detail here, just some important basics.
+
+Hello Tweepy
+============
+
+.. code-block :: python
+
+   import tweepy
+
+   auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
+   auth.set_access_token(access_token, access_token_secret)
+
+   api = tweepy.API(auth)
+   
+   public_tweets = api.home_timeline()
+   for tweet in public_tweets:
+       print(tweet.text)
+
+This example will download your home timeline tweets and print each
+one of their texts to the console. Twitter requires all requests to
+use OAuth for authentication.
+The :ref:`auth_tutorial` goes into more details about authentication.
+
+API
+===
+
+The API class provides access to the entire twitter RESTful API
+methods. Each method can accept various parameters and return
+responses. For more information about these methods please refer to
+:ref:`API Reference <api_reference>`.
+
+Models
+======
+
+When we invoke an API method most of the time returned back to us will
+be a Tweepy model class instance. This will contain the data returned
+from Twitter which we can then use inside our application. For example
+the following code returns to us an User model::
+
+   # Get the User object for twitter...
+   user = api.get_user('twitter')
+
+Models contain the data and some helper methods which we can then
+use::
+
+   print(user.screen_name)
+   print(user.followers_count)
+   for friend in user.friends():
+      print(friend.screen_name)
+
+For more information about models please see ModelsReference.
+
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644 (file)
index 0000000..1daa4f9
--- /dev/null
@@ -0,0 +1,27 @@
+.. tweepy documentation master file, created by
+   sphinx-quickstart on Sun Dec  6 11:13:52 2009.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+Tweepy Documentation
+====================
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+   getting_started.rst
+   auth_tutorial.rst
+   code_snippet.rst
+   cursor_tutorial.rst
+   extended_tweets.rst
+   streaming_how_to.rst
+   api.rst
+   running_tests.rst
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`search`
diff --git a/docs/install.rst b/docs/install.rst
new file mode 100644 (file)
index 0000000..0d4857a
--- /dev/null
@@ -0,0 +1,13 @@
+Installation
+============
+
+Install from PyPI::
+
+    easy_install tweepy
+
+Install from source::
+
+    git clone git://github.com/tweepy/tweepy.git
+    cd tweepy
+    python setup.py install
+
diff --git a/docs/make.bat b/docs/make.bat
new file mode 100644 (file)
index 0000000..1a93dda
--- /dev/null
@@ -0,0 +1,116 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+set SPHINXBUILD=sphinx-build
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+       set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+)
+
+pause
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+       :help
+       echo.Please use `make ^<target^>` where ^<target^> is one of
+       echo.  html      to make standalone HTML files
+       echo.  dirhtml   to make HTML files named index.html in directories
+       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.  latex     to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+       echo.  changes   to make an overview over all changed/added/deprecated items
+       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
+)
+
+if "%1" == "html" (
+       %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+       echo.
+       echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+       goto end
+)
+
+if "%1" == "dirhtml" (
+       %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+       echo.
+       echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+       goto end
+)
+
+if "%1" == "pickle" (
+       %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+       echo.
+       echo.Build finished; now you can process the pickle files.
+       goto end
+)
+
+if "%1" == "json" (
+       %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+       echo.
+       echo.Build finished; now you can process the JSON files.
+       goto end
+)
+
+if "%1" == "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.
+       goto end
+)
+
+if "%1" == "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\tweepy.qhcp
+       echo.To view the help file:
+       echo.^> assistant -collectionFile %BUILDDIR%\qthelp\tweepy.ghc
+       goto end
+)
+
+if "%1" == "latex" (
+       %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+       echo.
+       echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+       goto end
+)
+
+if "%1" == "changes" (
+       %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+       echo.
+       echo.The overview file is in %BUILDDIR%/changes.
+       goto end
+)
+
+if "%1" == "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.
+       goto end
+)
+
+if "%1" == "doctest" (
+       %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+       echo.
+       echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+       goto end
+)
+
+:end
+pause
diff --git a/docs/parameters.rst b/docs/parameters.rst
new file mode 100644 (file)
index 0000000..28c04f2
--- /dev/null
@@ -0,0 +1,27 @@
+.. API parameters:
+
+.. |count| replace:: The number of results to try and retrieve per page.
+.. |cursor| replace:: Breaks the results into pages. Provide a value of  -1 to begin paging. Provide values as returned to in the response body's next_cursor and previous_cursor attributes to page back and forth in the list.
+.. |date| replace:: Permits specifying a start date for the report. The date should be formatted YYYY-MM-DD.
+.. |exclude| replace:: Setting this equal to hashtags will remove all hashtags from the trends list.
+.. |full_text| replace:: A boolean indicating whether or not the full text of a message should be returned. If False the message text returned will be truncated to 140 chars. Defaults to False.
+.. |include_card_uri| replace:: A boolean indicating if the retrieved Tweet should include a card_uri attribute when there is an ads card attached to the Tweet and when that card was attached using the card_uri value.
+.. |include_entities| replace:: The entities node will not be included when set to false. Defaults to true.
+.. |include_ext_alt_text| replace:: If alt text has been added to any attached media entities, this parameter will return an ext_alt_text value in the top-level key for the media entity.
+.. |include_user_entities| replace:: The user object entities node will not be included when set to false. Defaults to true.
+.. |list_id| replace:: The numerical id of the list.
+.. |list_mode| replace:: Whether your list is public or private. Values can be public or private. Lists are public by default if no mode is specified.
+.. |list_owner| replace:: the screen name of the owner of the list
+.. |max_id| replace:: Returns only statuses with an ID less than (that is, older than) or equal to the specified ID.
+.. |owner_id| replace:: The user ID of the user who owns the list being requested by a slug.
+.. |owner_screen_name| replace:: The screen name of the user who owns the list being requested by a slug.
+.. |page| replace:: Specifies the page of results to retrieve. Note: there are pagination limits.
+.. |screen_name| replace:: Specifies the screen name of the user. Helpful for disambiguating when a valid screen name is also a user ID.
+.. |sid| replace:: The numerical ID of the status.
+.. |since_id| replace:: Returns only statuses with an ID greater than (that is, more recent than) the specified ID.
+.. |skip_status| replace:: A boolean indicating whether statuses will not be included in the returned user objects. Defaults to false.
+.. |slug| replace:: You can identify a list by its slug instead of its numerical id. If you decide to do so, note that you'll also have to specify the list owner using the owner_id or owner_screen_name parameters.
+.. |trim_user| replace:: A boolean indicating if user IDs should be provided, instead of complete user objects. Defaults to False.
+.. |uid| replace:: Specifies the ID or screen name of the user.
+.. |user_id| replace:: Specifies the ID of the user. Helpful for disambiguating when a valid user ID is also a valid screen name.
+
diff --git a/docs/running_tests.rst b/docs/running_tests.rst
new file mode 100644 (file)
index 0000000..3131751
--- /dev/null
@@ -0,0 +1,29 @@
+.. _running_tests:
+
+*************
+Running Tests
+*************
+
+These steps outline how to run tests for Tweepy:
+
+1. Download Tweepy's source code to a directory.
+
+2. Install from the downloaded source with the ``test`` extra, e.g.
+   ``pip install .[test]``. Optionally install the ``dev`` extra as well, for
+   ``tox`` and ``coverage``, e.g. ``pip install .[dev,test]``.
+
+3. Run ``python setup.py nosetests`` or simply ``nosetests`` in the source
+   directory. With the ``dev`` extra, coverage will be shown, and ``tox`` can
+   also be run to test different Python versions.
+
+To record new cassettes, the following environment variables can be used:
+
+``TWITTER_USERNAME``
+``CONSUMER_KEY``
+``CONSUMER_SECRET``
+``ACCESS_KEY``
+``ACCESS_SECRET``
+``USE_REPLAY``
+
+Simply set ``USE_REPLAY`` to ``False`` and provide the app and account
+credentials and username.
diff --git a/docs/streaming_how_to.rst b/docs/streaming_how_to.rst
new file mode 100644 (file)
index 0000000..81d1539
--- /dev/null
@@ -0,0 +1,124 @@
+.. _streaming_how_to:
+.. _Twitter Streaming API Documentation: https://developer.twitter.com/en/docs/tweets/filter-realtime/overview
+.. _Twitter Streaming API Connecting Documentation: https://developer.twitter.com/en/docs/tutorials/consuming-streaming-data
+.. _Twitter Response Codes Documentation: https://dev.twitter.com/overview/api/response-codes
+
+*********************
+Streaming With Tweepy
+*********************
+Tweepy makes it easier to use the twitter streaming api by handling authentication, 
+connection, creating and destroying the session, reading incoming messages, 
+and partially routing messages. 
+
+This page aims to help you get started using Twitter streams with Tweepy 
+by offering a first walk through.  Some features of Tweepy streaming are
+not covered here. See streaming.py in the Tweepy source code. 
+
+API authorization is required to access Twitter streams. 
+Follow the :ref:`auth_tutorial` if you need help with authentication. 
+
+Summary
+=======
+The Twitter streaming API is used to download twitter messages in real 
+time.  It is useful for obtaining a high volume of tweets, or for 
+creating a live feed using a site stream or user stream. 
+See the `Twitter Streaming API Documentation`_.
+
+The streaming api is quite different from the REST api because the
+REST api is used to *pull* data from twitter but the streaming api
+*pushes* messages to a persistent session. This allows the streaming 
+api to download more data in real time than could be done using the
+REST API. 
+
+In Tweepy, an instance of **tweepy.Stream** establishes a streaming 
+session and routes messages to **StreamListener** instance.  The
+**on_data** method of a stream listener receives all messages and
+calls functions according to the message type. The default 
+**StreamListener** can classify most common twitter messages and 
+routes them to appropriately named methods, but these methods are 
+only stubs. 
+
+Therefore using the streaming api has three steps. 
+
+1. Create a class inheriting from **StreamListener**
+
+2. Using that class create a **Stream** object 
+
+3. Connect to the Twitter API using the **Stream**.
+
+
+Step 1: Creating a **StreamListener**
+=====================================
+This simple stream listener prints status text.
+The **on_data** method of Tweepy's **StreamListener** conveniently passes 
+data from statuses to the **on_status** method.
+Create class **MyStreamListener** inheriting from  **StreamListener** 
+and overriding **on_status**.::
+  import tweepy
+  #override tweepy.StreamListener to add logic to on_status
+  class MyStreamListener(tweepy.StreamListener):
+  
+      def on_status(self, status):
+          print(status.text)
+
+Step 2: Creating a **Stream**
+=============================
+We need an api to stream. See :ref:`auth_tutorial` to learn how to get an api object. 
+Once we have an api and a status listener we can create our stream object.::
+
+  myStreamListener = MyStreamListener()
+  myStream = tweepy.Stream(auth = api.auth, listener=myStreamListener)
+
+Step 3: Starting a Stream
+=========================
+A number of twitter streams are available through Tweepy. Most cases 
+will use filter, the user_stream, or the sitestream. 
+For more information on the capabilities and limitations of the different
+streams see `Twitter Streaming API Documentation`_.
+
+In this example we will use **filter** to stream all tweets containing
+the word *python*. The **track** parameter is an array of search terms to stream. ::
+  
+  myStream.filter(track=['python'])
+
+This example shows how to use **filter** to stream tweets by a specific user. The **follow** parameter is an array of IDs. ::
+
+  myStream.filter(follow=["2211149702"])
+
+An easy way to find a single ID is to use one of the many conversion websites: search for 'what is my twitter ID'.
+
+A Few More Pointers
+===================
+
+Async Streaming
+---------------
+Streams do not terminate unless the connection is closed, blocking the thread. 
+Tweepy offers a convenient **is_async** parameter on **filter** so the stream will run on a new
+thread. For example ::
+
+  myStream.filter(track=['python'], is_async=True)
+
+Handling Errors
+---------------
+When using Twitter's streaming API one must be careful of the dangers of 
+rate limiting. If clients exceed a limited number of attempts to connect to the streaming API 
+in a window of time, they will receive error 420.  The amount of time a client has to wait after receiving error 420
+will increase exponentially each time they make a failed attempt. 
+
+Tweepy's **Stream Listener** passes error codes to an **on_error** stub. The
+default implementation returns **False** for all codes, but we can override it
+to allow Tweepy to reconnect for some or all codes, using the backoff
+strategies recommended in the `Twitter Streaming API Connecting
+Documentation`_. ::
+
+  class MyStreamListener(tweepy.StreamListener):
+  
+      def on_error(self, status_code):
+          if status_code == 420:
+              #returning False in on_error disconnects the stream
+              return False
+
+          # returning non-False reconnects the stream, with backoff.
+
+For more information on error codes from the Twitter API see `Twitter Response Codes Documentation`_.
+