U
    ð¤ùd^  ã                   @   s†   d dl Z d dlZd dlmZ d dlmZ ddlmZ e  e	¡Z
e d¡ZG dd„ deƒZG d	d
„ d
eƒZG dd„ deƒZddd„ZdS )é    N)ÚOrderedDict)Úisclassé   )Ú	RestErrorz\{|\}|\,|[\w_:\-\*]+c                   @   s   e Zd ZdZdS )Ú	MaskErrorz#Raised when an error occurs on maskN©Ú__name__Ú
__module__Ú__qualname__Ú__doc__© r   r   ú4/tmp/pip-unpacked-wheel-dt_sn2ih/flask_restx/mask.pyr      s   r   c                   @   s   e Zd ZdZdS )Ú
ParseErrorz#Raised when the mask parsing failedNr   r   r   r   r   r      s   r   c                       sJ   e Zd ZdZd‡ fdd„	Zdd„ Zdd	„ Zd
d„ Zdd„ Zdd„ Z	‡  Z
S )ÚMaskzœ
    Hold a parsed mask.

    :param str|dict|Mask mask: A mask, parsed or not
    :param bool skip: If ``True``, missing fields won't appear in result
    NFc                    sj   || _ t|tƒr*tt| ƒ ¡  |  |¡ n<t|ttfƒrNtt| ƒj|f|Ž n|| _ tt| ƒjf |Ž d S )N)	ÚskipÚ
isinstanceÚstrÚsuperr   Ú__init__ÚparseÚdictr   )ÚselfÚmaskr   Úkwargs©Ú	__class__r   r   r   "   s    
zMask.__init__c                 C   s¾   |sdS |   |¡}| }d}g }t |¡D ]„}|dkrh||krDtdƒ‚t| jd||< | |¡ || }n@|dkr†|s|tdƒ‚| ¡ }n"|dkr |dkr¨td	ƒ‚nd
||< |}q(|rºtdƒ‚dS )a¡  
        Parse a fields mask.
        Expect something in the form::

            {field,nested{nested_field,another},last}

        External brackets are optionals so it can also be written::

            field,nested{nested_field,another},last

        All extras characters will be ignored.

        :param str mask: the mask string to parse
        :raises ParseError: when a mask is unparseable/invalid

        NÚ{zUnexpected opening bracket)r   Ú}zUnexpected closing bracketú,)r   r   NzUnexpected commaTúMissing closing bracket)ÚcleanÚLEXERÚfindallr   r   r   ÚappendÚpop)r   r   ÚfieldsÚpreviousÚstackÚtokenr   r   r   r   -   s0    




z
Mask.parsec                 C   s@   |  dd¡ ¡ }|d dkr<|d dkr0tdƒ‚|dd… }|S )	zRemove unnecessary charactersÚ
Ú r   r   éÿÿÿÿr   r   r   )ÚreplaceÚstripr   )r   r   r   r   r   r    \   s    z
Mask.cleanc                    sØ   ddl m} t|tttfƒr.‡ fdd„|D ƒS t||j|j|jfƒrN| 	ˆ ¡S t
|ƒ|jkrp|j|j|jˆ dS ||jkr†|jˆ dS t||jƒs¦t|ƒr°t||jƒr°tdƒ‚nt|ttfƒsÎt|dƒrÎ|j}ˆ  |¡S )	z¥
        Apply a fields mask to the data.

        :param data: The data or model to apply mask on
        :raises MaskError: when unable to apply the mask

        r   )r%   c                    s   g | ]}ˆ   |¡‘qS r   )Úapply)Ú.0Úd©r   r   r   Ú
<listcomp>r   s     zMask.apply.<locals>.<listcomp>)ÚdefaultÚ	attributer   )r   zMask is inconsistent with modelÚ__dict__)r*   r%   r   ÚlistÚtupleÚsetZNestedÚListZ	PolymorphÚcloneÚtypeZRawr3   r4   r   Ú
issubclassr   r   r   Úhasattrr5   Úfilter_data)r   Údatar%   r   r1   r   r.   f   s&    


ÿþ
ý
z
Mask.applyc                 C   sÀ   i }|   ¡ D ]€\}}|dkr qqt|tƒrj| |d¡}| jrH|dkrHqqŒ|dkrZd||< qŒ| |¡||< q| jr|||kr|qq| |d¡||< qd|  ¡ kr¼|  ¡ D ]\}}||kr¢|||< q¢|S )zì
        Handle the data filtering given a parsed mask

        :param dict data: the raw data to filter
        :param list mask: a parsed mask to filter against
        :param bool skip: whether or not to skip missing fields

        Ú*N)Úitemsr   r   Úgetr   r.   Úkeys)r   r?   ÚoutÚfieldÚcontentÚnestedÚkeyÚvaluer   r   r   r>   †   s&    	


zMask.filter_datac                 C   s   d  d dd„ |  ¡ D ƒ¡¡S )Nz{{{0}}}r   c                 S   s0   g | ](\}}t |tƒr(d  |t|ƒf¡n|‘qS )r*   )r   r   Újoinr   )r/   ÚkÚvr   r   r   r2   ©   s   ÿz Mask.__str__.<locals>.<listcomp>)ÚformatrJ   rA   r1   r   r   r   Ú__str__¦   s    þÿÿzMask.__str__)NF)r   r	   r
   r   r   r   r    r.   r>   rN   Ú__classcell__r   r   r   r   r      s   /
  r   Fc                 C   s   t ||ƒ | ¡S )a  
    Apply a fields mask to the data.

    :param data: The data or model to apply mask on
    :param str|Mask mask: the mask (parsed or not) to apply on data
    :param bool skip: If rue, missing field won't appear in result
    :raises MaskError: when unable to apply the mask

    )r   r.   )r?   r   r   r   r   r   r.   ±   s    
r.   )F)ÚloggingÚreÚcollectionsr   Úinspectr   Úerrorsr   Ú	getLoggerr   ÚlogÚcompiler!   r   r   r   r.   r   r   r   r   Ú<module>   s   

 