a
    Nb                     @   s   d dl Z d dlZd dlmZ d dlZd dlmZ d dlZd dlZd dlm	Z	m
Z
 d dlmZ d dlmZ d dlmZ d dlmZ d dlmZmZ zd dlZW n ey   dZY n0 dZeeZd	ed
ZG dd deZdS )    N)	text_type)OrderedDict)HTTPBasicAuthAuthBase)OAuth1)Sleepers)parse_timestampread_in_chunksz0.10.1zmwclient/{} ({})z$https://github.com/mwclient/mwclientc                   @   s  e Zd ZdZdZddddddd	 dd
ddddddddddddfddZdd Zed{ddZddddddddddddd d!d"d#d$d%d&Z	d'd( Z
d)d* Zd+d, Zd|d.d/Zd}d0d1Zed2d3 Zd~d4d5Zdd6d7Zdd8d9Zdd:d;Zdd=d>Zdd?d@ZddAdBZddCdDZdEdF ZddGdHZddLdMZddNdOZddQdRZddSdTZddUdVZddYdZZdd\d]Z dd_d`Z!ddadbZ"ddddeZ#ddgdhZ$ddidjZ%ddldmZ&ddndoZ'ddpdqZ(ddsdtZ)ddudvZ*ddwdxZ+ddydzZ,dS )Sitea  A MediaWiki site identified by its hostname.

        >>> import mwclient
        >>> site = mwclient.Site('en.wikipedia.org')

    Do not include the leading "http://".

    Mwclient assumes that the script path (where index.php and api.php are located)
    is '/w/'. If the site uses a different script path, you must specify this
    (path must end in a '/').

    Examples:

        >>> site = mwclient.Site('vim.wikia.com', path='/')
        >>> site = mwclient.Site('sourceforge.net', path='/apps/mediawiki/mwclient/')

      z/w/z.phpN      c                  G   s   d S N )xr   r   L/var/www/html/diaryflask/venv/lib/python3.9/site-packages/mwclient/client.py<lambda>5       zSite.<lambda>   Thttpsc              
   C   s  || _ || _|| _d | _|
| _t|	| _|| _|p4i | _|| _	d| jvrRd| jd< |d urjt
||||}n:t|ttfrt| }n"|d u st|tfr|}ntdt|||| _d| _d| _g | _g | _i | _d | _| j| _d| _|d u rHt | _|| j_|r|| j_|r"|d t  }nt }|| jj!d< |rN| jj!"| n|| _t#$| | _%t#j$| dd| _&t#j$| d	d| _'| j%| _(| j&| _)| j'| _*d| _+d
| _,|rz| -  W n\ t.j/y } z@|j0d dkrt.1| |j2|j3|j0d dvr W Y d }~n
d }~0 0 d S )Ntimeoutr   z8Authentication is not a tuple or an instance of AuthBaseF z
User-Agent   	namespace   i   r   mwoauth-invalid-authorization>   ZreadapideniedZunknown_action)4hostpathextcredentialscompressr   max_lagforce_loginrequestsschemer   
isinstancelisttupler   r   RuntimeErrorr   sleepersblockedhasmsggroupsrightstokensversiondefault_namespaces
namespaceswriteapiSession
connectionauthcert
USER_AGENTheadersupdatelistingZPageListpages
categoriesZimagesZPagesZ
CategoriesImagesinitialized
chunk_size	site_initerrorsAPIErrorargsZOAuthAuthorizationErrorcodeinfo)selfr   r   r   poolZretry_timeoutmax_retriesZwait_callbackZclients_useragentr"   r!   r#   Zdo_initZhttpauthreqsZconsumer_tokenZconsumer_secretZaccess_tokenZaccess_secretZclient_certificateZcustom_headersr%   r6   Zuaer   r   r   __init__4   sn    






zSite.__init__c                 C   s   | j rR| jdddd}|d d }|d | _|dg | _|dg | _i | _d S | jddd	dd
d}|d d | _dd t|d d D | _	d| jv | _
| | jd | _| dd |d d }|d | _|dg | _|dg | _d| _ d S )Nqueryuserinfozgroups|rights)metauipropnamer-   r.   zsiteinfo|userinfozgeneral|namespacesF)rO   ZsiproprP   retry_on_errorZgeneralc                 S   s   i | ]}|d  | ddqS )id* get).0r   r   r   r   
<dictcomp>   s   z"Site.site_init.<locals>.<dictcomp>r2   r3   	generator      T)r?   rW   usernamer-   r.   r/   sitesix
itervaluesr2   r3   version_tuple_from_generatorr0   require)rG   rF   rN   rO   r   r   r   rA      s0    

zSite.site_init
MediaWiki c                    sv   |  |std| | t|d d}dd  t fdd|D d}t|d	k rrtd
d||S )u   Return a version tuple from a MediaWiki Generator string.

        Example:
            "MediaWiki 1.5.1" → (1, 5, 1)

        Args:
            prefix (str): The expected prefix of the string
        zUnknown generator {}N.c                 S   sr   d}|t | k r4| | dk s4| | dkr*q4|d7 }q| |d r\t| d| | |d fS t| d| fS dS )zSplit the string on the first non-digit character.

            Returns:
                A tuple of the digit part as int and, if available,
                the rest of the string.
            r   09r[   N)lenint)sir   r   r   	split_num   s    
z4Site.version_tuple_from_generator.<locals>.split_numc                 3   s   | ]} |V  qd S r   r   )rX   ri   rk   r   r   	<genexpr>   r   z4Site.version_tuple_from_generator.<locals>.<genexpr>r      zUnknown MediaWiki {})
startswithrB   MediaWikiVersionErrorformatrg   splitsumjoin)stringprefixr0   Zversion_tupler   rl   r   ra      s    

z!Site.version_tuple_from_generatorrU   ZTalkZUserz	User talkZProjectzProject talkZImagez
Image talkZ	MediaWikizMediaWiki talkTemplatezTemplate talkZHelpz	Help talkZCategoryzCategory talkSpecialZMedia)r   r[   rn   r         r         	   
            r      c                 C   s   d| j | jf S )Nz<Site object '%s%s'>)r   r   )rG   r   r   r   __repr__   s    zSite.__repr__c                 O   s   | j |dg|R i |S )zPerform a generic API call using GET.

        This is just a shorthand for calling api() with http_method='GET'.
        All arguments will be passed on.

        Returns:
            The raw response from the API call, as a dictionary.
        GETapirG   actionrD   kwargsr   r   r   rW      s    	zSite.getc                 O   s   | j |dg|R i |S )zPerform a generic API call using POST.

        This is just a shorthand for calling api() with http_method='POST'.
        All arguments will be passed on.

        Returns:
            The raw response from the API call, as a dictionary.
        POSTr   r   r   r   r   post   s    	z	Site.postr   c                 O   s   | | |dkr"d|vr"d|d< |dkrnd|v rD|d  d7  < nd|d< d|v rf|d  d7  < nd	|d< | j }| j||fi |}|si }| j||d
rx|S qxdS )a  Perform a generic API call and handle errors.

        All arguments will be passed on.

        Example:
            To get coordinates from the GeoData MediaWiki extension at English Wikipedia:

            >>> site = Site('en.wikipedia.org')
            >>> result = site.api('query', prop='coordinates', titles='Oslo|Copenhagen')
            >>> for page in result['query']['pages'].values():
            ...     if 'coordinates' in page:
            ...         print '{} {} {}'.format(page['title'],
            ...             page['coordinates'][0]['lat'],
            ...             page['coordinates'][0]['lon'])
            Oslo 59.95 10.75
            Copenhagen 55.6761 12.5683

        Returns:
            The raw response from the API call, as a dictionary.
        rM   continuerU   rO   z	|userinforN   rP   z|blockinfo|hasmsgzblockinfo|hasmsg)sleeperN)r:   r*   makeraw_apihandle_api_result)rG   r   http_methodrD   r   r   rF   r   r   r   r      s     

zSite.apic                 C   s  |d u r| j  }z|d d }W n ty8   d}Y n0 d|v rZ|d |ddf| _nd| _d|v | _d	|v| _d
|v r|d
  D ]\}}d|v rt	|d  qd|v r|d ddv r|
  dS |d ddkrd|d dv rt	d |
  dS d|d v r2td |d d |d|d v rft|d d |d d |d d t|d d |d d |dS )NrM   rN   r   Z	blockedbyZblockreasonrU   FmessagesZanonwarningsrT   errorrE   >   Z$internal_api_error_DBConnectionErrorZinternal_api_error_DBQueryErrorr   zNonce already usedrF   zIRetrying due to nonce error, seehttps://phabricator.wikimedia.org/T106066T)r*   r   KeyErrorrW   r+   r,   Z	logged_initemslogwarningsleeprB   rC   )rG   rF   r   r   rN   moduler   r   r   r   r   #  sH    





zSite.handle_api_resultc                  O   s>   | |  dd t|D }dd t|D }t|| S )Nc                 S   s    g | ]\}}|d vr||fqS >   tokenZwpEditTokenr   rX   kvr   r   r   
<listcomp>T  s   z&Site._query_string.<locals>.<listcomp>c                 S   s    g | ]\}}|d v r||fqS r   r   r   r   r   r   r   W  s   )r:   r_   	iteritemsr   )rD   r   Zqs1Zqs2r   r   r   _query_stringQ  s    
zSite._query_stringc                 C   s  i }| j rtrd|d< | j||f}| j}| j}	t|	ttfrTt	
dt |	\}}	dj||	| j|| jd}
z||d}| j D ]\}}|||< q|dkr||d< n||d	< | jj||
fi |}|jd
rt|jd}td| || nd|jdkr|jW S |jdk s(|jdkr2|  n.|s@|  tdj|j|jd |  W ql tjjy   |s~ td |  Y ql0 qldS )a  
        Perform a generic request and return the raw text.

        In the event of a network problem, or a HTTP response with status code 5XX,
        we'll wait and retry the configured number of times before giving up
        if `retry_on_error` is True.

        `requests.exceptions.HTTPError` is still raised directly for
        HTTP responses with status codes in the 4XX range, and invalid
        HTTP responses.

        Args:
            script (str): Script name, usually 'api'.
            data (dict): Post data
            files (dict): Files to upload
            retry_on_error (bool): Retry on connection error
            http_method (str): The HTTP method, defaults to 'POST'

        Returns:
            The raw text response.
        gzipzAccept-EncodingzkSpecifying host as a tuple is deprecated as of mwclient 0.10.1. Please use the new scheme argument instead.z${scheme}://{host}{path}{script}{ext})r%   r   r   scriptr   )filesr9   r   paramsdatazx-database-lagzretry-afterz4Database lag exceeds max lag. Waiting for {} seconds   r   iW  z9Received {status} response: {text}. Retrying in a moment.)statustextz'Connection error. Retrying in a moment.N)r!   r   r*   r   r%   r   r&   r'   r(   r   warnDeprecationWarningrq   r   r   r$   r   r5   requestr9   rW   rh   r   r   r   status_coder   raise_for_status
exceptionsConnectionError)rG   r   r   r   rR   r   r9   r   r%   r   urlrD   r   r   streamZ	wait_timer   r   r   raw_call\  s\    





zSite.raw_callc                 O   s   z| d}W n ty$   d}Y n0 ||d< d|d< | j|i |}| jd|||d}ztj|tdW S  ty   |d	rt	j
t	|Y n0 d
S )zSend a call to the API.rR   Tr   jsonrq   r   )rR   r   )object_pairs_hookz+MediaWiki API is not enabled for this site.N)popr   r   r   r   loadsr   
ValueErrorro   rB   ZAPIDisabledErrorZInvalidResponse)rG   r   r   rD   r   rR   r   resr   r   r   r     s     


zSite.raw_apic                 O   s2   ||d< | j |d< | j|i |}| jd||dS )z.Sends a call to index.php rather than the API.r   Zmaxlagindex)r   )r"   r   r   )rG   r   r   rD   r   r   r   r   r   	raw_index  s    
zSite.raw_indexc                 C   s~   | j d u r&|d u rd S tdt|  |d u rv| j d d ||fkrHdS |rptdj||f| j d d dqzdS ntd S )Nz$Site %s has not yet been initializedrn   TzZRequires version {required[0]}.{required[1]}, current version is {current[0]}.{current[1]})requiredcurrentF)r0   r)   reprrB   rp   rq   NotImplementedError)rG   majorminorrevisionZraise_errorr   r   r   rb     s     
zSite.requireFc              
   C   sz   |  d}z| jd|||||d}W nP tjyt } z6|jd dkrVt||jd tj| W Y d}~n
d}~0 0 |S )a  
        Send email to a specified user on the wiki.

            >>> try:
            ...     site.email('SomeUser', 'Some message', 'Some subject')
            ... except mwclient.errors.NoSpecifiedEmail:
            ...     print('User does not accept email, or has no email address.')

        Args:
            user (str): User name of the recipient
            text (str): Body of the email
            subject (str): Subject of the email
            cc (bool): True to send a copy of the email to yourself (default is False)

        Returns:
            Dictionary of the JSON response

        Raises:
            NoSpecifiedEmail (mwclient.errors.NoSpecifiedEmail): User doesn't accept email
            EmailError (mwclient.errors.EmailError): Other email errors
        emailZ	emailuser)targetsubjectr   Zccmer   r   Znoemailr[   N)	get_tokenr   rB   rC   rD   ZNoSpecifiedEmailZ
EmailError)rG   userr   r   ccr   rF   rK   r   r   r   r     s    


 z
Site.emailc              	   C   s>  |r|r|||f| _ |r&| jj| | j r2| j }| j d | j d d}| j d rf| j d |d< z| d|d< W n" tjt	fy   t
d Y n0 | jdi |}|d d	 d
krq2q|d d	 dkr|d d |d< q|d d	 dkr|t|d dd qt| |d d	 |d d q|   dS )a  
        Login to the wiki using a username and password. The method returns
        nothing if the login was successful, but raises and error if it was not.

        Args:
            username (str): MediaWiki username
            password (str): MediaWiki password
            cookies (dict): Custom cookies to include with the log-in request.
            domain (str): Sends domain name for authentication; used by some
                MediaWiki plug-ins like the 'LDAP Authentication' extension.

        Raises:
            LoginError (mwclient.errors.LoginError): Login failed, the reason can be
                obtained from e.code and e.info (where e is the exception object) and
                will be one of the API:Login errors. The most common error code is
                "Failed", indicating a wrong username or password.

            MaximumRetriesExceeded: API call to log in failed and was retried until all
                retries were exhausted. This will not occur if the credentials are merely
                incorrect. See MaximumRetriesExceeded for possible reasons.

            APIError: An API error occurred. Rare, usually indicates an internal server
                error.
        r   r[   )ZlgnameZ
lgpasswordrn   ZlgdomainloginZlgtokenz8Failed to get login token, MediaWiki is older than 1.27.resultSuccessZ	NeedTokenr   Z	Throttledwaitrz   reasonN)r   )r    r5   cookiesr:   r*   r   r   rB   rC   r   r   debugr   r   rh   rW   Z
LoginErrorrA   )rG   r]   passwordr   domainr   r   r   r   r   r   r     s4    


z
Site.loginc                 C   s  | j d u s| j d d dkr(|dvr(d}|| jvr<d| j|< | j|ddksR|r| j d u sn| j d d dkr| jddd|d	}| | |d d d
|  | j|< nT|d u rd}| jd|d|d}t|d d D ]"}|d |kr|d
|  | j|< q| j| S )Nrn   )r[      >   rollbackr   ZpatrolZ
userrightsZwatchZcsrfre   rM   r   r/   )rO   typez%stokenZTestrF   )titlespropZintokenr<   title)r0   r/   rW   r   r   r   r_   r`   )rG   r   forcer   rF   rj   r   r   r   r   >  s&    


zSite.get_tokenc	                 C   s  |durt dt |du r$tdtdd |||fD dkrHtd| j| }	|	dsft||du rx|}d}
n|}|}
|durt	|d	st
|d
}|dd}|d | jdd dkr|| jkr| |||||
S dd|||
|	dd}|rd|d< |r||d< | jdd dk r2||d< n||d< |}d}|durXdd|fi}| j }| d||}t|}|si }| j|||drb|di }qqb|dur|  |S )a  Upload a file to the site.

        Note that one of `file`, `filekey` and `url` must be specified, but not
        more than one. For normal uploads, you specify `file`.

        Args:
            file (str): File object or stream to upload.
            filename (str): Destination filename, don't include namespace
                            prefix like 'File:'
            description (str): Wikitext for the file description page.
            ignore (bool): True to upload despite any warnings.
            file_size (int): Deprecated in mwclient 0.7
            url (str): URL to fetch the file from.
            filekey (str): Key that identifies a previous upload that was
                           stashed temporarily.
            comment (str): Upload comment. Also used as the initial page text
                           for new files if `description` is not specified.

        Example:

            >>> client.upload(open('somefile', 'rb'), filename='somefile.jpg',
                              description='Some description')

        Returns:
            JSON result from the API.

        Raises:
            errors.InsufficientPermission
            requests.exceptions.HTTPError
        Nz*file_size is deprecated since mwclient 0.7zfilename must be specifiedc                 S   s   g | ]}|d ur|qS r   r   )rX   r   r   r   r   r     r   zSite.upload.<locals>.<listcomp>r[   z<exactly one of 'file', 'filekey' and 'url' must be specifieduploadreadrbr   rn   )r[      r   edit)r   rq   filenamecommentr   r   trueignorewarningsr   )r[      Z
sessionkeyfilekeyfilezfake-filenamer   r   r   )r   r   r   	TypeErrorrg   r>   ZcanrB   ZInsufficientPermissionhasattropenseekr0   r@   chunk_uploadr   r*   r   r   r   r   r   rW   close)rG   r   r   descriptionignore	file_sizer   r   r   imager   content_sizeZpredataZpostdatar   r   r   rF   responser   r   r   r   d  sn    !





	




zSite.uploadc              	   C   sN  | j | }|dd}|d dddd|||dd}|rFd|d	< | j }	d}
t|| jD ]}| jd
|d|id}t	|}| j
|||	drd|di }qqd|
| 7 }
|  td||
| |d |d< |d dkr|d |d< q`|d dkr
|   qq`|  |  S q`|d= |d= |d= ||d< ||d< | jdi |S )av  Upload a file to the site in chunks.

        This method is called by `Site.upload` if you are connecting to a newer
        MediaWiki installation, so it's normally not necessary to call this
        method directly.

        Args:
            file (file-like object): File object or stream to upload.
            params (dict): Dict containing upload parameters.
        r   rn   r   r   r[   r   )r   rq   stashoffsetr   filesizer   r   r   r   chunk)r   r   z%s: Uploaded %d of %d bytesr   r   Continuer   r   r   r   r   r   )r   )r>   r   r   r*   r   r	   r@   r   r   r   r   rW   tellr   r   r   r   )rG   r   r   r   r   r   r   r   r   r   r   r   r   rF   r   r   r   r   r     sL    

	


zSite.chunk_uploadc           	      C   st   i }|d ur||d< |d ur$||d< |d ur4||d< |d urD||d< |rPd|d< |r\d|d< | j d	i |}|d S )
Nr   r   pager   1	redirectsmobileformatparse)r   )r   )	rG   r   r   r   r   r   r   r   r   r   r   r   r     s    z
Site.parsere   all	ascendingc                 C   s`   t jd|}tt jj|d|fd|f||||||||
|d}t j|| ddf|	dd|S )z.Retrieve all pages on the wiki as a generator.Zapfromto)	rv   minsizemaxsizeprtypeprlevelr   filterredirdirfilterlanglinksallpagesr   limitZreturn_valuesr;   ListZ
get_prefixdictgenerate_kwargsZget_list)rG   startrv   r   r  r  r  r  r  r  r	  r
  rZ   endpfxr   r   r   r   r  +  s    zSite.allpagesc                 C   sZ   t jd|	}tt jj|d|fd|
f||||||d	}t j|	| ddf|dd|S )z/Retrieve all images on the wiki as a generator.Zair  r  )rv   r  r  r	  sha1
sha1base36	allimagesztimestamp|urlr  r  )rG   r  rv   r  r  r  r	  r  r  rZ   r  r  r   r   r   r   r  <  s    zSite.allimagesr   c	              	   C   sd   t jd|}	tt jj|	d|fd|f|||d}
|rBd|
|	d < t j|| ddf|dd	|
S )
z8Retrieve a list of all links on the wiki as a generator.alr  r  )rv   r   r   r   uniquealllinksr   r  r  )rG   r  rv   r  r   r   r  rZ   r  r  r   r   r   r   r  J  s    zSite.alllinksc           	      C   sP   t jd|}tt jj|d|fd|f||d}t j|| ddfd|i|S )z3Retrieve all categories on the wiki as a generator.acr  r  )rv   r	  allcategoriesr  r  )	rG   r  rv   r	  r  rZ   r  r  r   r   r   r   r  W  s    zSite.allcategoriesc
                 C   sD   t tjjdd|fd|	f||||||d	}
tj| ddfd|i|
S )z.Retrieve all users on the wiki as a generator.aur  r  )rv   groupr   r.   witheditsonlyactiveusersallusersr  r  r;   r  r  )rG   r  rv   r  r   r  r  r   r.   r  r   r   r   r   r!  a  s    zSite.allusersolder(id|user|by|timestamp|expiry|reason|flagsc           	   
   C   s8   t tjjd||||||d}tj| ddfd|i|S )a  Retrieve blocks as a generator.

        Returns:
            mwclient.listings.List: Generator yielding dicts, each dict containing:
                - user: The username or IP address of the user
                - id: The ID of the block
                - timestamp: When the block was added
                - expiry: When the block runs out (infinity for indefinite blocks)
                - reason: The reason they are blocked
                - allowusertalk: Key is present (empty string) if the user is allowed to
                    edit their user talk page
                - by: the administrator who blocked the user
                - nocreate: key is present (empty string) if the user's ability to create
                    accounts has been disabled.

        Zbk)r  r  r	  idsusersr   blocksr  r"  )	rG   r  r  r	  r%  r&  r  r   r   r   r   r   r'  m  s    zSite.blocksuser|commentc              	   C   s6   t tjjd|||||d}tj| ddfd|i|S )NZdr)r  r  r	  r   r   Zdeletedrevsr  r"  )rG   r  r  r	  r   r  r   r   r   r   r   deletedrevisions  s    zSite.deletedrevisionshttpc                 C   s4   t tjjd||||d}tj| ddfd|i|S )a  Retrieve the list of pages that link to a particular domain or URL,
         as a generator.

        This API call mirrors the Special:LinkSearch function on-wiki.

        Query can be a domain like 'bbc.co.uk'.
        Wildcards can be used, e.g. '\*.bbc.co.uk'.
        Alternatively, a query can contain a full domain name and some or all of a URL:
        e.g. '\*.wikipedia.org/wiki/\*'

        See <https://meta.wikimedia.org/wiki/Help:Linksearch> for details.

        Returns:
            mwclient.listings.List: Generator yielding dicts, each dict containing:
                - url: The URL linked to.
                - ns: Namespace of the wiki page
                - pageid: The ID of the wiki page
                - title: The page title.

        eu)rM   r   protocolr   exturlusager  r"  )rG   rM   r   r,  r   r  r   r   r   r   r-    s
    zSite.exturlusagec
                 C   s<   t tjjd||||||||	d	}
tj| ddfd|i|
S )z"Retrieve logevents as a generator.le)r   r   r  r  r	  r   r   r   	logeventsr  r"  )rG   r   r   r  r  r	  r   r   r  r   r   r   r   r   r/    s
    zSite.logeventsr~   c              	   C   s8   t tjjd|||||d}tjd| ddfd|i|S )z+Retrieve checkuserlog items as a generator.Zcul)r   r  r  r	  r   entriescheckuserlogr  )r  r;   r  r  Z
NestedList)rG   r   r   r  r	  r  r  r   r   r   r   r1    s    zSite.checkuserlogr   c                 C   s.   t tjjd|d}tj| ddfd|i|S )a  Retrieve a generator of random pages from a particular namespace.

        limit specifies the number of random articles retrieved.
        namespace is a namespace identifier integer.

        Generator contains dictionary with namespace, page ID and title.

        Zrnr   randomr  r"  )rG   r   r  r   r   r   r   r2    s    
zSite.randomc
                 C   sD   t tjjd||||||||	r dndd	}
tj| ddfd|i|
S )uF   List recent changes to the wiki, à la Special:Recentchanges.
        rcr   N)r  r  r	  r   r   showr   toponlyrecentchangesr  r"  )rG   r  r  r	  r   r   r4  r  r   r5  r   r   r   r   r6    s    
zSite.recentchanges ids|timestamp|flags|comment|userc                 C   s   d|d tt|d}g }| jdi |di di  }|D ]L}|ddD ]:}|d|d< |d|d	< t|d
 |d
< || qTqD|S )a  Get data about a list of revisions.

        See also the `Page.revisions()` method.

        API doc: https://www.mediawiki.org/wiki/API:Revisions

        Example: Get revision text for two revisions:

            >>> for revision in site.revisions([689697696, 689816909], prop='content'):
            ...     print revision['*']

        Args:
            revids (list): A list of (max 50) revisions.
            prop (str): Which properties to get for each revision.

        Returns:
            A list of revisions
        	revisions|)r   ZrvproprevidsrM   r<   r   Zpageidr   Z	pagetitle	timestamp)rM   )rt   mapr   rW   valuesr   append)rG   r:  r   r   r8  r<   r   r   r   r   r   r8    s    $zSite.revisionsc                 C   s>   t tjjd|||d}|r$d|d< tj| ddfd|i|S )a  Perform a full text search.

        API doc: https://www.mediawiki.org/wiki/API:Search

        Example:
            >>> for result in site.search('prefix:Template:Citation/'):
            ...     print(result.get('title'))

        Args:
            search (str): The query string
            namespace (int): The namespace to search (default: 0)
            what (str): Search scope: 'text' for fulltext, or 'title' for titles only.
                        Depending on the search backend,
                        both options may not be available.
                        For instance
                        `CirrusSearch <https://www.mediawiki.org/wiki/Help:CirrusSearch>`_
                        doesn't support 'title', but instead provides an "intitle:"
                        query string filter.
            redirects (bool): Include redirect pages in the search
                              (option removed in MediaWiki 1.23).

        Returns:
            mwclient.listings.List: Search results iterator
        sr)searchr   whatr   Zsrredirectsr@  r  r"  )rG   r@  r   rA  r   r  r   r   r   r   r@    s    zSite.searchc
                 C   s<   t tjjd|||||||d}
tj| ddf||	d|
S )z
        List the contributions made by a given user to the wiki.

        API doc: https://www.mediawiki.org/wiki/API:Usercontribs
        Zuc)r   r  r  r	  r   r   r4  Zusercontribs)r  uselangr"  )rG   r   r  r  r	  r   r   r4  r  rB  r   r   r   r   usercontributions  s    zSite.usercontributionsblockinfo|groups|editcountc                 C   s   t j| ddd||dS )zs
        Get information about a list of users.

        API doc: https://www.mediawiki.org/wiki/API:Users
        r&  usr9  )ZususersZusprop)r;   r  rt   )rG   r&  r   r   r   r   r&     s    z
Site.usersc	           
   
   C   sD   t tjjd||||||d}	|r*d|	d< tj| ddfd|i|	S )z
        List the pages on the current user's watchlist.

        API doc: https://www.mediawiki.org/wiki/API:Watchlist
        Zwl)r  r  r   r	  r   r4  r   Zwlallrev	watchlistr  r"  )
rG   Zallrevr  r  r   r	  r   r4  r  r   r   r   r   rF  )  s    zSite.watchlistc                 C   s`   i }|du r||d< |r d|d< | j d	d|i|}|rP|d d |d d fS |d d S dS )
z
        Takes wikitext (text) and expands templates.

        API doc: https://www.mediawiki.org/wiki/API:Expandtemplates
        Nr   r   generatexmlexpandtemplatesr   rT   Z	parsetree)rH  rV   )rG   r   r   rG  r   r   r   r   r   rH  8  s    zSite.expandtemplatesc                 c   s   i }|du r||d< d}|dur| j ddj||ddd|}| | |d	}|d
 dg }t|trdd | D }|D ]
}|V  qqdS )ay  
        Ask a query against Semantic MediaWiki.

        API doc: https://semantic-mediawiki.org/wiki/Ask_API

        Returns:
            Generator for retrieving all search results, with each answer as a dictionary.
            If the query is invalid, an APIError is raised. A valid query with zero
            results will not raise any error.

        Examples:

            >>> query = "[[Category:my cat]]|[[Has name::a name]]|?Has property"
            >>> for answer in site.ask(query):
            >>>     for title, data in answer.items()
            >>>         print(title)
            >>>         print(data)
        Nr   r   askz{query}|offset={offset})rM   r   r   )rM   r   zquery-continue-offsetrM   resultsc                 S   s   g | ]}|qS r   r   )rX   answerr   r   r   r   o  r   zSite.ask.<locals>.<listcomp>)rI  )r   rq   r   rW   r&   r  r=  )rG   rM   r   r   r   rJ  ZanswersrK  r   r   r   rI  L  s&    



zSite.ask)rc   )r   )NN)NTr   )r   )r   )NT)F)NNNN)FN)NNrU   FNNNN)NNNNFF)NNre   r   NNNNNr  r   TN)
NNNNNr  NNTN)NNFr   re   NTN)NNr  NTN)	NNNNNFFNN)NNr#  NNNr$  )NNr#  NNr(  )Nr*  NN)	NNNNr#  NNNN)NNr~   r#  NN)r   )	NNr#  NNNNNN)r7  )re   NFN)NNr#  NNNNN)rD  )FNNNr#  NNN)NF)N)-__name__
__module____qualname____doc__Z	api_limitrL   rA   staticmethodra   r1   r   rW   r   r   r   r   r   r   r   rb   r   r   r   r   r   r   r  r  r  r  r!  r'  r)  r-  r/  r1  r2  r6  r8  r@  rC  r&  rF  rH  rI  r   r   r   r   r
       s   


W#(

,
.


P



#
?
&  
r=  
    
  
  
  

  
  
  

  
  


  


#
  

	  

r
   ) r   loggingr_   r   collectionsr   r   r$   Zrequests.authr   r   Zrequests_oauthlibr   Zmwclient.errorsrB   Zmwclient.listingr;   Zmwclient.sleepr   Zmwclient.utilr   r	   r   ImportError__version__	getLoggerrL  r   rq   r8   objectr
   r   r   r   r   <module>   s,   

