From c8a02eb61b36ac710010b67ff0ed7b8374ef9375 Mon Sep 17 00:00:00 2001 From: Harmon Date: Fri, 17 Mar 2023 06:29:51 -0500 Subject: [PATCH] Remove Stream and AsyncStream https://twittercommunity.com/t/announcing-the-deprecation-of-v1-1-statuses-filter-endpoint/182960 --- docs/asyncstream.rst | 12 -- docs/examples.rst | 4 - docs/extended_tweets.rst | 38 ----- docs/faq.rst | 15 +- docs/index.rst | 2 - docs/stream.rst | 12 -- docs/streaming.rst | 100 +++--------- examples/API_v1/streaming.py | 22 --- tweepy/__init__.py | 2 +- tweepy/asynchronous/__init__.py | 2 +- tweepy/asynchronous/streaming.py | 263 ------------------------------- tweepy/streaming.py | 252 ----------------------------- 12 files changed, 24 insertions(+), 700 deletions(-) delete mode 100644 docs/asyncstream.rst delete mode 100644 docs/stream.rst delete mode 100644 examples/API_v1/streaming.py diff --git a/docs/asyncstream.rst b/docs/asyncstream.rst deleted file mode 100644 index f77b1d8..0000000 --- a/docs/asyncstream.rst +++ /dev/null @@ -1,12 +0,0 @@ -.. _asyncstream_reference: - -.. currentmodule:: tweepy.asynchronous - -******************** -:class:`AsyncStream` -******************** - -.. autoclass:: AsyncStream - :members: - :inherited-members: - :member-order: bysource diff --git a/docs/examples.rst b/docs/examples.rst index c113867..0b0fef6 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -30,10 +30,6 @@ Examples .. literalinclude:: ../examples/API_v1/rate_limit_handling.py - .. tab:: Streaming - - .. literalinclude:: ../examples/API_v1/streaming.py - .. tab:: API v2 .. tabs:: diff --git a/docs/extended_tweets.rst b/docs/extended_tweets.rst index 2389419..b0a4c28 100644 --- a/docs/extended_tweets.rst +++ b/docs/extended_tweets.rst @@ -59,20 +59,6 @@ contain all entities. Additionally, the Status object will have a 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 ================= @@ -83,12 +69,6 @@ containing the full text of the Retweet. However, since the 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 ======== @@ -104,24 +84,6 @@ full text of the Retweeted Tweet:: If ``status`` is a Retweet, ``status.full_text`` could be truncated. -This Status event handler for a :class:`Stream` 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 diff --git a/docs/faq.rst b/docs/faq.rst index ffdf5f8..eaaf140 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -27,7 +27,7 @@ Why am I encountering a 403 Forbidden error with :class:`API`? -------------------------------------------------------------- If you have Essential access to the Twitter API, you won't be able to access -Twitter API v1.1. This includes all :class:`API` methods and :class:`Stream`. +Twitter API v1.1. This includes all :class:`API` methods. You can use Twitter API v2 with :class:`Client` or apply for Elevated access. @@ -86,19 +86,6 @@ This is because :ref:`Tweepy v4.0.0 ` removed Instead, you can use :meth:`API.verify_credentials`. -Where did ``StreamListener`` go? --------------------------------- - -If you're attempting to import ``StreamListener`` with Tweepy v4, you'll get an -:class:`AttributeError` about ``tweepy`` not having a ``StreamListener`` -attribute. - -This is because :ref:`Tweepy v4.0.0 ` merged -``StreamListener`` into :class:`Stream`. - -To use Tweepy v4, you'll need to update your code to subclass :class:`Stream` -instead. - Twitter API v2 ============== diff --git a/docs/index.rst b/docs/index.rst index 2ac23a3..24382c5 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -21,8 +21,6 @@ Contents: :caption: Twitter API v1.1 Reference api.rst - stream.rst - asyncstream.rst exceptions.rst v1_models.rst v1_pagination.rst diff --git a/docs/stream.rst b/docs/stream.rst deleted file mode 100644 index c92a12c..0000000 --- a/docs/stream.rst +++ /dev/null @@ -1,12 +0,0 @@ -.. _stream_reference: - -.. currentmodule:: tweepy - -*************** -:class:`Stream` -*************** - -.. autoclass:: Stream - :members: - :inherited-members: - :member-order: bysource diff --git a/docs/streaming.rst b/docs/streaming.rst index 95a3641..c2154cd 100644 --- a/docs/streaming.rst +++ b/docs/streaming.rst @@ -15,60 +15,17 @@ results in a low-latency delivery mechanism that can support very high throughput. For further information, see https://developer.twitter.com/en/docs/tutorials/consuming-streaming-data -:class:`Stream` allows `filtering `_ and -`sampling `_ of realtime Tweets using Twitter API v1.1. +The Twitter API v1.1 streaming endpoints, `statuses/filter`_ and +`statuses/sample`_, have been deprecated and retired. :class:`StreamingClient` allows `filtering `_ and `sampling `_ of realtime Tweets using Twitter API v2. -.. _v1.1 filtering: https://developer.twitter.com/en/docs/twitter-api/v1/tweets/filter-realtime/overview -.. _v1.1 sampling: https://developer.twitter.com/en/docs/twitter-api/v1/tweets/sample-realtime/overview +.. _statuses/filter: https://twittercommunity.com/t/announcing-the-deprecation-of-v1-1-statuses-filter-endpoint/182960 +.. _statuses/sample: https://twittercommunity.com/t/deprecation-announcement-removing-compliance-messages-from-statuses-filter-and-retiring-statuses-sample-from-the-twitter-api-v1-1/170500 .. _v2 filtering: https://developer.twitter.com/en/docs/twitter-api/tweets/filtered-stream/introduction .. _v2 sampling: https://developer.twitter.com/en/docs/twitter-api/tweets/volume-streams/introduction -Using :class:`Stream` -===================== - -To use :class:`Stream`, an instance of it needs to be initialized with Twitter -API credentials (Consumer Key, Consumer Secret, Access Token, Access Token -Secret):: - - import tweepy - - stream = tweepy.Stream( - "Consumer Key here", "Consumer Secret here", - "Access Token here", "Access Token Secret here" - ) - -Then, :meth:`Stream.filter` or :meth:`Stream.sample` can be used to connect to -and run a stream:: - - stream.filter(track=["Tweepy"]) - -Data received from the stream is passed to :meth:`Stream.on_data`. This method -handles sending the data to other methods based on the message type. For -example, if a Tweet is received from the stream, the raw data is sent to -:meth:`Stream.on_data`, which constructs a :class:`Status` object and passes it -to :meth:`Stream.on_status`. By default, the other methods, besides -:meth:`Stream.on_data`, that receive the data from the stream, simply log the -data received, with the :ref:`logging level ` dependent on the -type of the data. - -To customize the processing of the stream data, :class:`Stream` needs to be -subclassed. For example, to print the IDs of every Tweet received:: - - class IDPrinter(tweepy.Stream): - - def on_status(self, status): - print(status.id) - - - printer = IDPrinter( - "Consumer Key here", "Consumer Secret here", - "Access Token here", "Access Token Secret here" - ) - printer.sample() - Using :class:`StreamingClient` ============================== @@ -122,57 +79,42 @@ subclassed. For example, to print the IDs of every Tweet received:: Threading ========= -:meth:`Stream.filter`, :meth:`Stream.sample`, :meth:`StreamingClient.filter`, -and :meth:`StreamingClient.sample` all have a ``threaded`` parameter. When set -to ``True``, the stream will run in a separate +:meth:`StreamingClient.filter` and :meth:`StreamingClient.sample` have a +``threaded`` parameter. When set to ``True``, the stream will run in a separate :ref:`thread `, which is returned by the call to the method. For example:: - thread = stream.filter(follow=[1072250532645998596], threaded=True) - -or:: - thread = streaming_client.sample(threaded=True) Handling Errors =============== -Both :class:`Stream` and :class:`StreamingClient` have multiple methods to -handle errors during streaming. +:class:`StreamingClient` has multiple methods to handle errors during +streaming. -:meth:`Stream.on_closed` / :meth:`StreamingClient.on_closed` is called when the -stream is closed by Twitter. +:meth:`StreamingClient.on_closed` is called when the stream is closed by +Twitter. -:meth:`Stream.on_connection_error` / :meth:`StreamingClient.on_connection_error` is called when the stream encounters a connection error. -:meth:`Stream.on_request_error` / :meth:`StreamingClient.on_request_error` is -called when an error is encountered while trying to connect to the stream. +:meth:`StreamingClient.on_request_error` is called when an error is encountered +while trying to connect to the stream. When these errors are encountered and ``max_retries``, which defaults to -infinite, hasn't been exceeded yet, the :class:`Stream` / -:class:`StreamingClient` instance will attempt to reconnect the stream after an -appropriate amount of time. By default, both versions of all three of these -methods log an error. To customize that handling, they can be overridden in a -subclass:: - - class ConnectionTester(tweepy.Stream): - - def on_connection_error(self): - self.disconnect() - -:: +infinite, hasn't been exceeded yet, the :class:`StreamingClient` instance will +attempt to reconnect the stream after an appropriate amount of time. By +default, all three of these methods log an error. To customize that handling, +they can be overridden in a subclass:: class ConnectionTester(tweepy.StreamingClient): def on_connection_error(self): self.disconnect() -:meth:`Stream.on_request_error` / :meth:`StreamingClient.on_request_error` is -also passed the HTTP status code that was encountered. The HTTP status codes -reference for the Twitter API can be found at +:meth:`StreamingClient.on_request_error` is also passed the HTTP status code +that was encountered. The HTTP status codes reference for the Twitter API can +be found at https://developer.twitter.com/en/support/twitter-api/error-troubleshooting. -:meth:`Stream.on_exception` / :meth:`StreamingClient.on_exception` is called -when an unhandled exception occurs. This is fatal to the stream, and by -default, an exception is logged. +:meth:`StreamingClient.on_exception` is called when an unhandled exception +occurs. This is fatal to the stream, and by default, an exception is logged. diff --git a/examples/API_v1/streaming.py b/examples/API_v1/streaming.py deleted file mode 100644 index 1349c3a..0000000 --- a/examples/API_v1/streaming.py +++ /dev/null @@ -1,22 +0,0 @@ -import tweepy - - -consumer_key = "" -consumer_secret = "" -access_token = "" -access_token_secret = "" - -# Subclass Stream to print IDs of Tweets received -class IDPrinter(tweepy.Stream): - - def on_status(self, status): - print(status.id) - -# Initialize instance of the subclass -printer = IDPrinter( - consumer_key, consumer_secret, - access_token, access_token_secret -) - -# Filter realtime Tweets by keyword -printer.filter(track=["Twitter"]) diff --git a/tweepy/__init__.py b/tweepy/__init__.py index 05690f9..8c91250 100644 --- a/tweepy/__init__.py +++ b/tweepy/__init__.py @@ -29,7 +29,7 @@ from tweepy.place import Place from tweepy.poll import Poll from tweepy.space import Space from tweepy.streaming import ( - Stream, StreamingClient, StreamResponse, StreamRule + StreamingClient, StreamResponse, StreamRule ) from tweepy.tweet import ReferencedTweet, Tweet from tweepy.user import User diff --git a/tweepy/asynchronous/__init__.py b/tweepy/asynchronous/__init__.py index 4281ef5..2a5e7fc 100644 --- a/tweepy/asynchronous/__init__.py +++ b/tweepy/asynchronous/__init__.py @@ -21,4 +21,4 @@ except ModuleNotFoundError: from tweepy.asynchronous.client import AsyncClient from tweepy.asynchronous.pagination import AsyncPaginator -from tweepy.asynchronous.streaming import AsyncStream, AsyncStreamingClient +from tweepy.asynchronous.streaming import AsyncStreamingClient diff --git a/tweepy/asynchronous/streaming.py b/tweepy/asynchronous/streaming.py index 2ed0ee9..3275f8e 100644 --- a/tweepy/asynchronous/streaming.py +++ b/tweepy/asynchronous/streaming.py @@ -10,14 +10,11 @@ from platform import python_version import traceback import aiohttp -from oauthlib.oauth1 import Client as OAuthClient -from yarl import URL import tweepy from tweepy.asynchronous.client import AsyncBaseClient from tweepy.client import Response from tweepy.errors import TweepyException -from tweepy.models import Status from tweepy.streaming import StreamResponse, StreamRule from tweepy.tweet import Tweet @@ -207,266 +204,6 @@ class AsyncBaseStream: log.error("Stream encountered HTTP Error: %d", status_code) -class AsyncStream(AsyncBaseStream): - """Stream realtime Tweets asynchronously with Twitter API v1.1 - - .. deprecated:: 4.13 - `The Twitter API v1.1 streaming statuses/filter endpoint that`_ - :class:`AsyncStream` `uses has a formal deprecation date of - March 9, 2023.`_ - - .. note:: - - New Twitter Developer Apps created on or after April 29, 2022 `will not - be able to gain access to v1.1 statuses/filter`_, the Twitter API v1.1 - endpoint that :class:`AsyncStream` uses. Twitter API v2 can be used - instead with :class:`AsyncStreamingClient`. - - .. versionadded:: 4.0 - - .. versionchanged:: 4.13 - Removed ``sample``, ``on_delete``, ``on_scrub_geo``, - ``on_status_withheld``, and ``on_user_withheld`` methods, as `the - Twitter API v1.1 statuses/sample endpoint and compliance messages on - the Twitter API v1.1 statuses/filter endpoint have been retired`_ - - Parameters - ---------- - consumer_key: str - Twitter API Consumer Key - consumer_secret: str - Twitter API Consumer Secret - access_token: str - Twitter API Access Token - access_token_secret: str - Twitter API Access Token Secret - max_retries: int | None - Number of times to attempt to (re)connect the stream. - proxy: str | None - URL of the proxy to use when connecting to the stream - - Attributes - ---------- - session : aiohttp.ClientSession | None - Aiohttp client session used to connect to the API - task : asyncio.Task | None - The task running the stream - user_agent : str - User agent used when connecting to the API - - - .. _will not be able to gain access to v1.1 statuses/filter: https://twittercommunity.com/t/deprecation-announcement-removing-compliance-messages-from-statuses-filter-and-retiring-statuses-sample-from-the-twitter-api-v1-1/170500 - .. _the Twitter API v1.1 statuses/sample endpoint and compliance messages - on the Twitter API v1.1 statuses/filter endpoint have been retired: https://twittercommunity.com/t/deprecation-announcement-removing-compliance-messages-from-statuses-filter-and-retiring-statuses-sample-from-the-twitter-api-v1-1/170500 - .. _The Twitter API v1.1 streaming statuses/filter endpoint that: https://twittercommunity.com/t/announcing-the-deprecation-of-v1-1-statuses-filter-endpoint/182960 - .. _uses has a formal deprecation date of March 9, 2023.: https://twittercommunity.com/t/announcing-the-deprecation-of-v1-1-statuses-filter-endpoint/182960 - """ - - def __init__(self, consumer_key, consumer_secret, access_token, - access_token_secret, **kwargs): - """__init__( \ - consumer_key, consumer_secret, access_token, access_token_secret, \ - *, max_retries=inf, proxy=None \ - ) - """ - self.consumer_key = consumer_key - self.consumer_secret = consumer_secret - self.access_token = access_token - self.access_token_secret = access_token_secret - super().__init__(**kwargs) - - async def _connect( - self, method, endpoint, params={}, headers=None, body=None - ): - oauth_client = OAuthClient(self.consumer_key, self.consumer_secret, - self.access_token, self.access_token_secret) - url = f"https://stream.twitter.com/1.1/{endpoint}.json" - url = str(URL(url).with_query(sorted(params.items()))) - await super()._connect( - method, url, headers=headers, body=body, oauth_client=oauth_client, - timeout=90 - ) - - def filter(self, *, follow=None, track=None, locations=None, - filter_level=None, languages=None, stall_warnings=False): - """Filter realtime Tweets - - .. deprecated:: 4.10 - `The delivery of compliance messages through the Twitter API v1.1 - endpoint this method uses has been deprecated, and they will stop - being delivered beginning October 29, 2022.`_ Twitter API v2 can be - used instead with :meth:`AsyncStreamingClient.filter` and/or - :class:`AsyncClient` :ref:`batch compliance ` - methods. - - Parameters - ---------- - follow: list[int | str] | None - A list of user IDs, indicating the users to return statuses for in - the stream. See https://developer.twitter.com/en/docs/twitter-api/v1/tweets/filter-realtime/guides/basic-stream-parameters - for more information. - track: list[str] | None - Keywords to track. Phrases of keywords are specified by a list. See - https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters - for more information. - locations: list[float] | None - Specifies a set of bounding boxes to track. See - https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters - for more information. - filter_level : str | None - Setting this parameter to one of none, low, or medium will set the - minimum value of the filter_level Tweet attribute required to be - included in the stream. The default value is none, which includes - all available Tweets. - - When displaying a stream of Tweets to end users (dashboards or live - feeds at a presentation or conference, for example) it is suggested - that you set this value to medium. - languages : list[str] | None - Setting this parameter to a comma-separated list of `BCP 47`_ - language identifiers corresponding to any of the languages listed - on Twitter’s `advanced search`_ page will only return Tweets that - have been detected as being written in the specified languages. For - example, connecting with language=en will only stream Tweets - detected to be in the English language. - stall_warnings: bool | None - Specifies whether stall warnings should be delivered. See - https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters - for more information. - - Raises - ------ - TweepyException - When the stream is already connected or when the number of location - coordinates is not a multiple of 4 - - Returns - ------- - asyncio.Task - The task running the stream - - References - ---------- - https://developer.twitter.com/en/docs/twitter-api/v1/tweets/filter-realtime/api-reference/post-statuses-filter - - .. _BCP 47: https://tools.ietf.org/html/bcp47 - .. _advanced search: https://twitter.com/search-advanced - .. _The delivery of compliance messages through the Twitter API v1.1 - endpoint this method uses has been deprecated, and they will stop - being delivered beginning October 29, 2022.: https://twittercommunity.com/t/deprecation-announcement-removing-compliance-messages-from-statuses-filter-and-retiring-statuses-sample-from-the-twitter-api-v1-1/170500 - """ - if self.task is not None and not self.task.done(): - raise TweepyException("Stream is already connected") - - endpoint = "statuses/filter" - headers = {"Content-Type": "application/x-www-form-urlencoded"} - - body = {} - if follow is not None: - body["follow"] = ','.join(map(str, follow)) - if track is not None: - body["track"] = ','.join(map(str, track)) - if locations is not None: - if len(locations) % 4: - raise TweepyException( - "Number of location coordinates should be a multiple of 4" - ) - body["locations"] = ','.join( - f"{location:.4f}" for location in locations - ) - if filter_level is not None: - body["filter_level"] = filter_level - if languages is not None: - body["language"] = ','.join(map(str, languages)) - if stall_warnings: - body["stall_warnings"] = "true" - - self.task = asyncio.create_task( - self._connect("POST", endpoint, headers=headers, body=body or None) - ) - # Use name parameter when support for Python 3.7 is dropped - return self.task - - async def on_data(self, raw_data): - """|coroutine| - - This is called when raw data is received from the stream. - This method handles sending the data to other methods, depending on the - message type. - - Parameters - ---------- - raw_data : JSON - The raw data from the stream - - References - ---------- - https://developer.twitter.com/en/docs/twitter-api/v1/tweets/filter-realtime/guides/streaming-message-types - """ - data = json.loads(raw_data) - - if "in_reply_to_status_id" in data: - status = Status.parse(None, data) - return await self.on_status(status) - if "disconnect" in data: - return await self.on_disconnect_message(data["disconnect"]) - if "limit" in data: - return await self.on_limit(data["limit"]["track"]) - if "warning" in data: - return await self.on_warning(data["warning"]) - - log.warning("Received unknown message type: %s", raw_data) - - async def on_status(self, status): - """|coroutine| - - This is called when a status is received. - - Parameters - ---------- - status : Status - The Status received - """ - log.debug("Received status: %d", status.id) - - async def on_disconnect_message(self, message): - """|coroutine| - - This is called when a disconnect message is received. - - Parameters - ---------- - message : JSON - The disconnect message - """ - log.warning("Received disconnect message: %s", message) - - async def on_limit(self, track): - """|coroutine| - - This is called when a limit notice is received. - - Parameters - ---------- - track : int - Total count of the number of undelivered Tweets since the - connection was opened - """ - log.debug("Received limit notice: %d", track) - - async def on_warning(self, notice): - """|coroutine| - - This is called when a stall warning message is received. - - Parameters - ---------- - warning : JSON - The stall warning - """ - log.warning("Received stall warning: %s", notice) - - class AsyncStreamingClient(AsyncBaseClient, AsyncBaseStream): """Stream realtime Tweets asynchronously with Twitter API v2 diff --git a/tweepy/streaming.py b/tweepy/streaming.py index 327e0e4..4d9d6fb 100644 --- a/tweepy/streaming.py +++ b/tweepy/streaming.py @@ -16,13 +16,11 @@ from time import sleep from typing import NamedTuple import requests -from requests_oauthlib import OAuth1 import urllib3 import tweepy from tweepy.client import BaseClient, Response from tweepy.errors import TweepyException -from tweepy.models import Status from tweepy.tweet import Tweet log = logging.getLogger(__name__) @@ -217,256 +215,6 @@ class BaseStream: log.error("Stream encountered HTTP error: %d", status_code) -class Stream(BaseStream): - """Filter realtime Tweets with Twitter API v1.1 - - .. deprecated:: 4.13 - `The Twitter API v1.1 streaming statuses/filter endpoint that`_ - :class:`Stream` `uses has a formal deprecation date of March 9, 2023.`_ - - .. note:: - - New Twitter Developer Apps created on or after April 29, 2022 `will not - be able to gain access to v1.1 statuses/filter`_, the Twitter API v1.1 - endpoint that :class:`Stream` uses. Twitter API v2 can be used instead - with :class:`StreamingClient`. - - .. versionchanged:: 4.13 - Removed ``sample``, ``on_delete``, ``on_scrub_geo``, - ``on_status_withheld``, and ``on_user_withheld`` methods, as `the - Twitter API v1.1 statuses/sample endpoint and compliance messages on - the Twitter API v1.1 statuses/filter endpoint have been retired`_ - - Parameters - ---------- - consumer_key : str - Twitter API Consumer Key - consumer_secret : str - Twitter API Consumer Secret - access_token: str - Twitter API Access Token - access_token_secret : str - Twitter API Access Token Secret - chunk_size : int - The default socket.read size. Default to 512, less than half the size - of a Tweet so that it reads Tweets with the minimal latency of 2 reads - per Tweet. Values higher than ~1kb will increase latency by waiting for - more data to arrive but may also increase throughput by doing fewer - socket read calls. - daemon : bool - Whether or not to use a daemon thread when using a thread to run the - stream - max_retries : int - Max number of times to retry connecting the stream - proxy : str | None - URL of the proxy to use when connecting to the stream - verify : bool | str - Either a boolean, in which case it controls whether to verify the - server’s TLS certificate, or a string, in which case it must be a path - to a CA bundle to use. - - Attributes - ---------- - running : bool - Whether there's currently a stream running - session : :class:`requests.Session` - Requests Session used to connect to the stream - thread : :class:`threading.Thread` | None - Thread used to run the stream - user_agent : str - User agent used when connecting to the stream - - - .. _will not be able to gain access to v1.1 statuses/filter: https://twittercommunity.com/t/deprecation-announcement-removing-compliance-messages-from-statuses-filter-and-retiring-statuses-sample-from-the-twitter-api-v1-1/170500 - .. _the Twitter API v1.1 statuses/sample endpoint and compliance messages - on the Twitter API v1.1 statuses/filter endpoint have been retired: https://twittercommunity.com/t/deprecation-announcement-removing-compliance-messages-from-statuses-filter-and-retiring-statuses-sample-from-the-twitter-api-v1-1/170500 - .. _The Twitter API v1.1 streaming statuses/filter endpoint that: https://twittercommunity.com/t/announcing-the-deprecation-of-v1-1-statuses-filter-endpoint/182960 - .. _uses has a formal deprecation date of March 9, 2023.: https://twittercommunity.com/t/announcing-the-deprecation-of-v1-1-statuses-filter-endpoint/182960 - """ - - def __init__(self, consumer_key, consumer_secret, access_token, - access_token_secret, **kwargs): - """__init__( \ - consumer_key, consumer_secret, access_token, access_token_secret, \ - chunk_size=512, daemon=False, max_retries=inf, proxy=None, \ - verify=True \ - ) - """ - self.consumer_key = consumer_key - self.consumer_secret = consumer_secret - self.access_token = access_token - self.access_token_secret = access_token_secret - super().__init__(**kwargs) - - def _connect(self, method, endpoint, **kwargs): - auth = OAuth1(self.consumer_key, self.consumer_secret, - self.access_token, self.access_token_secret) - url = f"https://stream.twitter.com/1.1/{endpoint}.json" - super()._connect(method, url, auth=auth, timeout=90, **kwargs) - - def filter(self, *, follow=None, track=None, locations=None, - filter_level=None, languages=None, stall_warnings=False, - threaded=False): - """Filter realtime Tweets - - .. deprecated:: 4.9 - `The delivery of compliance messages through the Twitter API v1.1 - endpoint this method uses has been deprecated, and they will stop - being delivered beginning October 29, 2022.`_ Twitter API v2 can be - used instead with :meth:`StreamingClient.filter` and/or - :class:`Client` :ref:`batch compliance ` methods. - - Parameters - ---------- - follow : list[int | str] | None - User IDs, indicating the users to return statuses for in the stream - track : list[str] | None - Keywords to track - locations : list[float] | None - Specifies a set of bounding boxes to track - filter_level : str | None - Setting this parameter to one of none, low, or medium will set the - minimum value of the filter_level Tweet attribute required to be - included in the stream. The default value is none, which includes - all available Tweets. - - When displaying a stream of Tweets to end users (dashboards or live - feeds at a presentation or conference, for example) it is suggested - that you set this value to medium. - languages : list[str] | None - Setting this parameter to a comma-separated list of `BCP 47`_ - language identifiers corresponding to any of the languages listed - on Twitter’s `advanced search`_ page will only return Tweets that - have been detected as being written in the specified languages. For - example, connecting with language=en will only stream Tweets - detected to be in the English language. - stall_warnings : bool - Specifies whether stall warnings should be delivered - threaded : bool - Whether or not to use a thread to run the stream - - Raises - ------ - TweepyException - When the stream is already connected or when the number of location - coordinates is not a multiple of 4 - - Returns - ------- - threading.Thread | None - The thread if ``threaded`` is set to ``True``, else ``None`` - - References - ---------- - https://developer.twitter.com/en/docs/twitter-api/v1/tweets/filter-realtime/api-reference/post-statuses-filter - - .. _BCP 47: https://tools.ietf.org/html/bcp47 - .. _advanced search: https://twitter.com/search-advanced - .. _The delivery of compliance messages through the Twitter API v1.1 - endpoint this method uses has been deprecated, and they will stop - being delivered beginning October 29, 2022.: https://twittercommunity.com/t/deprecation-announcement-removing-compliance-messages-from-statuses-filter-and-retiring-statuses-sample-from-the-twitter-api-v1-1/170500 - """ - if self.running: - raise TweepyException("Stream is already connected") - - method = "POST" - endpoint = "statuses/filter" - headers = {"Content-Type": "application/x-www-form-urlencoded"} - - body = {} - if follow: - body["follow"] = ','.join(map(str, follow)) - if track: - body["track"] = ','.join(map(str, track)) - if locations and len(locations) > 0: - if len(locations) % 4: - raise TweepyException( - "Number of location coordinates should be a multiple of 4" - ) - body["locations"] = ','.join(f"{l:.4f}" for l in locations) - if filter_level: - body["filter_level"] = filter_level - if languages: - body["language"] = ','.join(map(str, languages)) - if stall_warnings: - body["stall_warnings"] = stall_warnings - - if threaded: - return self._threaded_connect(method, endpoint, headers=headers, - body=body) - else: - self._connect(method, endpoint, headers=headers, body=body) - - def on_data(self, raw_data): - """This is called when raw data is received from the stream. - This method handles sending the data to other methods based on the - message type. - - Parameters - ---------- - raw_data : JSON - The raw data from the stream - - References - ---------- - https://developer.twitter.com/en/docs/twitter-api/v1/tweets/filter-realtime/guides/streaming-message-types - """ - data = json.loads(raw_data) - - if "in_reply_to_status_id" in data: - status = Status.parse(None, data) - return self.on_status(status) - if "disconnect" in data: - return self.on_disconnect_message(data["disconnect"]) - if "limit" in data: - return self.on_limit(data["limit"]["track"]) - if "warning" in data: - return self.on_warning(data["warning"]) - - log.error("Received unknown message type: %s", raw_data) - - def on_status(self, status): - """This is called when a status is received. - - Parameters - ---------- - status : Status - The Status received - """ - log.debug("Received status: %d", status.id) - - def on_disconnect_message(self, message): - """This is called when a disconnect message is received. - - Parameters - ---------- - message : JSON - The disconnect message - """ - log.warning("Received disconnect message: %s", message) - - def on_limit(self, track): - """This is called when a limit notice is received. - - Parameters - ---------- - track : int - Total count of the number of undelivered Tweets since the - connection was opened - """ - log.debug("Received limit notice: %d", track) - - def on_warning(self, warning): - """This is called when a stall warning message is received. - - Parameters - ---------- - warning : JSON - The stall warning - """ - log.warning("Received stall warning: %s", warning) - - class StreamingClient(BaseClient, BaseStream): """Filter and sample realtime Tweets with Twitter API v2 -- 2.25.1