U
    M8Úc k  ã                   @   sª   d dl Z 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m	Z	m
Z
 e e¡ZG dd„ dƒZG dd„ dƒZG d	d
„ d
ƒZG dd„ dƒZG dd„ dƒZG dd„ dƒZdS )é    N)Útee)ÚPaginationError)Úmerge_dictsÚset_value_from_jmespathc                   @   s8   e Zd ZdZdd„ Zdd„ Zdd„ Zdd	„ Zd
d„ ZdS )ÚTokenEncoderab  Encodes dictionaries into opaque strings.

    This for the most part json dumps + base64 encoding, but also supports
    having bytes in the dictionary in addition to the types that json can
    handle by default.

    This is intended for use in encoding pagination tokens, which in some
    cases can be complex structures and / or contain bytes.
    c              	   C   s`   zt  |¡}W n: ttfk
rH   |  |g ¡\}}||d< t  |¡}Y nX t | d¡¡ d¡S )a.  Encodes a dictionary to an opaque string.

        :type token: dict
        :param token: A dictionary containing pagination information,
            particularly the service pagination token(s) but also other boto
            metadata.

        :rtype: str
        :returns: An opaque string
        Úboto_encoded_keysúutf-8)	ÚjsonÚdumpsÚ	TypeErrorÚUnicodeDecodeErrorÚ_encodeÚbase64Ú	b64encodeÚencodeÚdecode)ÚselfÚtokenÚjson_stringZencoded_tokenÚencoded_keys© r   ú5/tmp/pip-unpacked-wheel-ozje0y8b/botocore/paginate.pyr   &   s    zTokenEncoder.encodec                 C   sN   t |tƒr|  ||¡S t |tƒr,|  ||¡S t |tƒrB|  ||¡S |g fS dS )z@Encode bytes in given data, keeping track of the path traversed.N)Ú
isinstanceÚdictÚ_encode_dictÚlistÚ_encode_listÚbytesÚ_encode_bytes©r   ÚdataÚpathr   r   r   r   C   s    


zTokenEncoder._encodec           
      C   sP   g }g }t |ƒD ]6\}}||g }|  ||¡\}}	| |¡ | |	¡ q||fS )z@Encode any bytes in a list, noting the index of what is encoded.)Ú	enumerater   ÚappendÚextend)
r   r    r!   Únew_dataÚencodedÚiÚvalueÚnew_pathÚ	new_valueÚnew_encodedr   r   r   r   N   s    

zTokenEncoder._encode_listc           
      C   sN   i }g }|  ¡ D ]4\}}||g }|  ||¡\}}	|||< | |	¡ q||fS )z@Encode any bytes in a dict, noting the index of what is encoded.)Úitemsr   r$   )
r   r    r!   r%   r&   Úkeyr(   r)   r*   r+   r   r   r   r   Y   s    
zTokenEncoder._encode_dictc                 C   s   t  |¡ d¡|gfS )zBase64 encode a byte string.r   )r   r   r   r   r   r   r   r   d   s    zTokenEncoder._encode_bytesN)	Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   r   r   r   r   r   r   r   r      s   
r   c                   @   s0   e Zd ZdZdd„ Zdd„ Zdd„ Zdd	„ Zd
S )ÚTokenDecoderz´Decodes token strings back into dictionaries.

    This performs the inverse operation to the TokenEncoder, accepting
    opaque strings and decoding them into a useable form.
    c                 C   sH   t  | d¡¡ d¡}t |¡}| dd¡}|dkr8|S |  ||¡S dS )ad  Decodes an opaque string to a dictionary.

        :type token: str
        :param token: A token string given by the botocore pagination
            interface.

        :rtype: dict
        :returns: A dictionary containing pagination information,
            particularly the service pagination token(s) but also other boto
            metadata.
        r   r   N)r   Ú	b64decoder   r   r	   ÚloadsÚpopÚ_decode)r   r   r   Zdecoded_tokenr   r   r   r   r   p   s    
zTokenDecoder.decodec                 C   s8   |D ].}|   ||¡}t | d¡¡}|  |||¡ q|S )z&Find each encoded value and decode it.r   )Ú	_path_getr   r3   r   Ú	_path_set)r   r   r   r-   r&   Údecodedr   r   r   r6   ‡   s
    zTokenDecoder._decodec                 C   s   |}|D ]}|| }q|S )z¨Return the nested data at the given path.

        For instance:
            data = {'foo': ['bar', 'baz']}
            path = ['foo', 0]
            ==> 'bar'
        r   )r   r    r!   ÚdÚstepr   r   r   r7      s    
zTokenDecoder._path_getc                 C   s$   |   ||dd… ¡}|||d < dS )zÖSet the value of a key in the given data.

        Example:
            data = {'foo': ['bar', 'baz']}
            path = ['foo', 1]
            value = 'bin'
            ==> data = {'foo': ['bar', 'bin']}
        Néÿÿÿÿ)r7   )r   r    r!   r(   Ú	containerr   r   r   r8       s    	zTokenDecoder._path_setN)r.   r/   r0   r1   r   r6   r7   r8   r   r   r   r   r2   i   s
   r2   c                   @   s   e Zd Zdd„ Zdd„ ZdS )ÚPaginatorModelc                 C   s   |d | _ d S )NZ
pagination)Ú_paginator_config)r   Zpaginator_configr   r   r   Ú__init__®   s    zPaginatorModel.__init__c                 C   s4   z| j | }W n  tk
r.   td| ƒ‚Y nX |S )Nz*Paginator for operation does not exist: %s)r?   ÚKeyErrorÚ
ValueError)r   Zoperation_nameZsingle_paginator_configr   r   r   Úget_paginator±   s    ÿ
zPaginatorModel.get_paginatorN)r.   r/   r0   r@   rC   r   r   r   r   r>   ­   s   r>   c                   @   sÂ   e Zd ZdZdd„ Zedd„ ƒZedd„ ƒZejdd„ ƒZed	d
„ ƒZ	dd„ Z
dd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd „ Zd!d"„ Zd#d$„ Zd%d&„ Zd'd(„ Zd)S )*ÚPageIteratorz‹An iterable object to pagiante API results.
    Please note it is NOT a python iterator.
    Use ``iter`` to wrap this as a generator.
    c                 C   sb   || _ || _|| _|| _|| _|| _|| _|	| _|
| _|| _	d | _
|| _i | _tƒ | _tƒ | _d S ©N)Ú_methodÚ_input_tokenÚ_output_tokenÚ_more_resultsÚ_result_keysÚ
_max_itemsÚ
_limit_keyÚ_starting_tokenÚ
_page_sizeÚ
_op_kwargsÚ_resume_tokenÚ_non_aggregate_key_exprsÚ_non_aggregate_partr   Ú_token_encoderr2   Ú_token_decoder)r   ÚmethodÚinput_tokenÚoutput_tokenÚmore_resultsÚresult_keysÚnon_aggregate_keysÚ	limit_keyÚ	max_itemsZstarting_tokenÚ	page_sizeÚ	op_kwargsr   r   r   r@   Á   s    zPageIterator.__init__c                 C   s   | j S rE   ©rJ   ©r   r   r   r   rY   ß   s    zPageIterator.result_keysc                 C   s   | j S )z&Token to specify to resume pagination.)rP   r`   r   r   r   Úresume_tokenã   s    zPageIterator.resume_tokenc                 C   sn   t |tƒstd| ƒ‚d|kr0t| jdg ƒ}n
t| jƒ}t| ¡ ƒ}||kr^| j |¡| _ntd| ƒ‚d S )NúBad starting token: %sÚboto_truncate_amount)	r   r   rB   ÚsortedrG   ÚkeysrS   r   rP   )r   r(   Z
token_keysÚ	dict_keysr   r   r   ra   è   s    

c                 C   s   | j S rE   )rR   r`   r   r   r   Únon_aggregate_partø   s    zPageIterator.non_aggregate_partc                 c   sˆ  | j }d }dd„ | jD ƒ}| jd k	r0|  ¡ d }d}d}| jd }d}|  |¡ |  |¡}|  |¡}	|r| jd k	r€|  |	||¡}d}|  	|	¡ nd}| 
|	¡}
|
d krªg }
t|
ƒ}d}| jd k	rÎ|| | j }|dkrô|  |	||||¡ |V  q„qP|V  ||7 }|  |	¡}tdd„ | ¡ D ƒƒr(q„| jd k	rJ|| jkrJ|| _q„|d k	rr||krrd|› }t|d	‚|  ||¡ |}qPd S )
Nc                 S   s   i | ]
}|d “qS rE   r   )Ú.0r-   r   r   r   Ú
<dictcomp>ÿ   s      z)PageIterator.__iter__.<locals>.<dictcomp>r   TFc                 s   s   | ]}|d kV  qd S rE   r   )rh   Útr   r   r   Ú	<genexpr>5  s     z(PageIterator.__iter__.<locals>.<genexpr>z(The same next token was received twice: ©Úmessage)rO   rG   rM   Ú_parse_starting_tokenrY   Ú_inject_starting_paramsÚ_make_requestÚ_extract_parsed_responseÚ_handle_first_requestÚ _record_non_aggregate_key_valuesÚsearchÚlenrK   Ú_truncate_responseÚ_get_next_tokenÚallÚvaluesra   r   Ú_inject_token_into_kwargs)r   Úcurrent_kwargsZprevious_next_tokenÚ
next_tokenZtotal_itemsZfirst_requestÚprimary_result_keyÚstarting_truncationÚresponseÚparsedZcurrent_responseZnum_current_responseÚtruncate_amountrm   r   r   r   Ú__iter__ü   sx    





  ÿ

ÿû
ÿþÿþÿ
zPageIterator.__iter__c                 c   s>   t  |¡}| D ]*}| |¡}t|tƒr2|E dH  q|V  qdS )a…  Applies a JMESPath expression to a paginator

        Each page of results is searched using the provided JMESPath
        expression. If the result is not a list, it is yielded
        directly. If the result is a list, each element in the result
        is yielded individually (essentially implementing a flatmap in
        which the JMESPath search is the mapping function).

        :type expression: str
        :param expression: JMESPath expression to apply to each page.

        :return: Returns an iterator that yields the individual
            elements of applying a JMESPath expression to each page of
            results.
        N)ÚjmespathÚcompilert   r   r   )r   Ú
expressionZcompiledÚpageÚresultsr   r   r   rt   K  s    


zPageIterator.searchc                 C   s   | j f |ŽS rE   )rF   )r   r{   r   r   r   rp   d  s    zPageIterator._make_requestc                 C   s   |S rE   r   )r   r   r   r   r   rq   g  s    z%PageIterator._extract_parsed_responsec                 C   s2   i }| j D ]}| |¡}t||j|ƒ q
|| _d S rE   )rQ   rt   r   r…   rR   )r   r   rZ   r…   Úresultr   r   r   rs   j  s    

  ÿz-PageIterator._record_non_aggregate_key_valuesc                 C   s<   | j d k	r"|  ¡ d }|  ||¡ | jd k	r8| j|| j< d S )Nr   )rM   rn   rz   rN   rL   )r   r^   r|   r   r   r   ro   s  s
    

z$PageIterator._inject_starting_paramsc                 C   s>   |  ¡ D ]0\}}|d k	r*|dkr*|||< q||kr||= qd S )NÚNone)r,   )r   r^   r|   Únamer   r   r   r   rz   €  s
    
z&PageIterator._inject_token_into_kwargsc           	      C   s®   |   ¡ d }| |¡}t|ttfƒr2||d … }nd }t||j|ƒ | jD ]^}||krXqJ| |¡}t|tƒrrg }n(t|tƒr‚d}nt|tt	fƒr–d}nd }t||j|ƒ qJ|S )Né   Ú r   )
rn   rt   r   r   Ústrr   r…   rY   ÚintÚfloat)	r   r€   r}   r~   Zall_datar    r   ÚsampleZempty_valuer   r   r   rr   ‡  s&    




z"PageIterator._handle_first_requestc           	      C   sR   |  |¡}|d krg }t|ƒ| }|d |… }t||j|ƒ || |d< || _d S )Nrc   )rt   ru   r   r…   ra   )	r   r€   r}   r   r~   r|   ÚoriginalZamount_to_keepZ	truncatedr   r   r   rv   ¥  s    
  ÿÿzPageIterator._truncate_responsec                 C   sZ   | j d k	r| j  |¡si S i }t| j| jƒD ](\}}| |¡}|rL|||< q,d ||< q,|S rE   )rI   rt   ÚziprH   rG   )r   r€   Znext_tokensrW   Z	input_keyr|   r   r   r   rw   Å  s    
 ÿ


zPageIterator._get_next_tokenc                 C   s&   t | t| jƒƒ}dd„ t|| jƒD ƒS )Nc                 S   s   g | ]\}}t ||ƒ‘qS r   )ÚResultKeyIterator)rh   r'   Ú
result_keyr   r   r   Ú
<listcomp>Ø  s   ÿz1PageIterator.result_key_iters.<locals>.<listcomp>)r   ru   rY   r’   )r   Zteed_resultsr   r   r   Úresult_key_itersÖ  s    
þzPageIterator.result_key_itersc                 C   sÎ   i }| D ] }|}t |tƒr.t|ƒdkr.|d }| jD ]r}| |¡}|d krLq4| |¡}|d krnt||j|ƒ q4t |tƒr„| |¡ q4t |t	t
tfƒr4t||j|| ƒ q4qt|| jƒ | jd k	rÊ| j|d< |S )Né   r‹   Z	NextToken)r   Útupleru   rY   rt   r   r…   r   r$   rŽ   r   r   r   rg   ra   )r   Zcomplete_resultr   r†   Zresult_expressionZresult_valueZexisting_valuer   r   r   Úbuild_full_resultÝ  s:    


ý
ý

zPageIterator.build_full_resultc              	   C   sn   | j d krd S | j }z,| j |¡}d}d|kr>| d¡}|d= W n$ ttfk
rd   |  ¡ \}}Y nX ||fS )Nr   rc   )rM   rT   r   ÚgetrB   r   Ú _parse_starting_token_deprecated)r   r|   Úindexr   r   r   rn     s    


z"PageIterator._parse_starting_tokenc                 C   s¬   t  d| j ¡ | jdkrdS | j d¡}g }d}t|ƒt| jƒd krvzt| ¡ ƒ}W n tk
rt   | jg}Y nX |D ]"}|dkr’| 	d¡ qz| 	|¡ qz|  
|¡|fS )z|
        This handles parsing of old style starting tokens, and attempts to
        coerce them into the new style.
        zCAttempting to fall back to old starting token parser. For token: %sNZ___r   r‹   r‰   )ÚlogÚdebugrM   Úsplitru   rG   rŽ   r5   rB   r#   Ú"_convert_deprecated_starting_token)r   Úpartsr|   rœ   Úpartr   r   r   r›     s(    ÿÿ
z-PageIterator._parse_starting_token_deprecatedc                 C   sh   t |ƒ}t | jƒ}||kr*td| j ƒ‚n.||k rXt d¡ t|| ƒD ]}| d¡ qHtt	| j|ƒƒS )zb
        This attempts to convert a deprecated starting token into the new
        style.
        rb   zaOld format starting token does not contain all input tokens. Setting the rest, in order, as None.N)
ru   rG   rB   rM   r   rž   Úranger#   r   r’   )r   Zdeprecated_tokenZlen_deprecated_tokenZlen_input_tokenr'   r   r   r   r    <  s    
ÿz/PageIterator._convert_deprecated_starting_tokenN)r.   r/   r0   r1   r@   ÚpropertyrY   ra   Úsetterrg   r‚   rt   rp   rq   rs   ro   rz   rr   rv   rw   r–   r™   rn   r›   r    r   r   r   r   rD   »   s2   



O	 1rD   c                   @   sd   e Zd ZeZdd„ Zedd„ ƒZdd„ Zdd„ Z	d	d
„ Z
dd„ Zdd„ Zdd„ Zdd„ Zdd„ ZdS )Ú	Paginatorc                 C   sj   || _ || _|| _|  | j¡| _|  | j¡| _|  | j¡| _|  	| j¡| _
|  | j¡| _|  | j¡| _d S rE   )Ú_modelrF   Ú_pagination_cfgÚ_get_output_tokensrH   Ú_get_input_tokensrG   Ú_get_more_results_tokenrI   Ú_get_non_aggregate_keysÚ_non_aggregate_keysÚ_get_result_keysrJ   Ú_get_limit_keyrL   )r   rU   Úpagination_configÚmodelr   r   r   r@   R  s    ÿzPaginator.__init__c                 C   s   | j S rE   r_   r`   r   r   r   rY   _  s    zPaginator.result_keysc                 C   s*   g }|  dg ¡D ]}| t |¡¡ q|S )NrZ   )rš   r#   rƒ   r„   )r   Úconfigre   r-   r   r   r   r¬   c  s    z!Paginator._get_non_aggregate_keysc                 C   s:   g }|d }t |tƒs|g}|D ]}| t |¡¡ q |S )NrW   )r   r   r#   rƒ   r„   )r   r²   ÚoutputrW   r   r   r   r©   i  s    
zPaginator._get_output_tokensc                 C   s   | j d }t|tƒs|g}|S )NrV   )r¨   r   r   )r   r²   rV   r   r   r   rª   r  s    

zPaginator._get_input_tokensc                 C   s    |  d¡}|d k	rt |¡S d S )NrX   )rš   rƒ   r„   )r   r²   rX   r   r   r   r«   x  s    
z!Paginator._get_more_results_tokenc                 C   s8   |  d¡}|d k	r4t|tƒs"|g}dd„ |D ƒ}|S d S )Nr”   c                 S   s   g | ]}t  |¡‘qS r   )rƒ   r„   )rh   Zrkr   r   r   r•   ‚  s     z.Paginator._get_result_keys.<locals>.<listcomp>)rš   r   r   )r   r²   r”   r   r   r   r®   }  s    

zPaginator._get_result_keysc                 C   s
   |  d¡S )Nr[   )rš   )r   r²   r   r   r   r¯   …  s    zPaginator._get_limit_keyc                 K   sB   |   |¡}|  | j| j| j| j| j| j| j|d |d |d |¡S )z»Create paginator object for an operation.

        This returns an iterable object.  Iterating over
        this object will yield a single page of a response
        at a time.

        ÚMaxItemsÚStartingTokenÚPageSize)	Ú_extract_paging_paramsÚPAGE_ITERATOR_CLSrF   rG   rH   rI   rJ   r­   rL   )r   ÚkwargsZpage_paramsr   r   r   Úpaginateˆ  s    
õzPaginator.paginatec                 C   s    |  di ¡}| dd ¡}|d k	r(t|ƒ}| dd ¡}|d k	rŒ| jd krPtdd‚| jjj}| | j¡}|jdkr„t	|t
ƒsŒt
|ƒ}nt|ƒ}|| dd ¡|dœS )	NZPaginationConfigr´   r¶   zTPageSize parameter is not supported for the pagination interface for this operation.rl   Ústringrµ   )r´   rµ   r¶   )r5   rš   rŽ   rL   r   r§   Zinput_shapeÚmembersÚ	type_namer   r   )r   r¹   r°   r\   r]   Zinput_membersZlimit_key_shaper   r   r   r·   Ÿ  s(    
ÿ




ýz Paginator._extract_paging_paramsN)r.   r/   r0   rD   r¸   r@   r¤   rY   r¬   r©   rª   r«   r®   r¯   rº   r·   r   r   r   r   r¦   O  s   
	r¦   c                   @   s    e Zd ZdZdd„ Zdd„ ZdS )r“   aŒ  Iterates over the results of paginated responses.

    Each iterator is associated with a single result key.
    Iterating over this object will give you each element in
    the result key list.

    :param pages_iterator: An iterator that will give you
        pages of results (a ``PageIterator`` class).
    :param result_key: The JMESPath expression representing
        the result key.

    c                 C   s   || _ || _d S rE   )Ú_pages_iteratorr”   )r   Zpages_iteratorr”   r   r   r   r@   Ç  s    zResultKeyIterator.__init__c                 c   s2   | j D ]&}| j |¡}|d kr"g }|E d H  qd S rE   )r¾   r”   rt   )r   r†   r‡   r   r   r   r‚   Ë  s
    
zResultKeyIterator.__iter__N)r.   r/   r0   r1   r@   r‚   r   r   r   r   r“   ¹  s   r“   )r   r	   ÚloggingÚ	itertoolsr   rƒ   Zbotocore.exceptionsr   Zbotocore.utilsr   r   Ú	getLoggerr.   r   r   r2   r>   rD   r¦   r“   r   r   r   r   Ú<module>   s    
ND   j