U
    d&                     @   s   d dl mZ d dlmZ d dlmZmZmZ ddlm	Z	m
Z ddlmZ dd ZdddZdddZG dd deZG dd deZd	S )    OrderedDictwraps)requestcurrent_apphas_app_context   )Maskapply)unpackc                 C   s   t | tr|  S | S N)
isinstancetype)cls r   ;/tmp/pip-unpacked-wheel-dt_sn2ih/flask_restx/marshalling.pymake
   s    
r   NFc                    s  t | ||||\}}|rddlm} g  g }	| D ]\}
}|
}t|trbt| ||d}nt|}t||}|r|  |	r| j	t
|	O  _	g }	|j|
| |d}|r fdd}|jp|
}||| |j|
| |d}|dks||j|jkr q8|j}||| qq8|	| rB|dks8|t ks8|i krBq8 ||f q8t  |rht nt }|r|rt||fgn||i}|S |S )  Takes raw data (in the form of a dict, list, object) and a dict of
    fields to output and filters the data based on those fields.

    :param data: the actual object(s) from which the fields are taken from
    :param fields: a dict of whose keys will make up the final serialized
                   response output
    :param envelope: optional key that will be used to envelop the serialized
                     response
    :param bool skip_none: optional key will be used to eliminate fields
                           which value is None or the field's key not
                           exist in data
    :param bool ordered: Wether or not to preserve order


    >>> from flask_restx import fields, marshal
    >>> data = { 'a': 100, 'b': 'foo', 'c': None }
    >>> mfields = { 'a': fields.Raw, 'c': fields.Raw, 'd': fields.Raw }

    >>> marshal(data, mfields)
    {'a': 100, 'c': None, 'd': None}

    >>> marshal(data, mfields, envelope='data')
    {'data': {'a': 100, 'c': None, 'd': None}}

    >>> marshal(data, mfields, skip_none=True)
    {'a': 100}

    >>> marshal(data, mfields, ordered=True)
    OrderedDict([('a', 100), ('c', None), ('d', None)])

    >>> marshal(data, mfields, envelope='data', ordered=True)
    OrderedDict([('data', OrderedDict([('a', 100), ('c', None), ('d', None)]))])

    >>> marshal(data, mfields, skip_none=True, ordered=True)
    OrderedDict([('a', 100)])

    r	   Wildcard	skip_noneorderedr   c                    s4   r"|d ks|t  ks|i kr"d S  | |f d S r   )r   append)kvitemsr   r   r   _appendN   s    zmarshal.<locals>._appendN)_marshalfieldsr   r   r   dictmarshalr   resetexcludesetoutputkey	containerformatdefaultr   r   tuple)datar"   enveloper   maskr   outhas_wildcardsr   keysZdkeyvalr)   valuefieldZis_wildcardr    r   r   r   r$      sN    &




"r$   c                    s
  ddl m  |ptdd}td|r:t|ddtttfrfdd	D }|r|rtt||fgn||i}|d
fS dd
i fddfdd D }rdd |D }rt|nt	|}|rrt||fgn||i}|d fS )r   r	   r   Z__mask__NZresolvedTskipc                    s   g | ]}t | d qS )r   )r$   ).0d)r"   r   r   r   r   
<listcomp>   s     z_marshal.<locals>.<listcomp>Fpresentc                    s2   t |}t| rdd< |j| d}| |fS )NTr<   r   )r   r   r(   )r)   r4   r6   r5   )r   r.   r2   r   r   r   __format_field   s
    
z _marshal.<locals>.__format_fieldc                 3   s:   | ]2\}}t |tr(|t|d fn ||V  qdS )r   N)r   r#   r$   r9   r   r   )r=   r.   r   r   r   r   	<genexpr>   s   z_marshal.<locals>.<genexpr>c                 s   s4   | ],\}}|d k	r|t  kr|i kr||fV  qd S r   r   r>   r   r   r   r?      s
     
  )
r"   r   getattr
apply_maskr   listr-   r   r   r#   )r.   r"   r/   r   r0   r   r1   r   r   )r   r=   r.   r"   r2   r   r   r   r!   p   s.    'r!   c                   @   s"   e Zd ZdZdddZdd ZdS )	marshal_witha+  A decorator that apply marshalling to the return values of your methods.

    >>> from flask_restx import fields, marshal_with
    >>> mfields = { 'a': fields.Raw }
    >>> @marshal_with(mfields)
    ... def get():
    ...     return { 'a': 100, 'b': 'foo' }
    ...
    ...
    >>> get()
    OrderedDict([('a', 100)])

    >>> @marshal_with(mfields, envelope='data')
    ... def get():
    ...     return { 'a': 100, 'b': 'foo' }
    ...
    ...
    >>> get()
    OrderedDict([('data', OrderedDict([('a', 100)]))])

    >>> mfields = { 'a': fields.Raw, 'c': fields.Raw, 'd': fields.Raw }
    >>> @marshal_with(mfields, skip_none=True)
    ... def get():
    ...     return { 'a': 100, 'b': 'foo', 'c': None }
    ...
    ...
    >>> get()
    OrderedDict([('a', 100)])

    see :meth:`flask_restx.marshal`
    NFc                 C   s*   || _ || _|| _|| _t|dd| _dS )z
        :param fields: a dict of whose keys will make up the final
                       serialized response output
        :param envelope: optional key that will be used to envelop the serialized
                         response
        Tr7   N)r"   r/   r   r   r
   r0   )selfr"   r/   r   r0   r   r   r   r   __init__   s
    	zmarshal_with.__init__c                    s   t   fdd}|S )Nc                     s    | |}j }t r0tjd }tj|p.|}t|trht	|\}}}t
|jjj|j||fS t
|jjj|jS d S )NZRESTX_MASK_HEADER)r0   r   r   configr   headersgetr   r-   r   r$   r"   r/   r   r   )argskwargsrespr0   Zmask_headerr.   coderG   frD   r   r   wrapper   s4    


     z&marshal_with.__call__.<locals>.wrapperr   rD   rN   rO   r   rM   r   __call__   s    zmarshal_with.__call__)NFNF__name__
__module____qualname____doc__rE   rQ   r   r   r   r   rC      s   !       
rC   c                   @   s    e Zd ZdZdd Zdd ZdS )marshal_with_fieldaP  
    A decorator that formats the return values of your methods with a single field.

    >>> from flask_restx import marshal_with_field, fields
    >>> @marshal_with_field(fields.List(fields.Integer))
    ... def get():
    ...     return ['1', 2, 3.0]
    ...
    >>> get()
    [1, 2, 3]

    see :meth:`flask_restx.marshal_with`
    c                 C   s   t |tr| | _n|| _dS )zP
        :param field: a single field with which to marshal the output.
        N)r   r   r6   )rD   r6   r   r   r   rE     s    

zmarshal_with_field.__init__c                    s   t   fdd}|S )Nc                     s@    | |}t |tr4t|\}}}j|||fS j|S r   )r   r-   r   r6   r+   )rI   rJ   rK   r.   rL   rG   rM   r   r   rO   (  s
    

z,marshal_with_field.__call__.<locals>.wrapperr   rP   r   rM   r   rQ   '  s    zmarshal_with_field.__call__NrR   r   r   r   r   rW     s   	rW   )NFNF)NFNF)collectionsr   	functoolsr   Zflaskr   r   r   r0   r
   r   rA   utilsr   r   r$   r!   objectrC   rW   r   r   r   r   <module>   s   
`
QN