U
    d                      @   s   d dl Z d dlZd dl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 d dlmZ d d	lmZ dd
lmZ ddlmZ edejejB Zdd ZG dd deZG dd deZG dd deeeZG dd deeeZG dd deZ dS )    N)OrderedDict)MutableMapping)cached_property   )Mask)abort)Draft4Validator)ValidationError)not_none)
HTTPStatusz)u?\'(?P<name>.*)\' is a required propertyc                 C   s   t | tr|  S | S N)
isinstancetype)cls r   5/tmp/pip-unpacked-wheel-dt_sn2ih/flask_restx/model.pyinstance   s    
r   c                       sj   e Zd ZdZ fddZedd Zdd Zedd	 Ze	d
d Z
dddZdd Zdd ZeZ  ZS )	ModelBasez
    Handles validation and swagger style inheritance for both subclasses.
    Subclass must define `schema` attribute.

    :param str name: The model public name
    c                    s>   t t j|| d|i _| _g  _ fdd}| _d S )Nnamec                    s    j j|  f| S r   )	__class__inheritr   parentsselfr   r   instance_inherit+   s    z,ModelBase.__init__.<locals>.instance_inherit)superr   __init__Z
__apidoc__r   __parents__r   )r   r   argskwargsr   r   r   r   r   %   s    
zModelBase.__init__c                 C   s(   dd | j D }tjt| jgf| S )z+
        Return the ancestors tree
        c                 S   s   g | ]
}|j qS r   )	ancestors.0pr   r   r   
<listcomp>5   s     z'ModelBase.ancestors.<locals>.<listcomp>)r   setunionr   )r   r"   r   r   r   r"   0   s    zModelBase.ancestorsc                 C   sD   | j |kr| S | jD ]}||}|r|  S qtd| d d S )NzParent z
 not found)r   r   
get_parent
ValueError)r   r   parentfoundr   r   r   r)   8   s    



zModelBase.get_parentc                 C   s2   | j }| jr*dd | jD }d||g iS |S d S )Nc                 S   s   g | ]}d d |jiqS )z$refz#/definitions/{0})formatr   )r$   r+   r   r   r   r&   G   s   z(ModelBase.__schema__.<locals>.<listcomp>ZallOf)_schemar   )r   schemarefsr   r   r   
__schema__B   s    zModelBase.__schema__c                 G   s    | ||d }|dd |_ |S )z
        Inherit this model (use the Swagger composition pattern aka. allOf)
        :param str name: The new model name
        :param dict fields: The new model extra fields
        N)r   )r   r   r   modelr   r   r   r   P   s    zModelBase.inheritNc                    s`   t  j||d}z|| W n< tk
rZ   ttjdt fdd||D d Y nX d S )N)resolverformat_checkerzInput payload validation failedc                 3   s   | ]}  |V  qd S r   )format_error)r$   er   r   r   	<genexpr>e   s     z%ModelBase.validate.<locals>.<genexpr>)messageerrors)	r   r1   validater	   r   r   BAD_REQUESTdictZiter_errors)r   datar4   r5   	validatorr   r   r   r;   [   s      zModelBase.validatec                 C   sN   t |j}|jdkr0t|jd}|| ddd |D }||jfS )Nrequiredr   .c                 s   s   | ]}t |V  qd S r   )strr#   r   r   r   r8   m   s     z)ModelBase.format_error.<locals>.<genexpr>)	listpathr?   RE_REQUIREDmatchr9   groupappendjoin)r   errorrD   r   keyr   r   r   r6   h   s    


zModelBase.format_errorc                 C   s   dj | jd|  dS )NzModel({name},{{{fields}}}),)r   fields)r-   r   rI   keysr   r   r   r   __unicode__p   s     zModelBase.__unicode__)NN)__name__
__module____qualname____doc__r   propertyr"   r)   r1   classmethodr   r;   r6   rO   __str____classcell__r   r   r!   r   r      s   





r   c                       sX   e Zd ZdZeZ fddZedd Ze	dd Z
dd	 Zed
d Zdd Z  ZS )RawModela:  
    A thin wrapper on ordered fields dict to store API doc metadata.
    Can also be used for response marshalling.

    :param str name: The model public name
    :param str mask: an optional default model mask
    :param bool strict: validation should raise error when there is param not provided in schema
    c                    sh   | dd  _| dd _ jr:t jts:t j _tt j|f||  fdd}| _d S )NmaskstrictFc                    s    j j|  f| S r   )r   cloner   r   r   r   instance_clone   s    z)RawModel.__init__.<locals>.instance_clone)	pop__mask__
__strict__r   r   r   rX   r   r[   )r   r   r   r    r\   r!   r   r   r      s    zRawModel.__init__c                 C   s   |   }t }d }|  D ]:\}}t|}|j||< |jrD|| t|ddr|}qtt	|pdd ||| j
rxt| j
nd dd}| jrd|d< t|S )NdiscriminatorFobject)r@   
propertiesr`   zx-maskr   ZadditionalProperties)wrapperr'   itemsr   r1   r@   addgetattrsortedrC   r^   rB   r_   r
   )r   rb   r@   r`   r   fieldZ
definitionr   r   r   r.      s&    

zRawModel._schemac                 C   sf   t | }| jD ]}||j qdd | D }t|dkrJtdnt|dkrb| j|d _	|S )zG
        Resolve real fields before submitting them to marshal
        c                 S   s   g | ]}t |d dr|qS )r`   N)rf   )r$   fr   r   r   r&      s      z%RawModel.resolved.<locals>.<listcomp>r   z-There can only be one discriminator by schemar   )
copydeepcopyr   updateresolvedvalueslenr*   r   default)r   rm   r+   
candidatesr   r   r   rm      s    


zRawModel.resolvedc                 C   s>   t jdtdd t|ttfr.| j|f| S | ||S dS )z
        Extend this model (Duplicate all fields)

        :param str name: The new model name
        :param dict fields: The new model extra fields

        :deprecated: since 0.9. Use :meth:`clone` instead.
        z*extend is is deprecated, use clone instead   )
stacklevelN)warningswarnDeprecationWarningr   rC   tupler[   )r   r   rM   r   r   r   extend   s    	zRawModel.extendc                 G   s,   |   }|D ]}|t| q| ||S )a\  
        Clone these models (Duplicate all fields)

        It can be used from the class

        >>> model = Model.clone(fields_1, fields_2)

        or from an Instanciated model

        >>> new_model = model.clone(fields_1, fields_2)

        :param str name: The new model name
        :param dict parents: The new model extra fields
        )rc   rl   rj   rk   )r   r   r   rM   r+   r   r   r   r[      s    zRawModel.clonec                    s6   | j | j fdd|  D | j| jd}| j|_|S )Nc                    s    g | ]\}}|t | fqS r   )rj   rk   )r$   rK   valuememor   r   r&      s     z)RawModel.__deepcopy__.<locals>.<listcomp>)rY   rZ   )r   r   rd   r^   r_   r   )r   r{   objr   rz   r   __deepcopy__   s    zRawModel.__deepcopy__)rP   rQ   rR   rS   r=   rc   r   rT   r.   r   rm   rx   rU   r[   r}   rW   r   r   r!   r   rX   x   s   	


rX   c                   @   s   e Zd ZdZdS )Modelz
    A thin wrapper on fields dict to store API doc metadata.
    Can also be used for response marshalling.

    :param str name: The model public name
    :param str mask: an optional default model mask
    N)rP   rQ   rR   rS   r   r   r   r   r~      s   r~   c                   @   s   e Zd ZdZeZdS )OrderedModelz
    A thin wrapper on ordered fields dict to store API doc metadata.
    Can also be used for response marshalling.

    :param str name: The model public name
    :param str mask: an optional default model mask
    N)rP   rQ   rR   rS   r   rc   r   r   r   r   r      s   r   c                       s.   e Zd ZdZd fdd	Zdd ZeZ  ZS )SchemaModelz
    Stores API doc metadata based on a json schema.

    :param str name: The model public name
    :param dict schema: The json schema we are documenting
    Nc                    s   t t| | |pi | _d S r   )r   r   r   r.   )r   r   r/   r!   r   r   r     s    zSchemaModel.__init__c                 C   s   dj | j| jdS )NzSchemaModel({name},{schema}))r   r/   )r-   r   r.   r   r   r   r   rO     s     zSchemaModel.__unicode__)N)rP   rQ   rR   rS   r   rO   rV   rW   r   r   r!   r   r     s   r   )!rj   rert   collectionsr   collections.abcr   Zwerkzeug.utilsr   rY   r   r:   r   Z
jsonschemar   Zjsonschema.exceptionsr	   utilsr
   Z_httpr   compileIUrE   r   ra   r   rX   r=   r~   r   r   r   r   r   r   <module>   s$   [|