
    QdM                        d Z ddlZddlZddlZddlZddlZddlZddlZddlm	Z	m
Z
 ddlmZmZ ddlmZmZ ddlmZmZ  G d de
          Z G d	 d
e	          Z G d d          Z G d de          Z G d de          ZdS )ai  
NLTK Twitter client

This module offers methods for collecting and processing Tweets. Most of the
functionality depends on access to the Twitter APIs, and this is handled via
the third party Twython library.

If one of the methods below returns an integer, it is probably a `Twitter
error code <https://dev.twitter.com/overview/api/response-codes>`_. For
example, the response of '420' means that you have reached the limit of the
requests you can currently make to the Twitter API. Currently, `rate limits
for the search API <https://dev.twitter.com/rest/public/rate-limiting>`_ are
divided into 15 minute windows.
    N)TwythonTwythonStreamer)TwythonErrorTwythonRateLimitError)BasicTweetHandlerTweetHandlerI)credsfromfile
guess_pathc                   8    e Zd ZdZd Zd Zd Zd Zd Zdd	Z	d
S )Streamerz
    Retrieve data from the Twitter Streaming API.

    The streaming API requires
    `OAuth 1.0 <https://en.wikipedia.org/wiki/OAuth>`_ authentication.
    c                 R    d | _         d| _        t          j        | ||||           d S )NT)handlerdo_continuer   __init__selfapp_key
app_secretoauth_tokenoauth_token_secrets        :lib/python3.11/site-packages/nltk/twitter/twitterclient.pyr   zStreamer.__init__0   s<     ':{4F	
 	
 	
 	
 	
    c                     || _         dS )zr
        Register a method for handling Tweets.

        :param TweetHandlerI handler: method for viewing
        Nr   r   r   s     r   registerzStreamer.register8        r   c                 D   | j         rk| j        Ud|v rO| j        xj        dz  c_        | j                            |           | j                                         | _         dS dS t	          d          |                                  | j                                         dS )z8
        :param data: response from Twitter API
        Ntext   z$No data handler has been registered.)r   r   counterhandle
ValueError
disconnect	on_finish)r   datas     r   
on_successzStreamer.on_success@   s      
	%|'T>>L((A-((L''---'+|'?'?'A'AD$$$ ">
 !!GHHHOOL""$$$$$r   c                 $    t          |           dS )z
        :param status_code: The status code returned by the Twitter API
        :param data: The response from Twitter API

        N)print)r   status_coder&   s      r   on_errorzStreamer.on_errorP   s     	kr   c                     | j         rY	 | j                                         n5# t          j        j        $ r}|t          d|            Y d}~Od}~ww xY w| j         WdS dS )z:
        Wrapper for 'statuses / sample' API call
        NError (stream will continue): )r   statusessamplerequests
exceptionsChunkedEncodingErrorr)   )r   es     r   r/   zStreamer.sampleX   s      	$$&&&&&;   =>1>>???  	 	 	 	 	s   # AAA enc                    | j         rz	 |dk    r|dk    rd}t          |          | j                            |||           n5# t          j        j        $ r}|t          d|            Y d}~pd}~ww xY w| j         xdS dS )z:
        Wrapper for 'statuses / filter' API call
        r4   z+Please supply a value for 'track', 'follow'trackfollowlangNr-   )r   r#   r.   filterr0   r1   r2   r)   )r   r8   r9   r:   msgr3   s         r   r;   zStreamer.filteri   s      	B;;6R<<GC$S//)$$5d$KKKK&;   =>1>>???  	 	 	 	 	s   :A A6A11A6N)r4   r4   r5   )
__name__
__module____qualname____doc__r   r   r'   r+   r/   r;    r   r   r   r   (   s}         
 
 
  % % %     "     r   r   c                   L    e Zd ZdZd Zd ZddZddZ	 	 	 	 ddZd Z	ddZ
d	S )Queryz2
    Retrieve data from the Twitter REST API.
    c                 R    d| _         d| _        t          j        | ||||           dS )a  
        :param app_key: (optional) Your applications key
        :param app_secret: (optional) Your applications secret key
        :param oauth_token: (optional) When using **OAuth 1**, combined with
            oauth_token_secret to make authenticated calls
        :param oauth_token_secret: (optional) When using **OAuth 1** combined
            with oauth_token to make authenticated calls
        NT)r   r   r   r   r   s        r   r   zQuery.__init__   s3     w
KASTTTTTr   c                     || _         dS )z
        Register a method for handling Tweets.

        :param TweetHandlerI handler: method for viewing or writing Tweets to a file.
        Nr   r   s     r   r   zQuery.register   r   r   Tc                     d |D             |r#t          dt                     d| d           fdt          dt                    d          D             } fd|D             }t          j                            |          S )	a  
        Given a file object containing a list of Tweet IDs, fetch the
        corresponding full Tweets from the Twitter API.

        The API call `statuses/lookup` will fail to retrieve a Tweet if the
        user has deleted it.

        This call to the Twitter API is rate-limited. See
        <https://dev.twitter.com/rest/reference/get/statuses/lookup> for details.

        :param ids_f: input file object consisting of Tweet IDs, one to a line
        :return: iterable of Tweet objects in JSON format
        c                 :    g | ]}||                                 S rA   )strip).0lines     r   
<listcomp>z)Query.expand_tweetids.<locals>.<listcomp>   s%    6666tzz||666r   zCounted z Tweet IDs in .c                 *    g | ]}||d z            S )d   rA   )rI   iidss     r   rK   z)Query.expand_tweetids.<locals>.<listcomp>   s&    GGG!SQW%GGGr   r   rN   c              3   D   K   | ]}                     |           V  dS ))idN)lookup_status)rI   chunkr   s     r   	<genexpr>z(Query.expand_tweetids.<locals>.<genexpr>   s4      NN5$,,,66NNNNNNr   )r)   lenrange	itertoolschainfrom_iterable)r   ids_fverbose	id_chunkschunked_tweetsrP   s   `    @r   expand_tweetidszQuery.expand_tweetids   s     76666 	?=SXX==U===>>> HGGGuQC#/F/FGGG	NNNNINNN,,^<<<r   rN   r5   c                    	 |                      |||| j        j                  }|D ]}| j                            |           | j                                        r| j        j        sni| j                                         dS )a[  
        Assumes that the handler has been informed. Fetches Tweets from
        search_tweets generator output and passses them to handler

        :param str keywords: A list of query terms to search for, written as        a comma-separated string.
        :param int limit: Number of Tweets to process
        :param str lang: language
        T)keywordslimitr:   max_idN)search_tweetsr   rc   r"   r   repeatr%   )r   ra   rb   r:   tweetstweets         r   _search_tweetszQuery._search_tweets   s    	''!T$,BU (  F   + +##E****L,,.. 4<3F 	 	     r   Nr   c              #     K   | j         st          |          | _         d}|r|| j         _        n|                     |t	          d|          |d          }t          |d                   }|dk    rt          d           dS |}|d         |d	z
           d
         d	z
  | j         _        |d         D ];}	|	V  | j         xj        d	z  c_        | j                                         dk    r dS <d}
||k     rI	 t	          d||z
            }|                     |||| j         j        d          }nn# t          $ r0}t          d|            t          j        d           Y d}~ud}~wt          $ r)}t          d|            ||
k    r||
d	z  }
Y d}~nd}~ww xY wt          |d                   }|dk    rt          d           dS ||z  }|d         |d	z
           d
         d	z
  | j         _        |d         D ];}	|	V  | j         xj        d	z  c_        | j                                         dk    r dS <||k     GdS dS )a  
        Call the REST API ``'search/tweets'`` endpoint with some plausible
        defaults. See `the Twitter search documentation
        <https://dev.twitter.com/rest/public/search>`_ for more information
        about admissible search parameters.

        :param str keywords: A list of query terms to search for, written as        a comma-separated string
        :param int limit: Number of Tweets to process
        :param str lang: language
        :param int max_id: id of the last tweet fetched
        :param int retries_after_twython_exception: number of retries when        searching Tweets before raising an exception
        :rtype: python generator
        rb   r   rN   recent)qcountr:   result_typer.   z7No Tweets available through REST API for those keywordsNr    rR   F)rl   rm   r:   rc   rn   zWaiting for 15 minutes -i  z Fatal error in Twython request -z)No more Tweets available through rest api)r   r   rc   searchminrV   r)   r!   r   r   timesleepr   )r   ra   rb   r:   rc   retries_after_twython_exceptioncount_from_queryresultsrm   resultretriesmcountr3   s                r   rd   zQuery.search_tweets   s     . | 	: -5999DL 	"(DLkk#c5//( "  G 
+,,EzzOPPP$")*"5eai"@"F"JDL!*-  $$)$$<++--66FF 7
 &&S%*:":;;++ <. ( &   )   444555
7###   <<<===2g==G1	 
+,,EzzABBB%
 #**"5eai"@"F"JDL!*-  $$)$$<++--66FF 7E &&&&&&s$   77D/ /
F9&E$$F1FFc                        fd|D             S )a  
        Convert a list of userIDs into a variety of information about the users.

        See <https://dev.twitter.com/rest/reference/get/users/show>.

        :param list userids: A list of integer strings corresponding to Twitter userIDs
        :rtype: list(json)
        c                 <    g | ]}                     |           S ))user_id)	show_user)rI   useridr   s     r   rK   z+Query.user_info_from_id.<locals>.<listcomp>%  s'    EEE6v..EEEr   rA   )r   useridss   ` r   user_info_from_idzQuery.user_info_from_id  s      FEEEWEEEEr   falsec                 t    |                      |||          }|D ]}| j                            |           dS )a  
        Return a collection of the most recent Tweets posted by the user

        :param str user: The user's screen name; the initial '@' symbol        should be omitted
        :param int limit: The number of Tweets to recover; 200 is the maximum allowed
        :param str include_rts: Whether to include statuses which have been        retweeted by the user; possible values are 'true' and 'false'
        )screen_namerm   include_rtsN)get_user_timeliner   r"   )r   r   rb   r   r&   items         r   user_tweetszQuery.user_tweets'  sY     %%#5k & 
 
  	& 	&DL%%%%	& 	&r   )T)rN   r5   )rN   r5   Nr   )r   )r=   r>   r?   r@   r   r   r_   rh   rd   r   r   rA   r   r   rC   rC   {   s         U U U  = = = =6! ! ! !. ()V V V Vp	F 	F 	F& & & & & &r   rC   c                   2    e Zd ZdZd Z	 	 	 	 	 	 	 	 	 d
d	ZdS )TwitterzH
    Wrapper class with restricted functionality and fewer options.
    c                     t                      | _        t          di | j        | _        t	          di | j        | _        d S )NrA   )r	   _oauthr   streamerrC   queryr   s    r   r   zTwitter.__init__=  s?    #oo //4;//))T[))


r   r4   TrN   Nr5   Fc
                 .   |r|}
d}nd}
|}|rt          ||
|          }nt          ||
|||	          }|rt          |          }n|r|}
d}nd}
|}t          ||
|||	          }|r`| j                            |           |dk    r!|dk    r| j                                         dS | j                            |||           dS | j                            |           |dk    rt          d          | j                            |||           dS )	an  
        Process some Tweets in a simple manner.

        :param str keywords: Keywords to use for searching or filtering
        :param list follow: UserIDs to use for filtering Tweets from the public stream
        :param bool to_screen: If `True`, display the tweet texts on the screen,            otherwise print to a file

        :param bool stream: If `True`, use the live public stream,            otherwise search past public Tweets

        :param int limit: The number of data items to process in the current            round of processing.

        :param tuple date_limit: The date at which to stop collecting            new data. This should be entered as a tuple which can serve as the            argument to `datetime.datetime`.            E.g. `date_limit=(2015, 4, 1, 12, 40)` for 12:30 pm on April 1 2015.
            Note that, in the case of streaming, this is the maximum date, i.e.            a date in the future; if not, it is the minimum date, i.e. a date            in the past

        :param str lang: language

        :param bool repeat: A flag to determine whether multiple files should            be written. If `True`, the length of each file will be set by the            value of `limit`. Use only if `to_screen` is `False`. See also
            :py:func:`handle`.

        :param gzip_compress: if `True`, output files are compressed with gzip.
        N)rb   upper_date_limitlower_date_limit)rb   r   r   re   gzip_compressrj   r4   r7   z1Please supply at least one keyword to search for.)rb   r:   )	TweetViewerTweetWriterr   r   r/   r;   r   r#   rh   )r   ra   r9   	to_screenstreamrb   
date_limitr:   re   r   r   r   r   s                r   rf   zTwitter.tweetsB  s   V  	*)##) 	!!1!1  GG "!1!1+  G  	!...GG .#- #'  #' #- !!1!1+  G  	LM""7+++2~~&B,,$$&&&&&$$8F$NNNNNJ(((2~~ !TUUU
))(%d)KKKKKr   )	r4   r4   TTrN   Nr5   FF)r=   r>   r?   r@   r   rf   rA   r   r   r   r   8  sj         * * * ^L ^L ^L ^L ^L ^Lr   r   c                       e Zd ZdZd Zd ZdS )r   z4
    Handle data by sending it to the terminal.
    c                 p    |d         }t          |           |                     |           | j        rdS dS )z
        Direct data to `sys.stdout`

        :return: return ``False`` if processing should cease, otherwise return ``True``.
        :rtype: bool
        :param data: Tweet object returned by Twitter API
        r   N)r)   check_date_limitdo_stop)r   r&   r   s      r   r"   zTweetViewer.handle  sE     F|dd###< 	F	 	r   c                 6    t          d| j         d           d S NzWritten z Tweets)r)   r!   r   s    r   r%   zTweetViewer.on_finish  s$    ..../////r   N)r=   r>   r?   r@   r"   r%   rA   r   r   r   r     s<           0 0 0 0 0r   r   c                   F    e Zd ZdZ	 	 	 	 	 	 	 ddZd Zd	 Zd
 Zd Zd Z	dS )r   z.
    Handle data by writing it to a file.
      Nrf   twitter-filesFc                     || _         t          |          | _        || _        |                                 | _        || _        d| _        t          j	        | |||           dS )a  
        The difference between the upper and lower date limits depends on
        whether Tweets are coming in an ascending date order (i.e. when
        streaming) or descending date order (i.e. when searching past Tweets).

        :param int limit: number of data items to process in the current        round of processing.

        :param tuple upper_date_limit: The date at which to stop collecting new        data. This should be entered as a tuple which can serve as the        argument to `datetime.datetime`. E.g. `upper_date_limit=(2015, 4, 1, 12,        40)` for 12:30 pm on April 1 2015.

        :param tuple lower_date_limit: The date at which to stop collecting new        data. See `upper_data_limit` for formatting.

        :param str fprefix: The prefix to use in creating file names for Tweet        collections.

        :param str subdir: The name of the directory where Tweet collection        files should be stored.

        :param bool repeat: flag to determine whether multiple files should be        written. If `True`, the length of each file will be set by the value        of `limit`. See also :py:func:`handle`.

        :param gzip_compress: if `True`, output files are compressed with gzip.
        N)
fprefixr
   subdirr   timestamped_filefnamere   outputr   r   )r   rb   r   r   r   r   re   r   s           r   r   zTweetWriter.__init__  sc    L  ((***,,
tU,<>NOOOOOr   c                 ^   | j         }| j        }|r3t          j                            |          st          j        |           t          j                            ||          }d}t          j                                        	                    |          }| j
        rd}nd}| d| d| }|S )zD
        :return: timestamped file name
        :rtype: str
        z%Y%m%d-%H%M%Sz.gzr4   rL   z.json)r   r   ospathexistsmkdirjoindatetimenowstrftimer   )r   r   r   r   fmt	timestampsuffixoutfiles           r   r   zTweetWriter.timestamped_file  s    
 , 	!7>>&)) !   VW--%))++44S99	 	FFF55Y55V55r   c                    | j         rX| j        r t          j        | j        d          | _        nt          | j        d          | _        t          d| j                    t          j        |          }| j        r1| j        	                    |dz   
                    d                     n| j        	                    |dz              |                     |           | j        rdS d| _         dS )z
        Write Twitter data as line-delimited JSON into one or more files.

        :return: return `False` if processing should cease, otherwise return `True`.
        :param data: tweet object returned by Twitter API
        wzWriting to 
zutf-8NF)
startingupr   gzipopenr   r   r)   jsondumpswriteencoder   r   )r   r&   	json_datas      r   r"   zTweetWriter.handle  s     ? 	.! 4"i
C88"4:s33,
,,---Jt$$	 	0Ky4/77@@AAAAKi$.///d###< 	Fr   c                 z    t          d| j         d           | j        r| j                                         d S d S r   )r)   r!   r   closer   s    r   r%   zTweetWriter.on_finish  sL    ....///; 	 K	  	 r   c                     | j         dk    rt          j        |           S | j        rdS | j        | j        k    r|                                  dS )NFT)re   r   r   r   r!   rb   _restart_filer   s    r   r   zTweetWriter.do_continue"  sW    ;% ,T222< 	5<4:%%    tr   c                 |    |                                   |                                 | _        d| _        d| _        d S )NTr   )r%   r   r   r   r!   r   s    r   r   zTweetWriter._restart_file0  s7    **,,
r   )r   NNrf   r   FF)
r=   r>   r?   r@   r   r   r"   r%   r   r   rA   r   r   r   r     s          ,P ,P ,P ,P\  *     4     
      r   r   )r@   r   r   rX   r   r   rq   r0   twythonr   r   twython.exceptionsr   r   nltk.twitter.apir   r   nltk.twitter.utilr	   r
   r   rC   r   r   r   rA   r   r   <module>r      s           				   , , , , , , , , B B B B B B B B = = = = = = = = 7 7 7 7 7 7 7 7P P P P P P P Pfz& z& z& z& z&G z& z& z&zhL hL hL hL hL hL hL hLV0 0 0 0 0- 0 0 00y y y y y- y y y y yr   