U
    QhF                     @   s  d Z ddlZddlZddlZddlmZ ddlmZ zddlmZ W n e	k
rX   Y nX ddl
mZmZmZmZmZmZmZmZmZmZmZ ddlmZ ddlmZ dd	lmZmZmZmZ dd
lm Z  ddl!m"Z" ddl#m$Z$m%Z%m&Z&m'Z' ddl(m)Z)m*Z* ddl+m,Z, erVddl(m-Z- ddl.m/Z/m0Z0 edddZ1eed df Z2G dd dZ3dddddgZ4edZ5ej6dkrVeej7e$fdedddddddddd d!
e8e8e8e8e8e8eeee9 df ee8 ee8 e8eee5 gd"f d#d$dZ:eej7e$fdedddddddddd d!
ee5 e8e8e8e8e8e8eeee9 df ee8 ee8 e8d"d%d&dZ:neej7e$fdedddddddddd'	e8e8e8e8e8e8eeee9 df ee8 ee8 eee5 gd"f d(
d)dZ:eej7e$fdedddddddddd'	ee5 e8e8e8e8e8e8eeee9 df ee8 ee8 d"d*d+dZ:eej7e$fddLddddddddddd!
eee5  e8e8e8e8e8e8eeee9 df ee8 ee8 e8eeee5 gd"f d"f d%d,dZ:eed e8eed ddf d-d.dZ;G d/d dZ<ed ee e8e=dd0d1d2Z>d"d3d4d5d6Z?ed edd7d8d9Z@edfed ee ee= ed: d;d<dZAej6d=krpde=e8d>d?d@ZBnde=e8d>dAd@ZBdddBdCdDZCde=eddEdFdGZDee e8dHdIdZEed ee d3dJdKdZFdS )MaX  
The main purpose is to enhance stdlib dataclasses by adding validation
A pydantic dataclass can be generated from scratch or from a stdlib one.

Behind the scene, a pydantic dataclass is just like a regular one on which we attach
a `BaseModel` and magic methods to trigger the validation of the data.
`__init__` and `__post_init__` are hence overridden and have extra logic to be
able to validate input data.

When a pydantic dataclass is generated from scratch, it's just a plain dataclass
with validation triggered at initialization

The tricky part if for stdlib dataclasses that are converted after into pydantic ones e.g.

```py
@dataclasses.dataclass
class M:
    x: int

ValidatedM = pydantic.dataclasses.dataclass(M)
```

We indeed still want to support equality, hashing, repr, ... as if it was the stdlib one!

```py
assert isinstance(ValidatedM(x=1), M)
assert ValidatedM(x=1) == M(x=1)
```

This means we **don't want to create a new dataclass that inherits from it**
The trick is to create a wrapper around `M` that will act as a proxy to trigger
validation without altering default `M` behaviour.
    N)contextmanager)wraps)cached_property)TYPE_CHECKINGAnyCallableClassVarDict	GeneratorOptionalTypeTypeVarUnionoverload)dataclass_transform)gather_all_validators)
BaseConfig
ConfigDictExtra
get_config)ValidationError)DataclassTypeError)Field	FieldInfoRequired	Undefined)create_modelvalidate_model)ClassAttribute)	BaseModel)CallableGeneratorNoArgAnyCallable
DataclassT	Dataclass)ZboundDataclassProxyc                   @   s   e Zd ZU eeeef  ed< ee ed< eed  ed< ee	 ed< eed  ed< ee	 ed< ee
e  ed< eed gd	f  ed
< ee	 ed< eed	dddZee
d  ddddZee
d eddddZd	S )r#   __dataclass_fields____dataclass_params__).N__post_init____pydantic_run_validation____post_init_post_parse____pydantic_initialised____pydantic_model__N__pydantic_validate_values__#__pydantic_has_field_info_default__argskwargsreturnc                 O   s   d S N selfr/   r0   r3   r3   =./venv/lib/python3.8/site-packages/pydantic/v1/dataclasses.py__init__P   s    zDataclass.__init__r    clsr1   c                 C   s   d S r2   r3   r9   r3   r3   r6   __get_validators__S   s    zDataclass.__get_validators__r"   r9   vr1   c                 C   s   d S r2   r3   r9   r=   r3   r3   r6   __validate__W   s    zDataclass.__validate__)__name__
__module____qualname__r   r	   strr   __annotations__r   boolr   r   objectr7   classmethodr;   r?   r3   r3   r3   r6   r#   B   s   
	dataclassset_validation$create_pydantic_model_from_dataclassis_builtin_dataclassmake_dataclass_validator_T   
   )Zfield_specifiersTF.
initrepreqorderunsafe_hashfrozenconfigvalidate_on_init	use_proxykw_onlyDataclassClassOrWrapper)rR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   r1   c        
   
      C   s   d S r2   r3   rQ   r3   r3   r6   rH   h   s    )_clsrR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   r1   c       
         C   s   d S r2   r3   )r]   rR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   r3   r3   r6   rH   y   s    	rR   rS   rT   rU   rV   rW   rX   rY   rZ   )
rR   rS   rT   rU   rV   rW   rX   rY   rZ   r1   c        	   	      C   s   d S r2   r3   r^   r3   r3   r6   rH      s    )r]   rR   rS   rT   rU   rV   rW   rX   rY   rZ   r1   c       	   
      C   s   d S r2   r3   )
r]   rR   rS   rT   rU   rV   rW   rX   rY   rZ   r3   r3   r6   rH      s    c       
            sF   t |tt dd 	f
dd}| dkr>|S || S )a  
    Like the python standard lib dataclasses but with type validation.
    The result is either a pydantic dataclass that will validate input data
    or a wrapper that will trigger validation around a stdlib dataclass
    to avoid modifying it directly
    r\   r8   c              
      s   d k	rn2t | o>| jd tkp>tt| tt| jd k}|rVd}t| }d}nL| jp^d}tjdkrt	j
|  d}nt	j
|  d}d}	d kr|n	}t| || |jjf | j| i |S )Nr    FrN   )rR   rS   rT   rU   rV   rW   r[   )rR   rS   rT   rU   rV   rW   T)rK   	__bases__rF   setdirr$   __doc__sysversion_infodataclassesrH   #_add_pydantic_validation_attributesr+   Z__try_update_forward_refs__r@   )r9   Zshould_use_proxy
dc_cls_docdc_clsZdefault_validate_on_initZshould_validate_on_init
rT   rW   rR   r[   rU   rS   Z
the_configrV   rZ   rY   r3   r6   wrap   sF    *

      zdataclass.<locals>.wrapN)r   r   r   )r]   rR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   rk   r3   rj   r6   rH      s
    *%)r9   valuer1   c                 c   s$   | j }z|| _ | V  W 5 || _ X d S r2   )r(   )r9   rl   Zoriginal_run_validationr3   r3   r6   rI      s
    
c                   @   s   e Zd ZdZed ddddZeeeddd	Zeed
ddZ	eeddddZ
eedddZd dddZed dddZdS )r$   __dataclass__r#   N)ri   r1   c                 C   s   t | d| d S )Nrm   )rF   __setattr__)r5   ri   r3   r3   r6   r7      s    zDataclassProxy.__init__r.   c              
   O   s0   t | jd | j||W  5 Q R  S Q R X d S )NT)rI   rm   r4   r3   r3   r6   __call__  s    zDataclassProxy.__call__)namer1   c                 C   s   t | j|S r2   )getattrrm   )r5   rp   r3   r3   r6   __getattr__  s    zDataclassProxy.__getattr__)_DataclassProxy__name_DataclassProxy__valuer1   c                 C   s   t | j||S r2   )setattrrm   )r5   rs   rt   r3   r3   r6   rn     s    zDataclassProxy.__setattr__)instancer1   c                 C   s   t || jS r2   )
isinstancerm   )r5   rv   r3   r3   r6   __instancecheck__  s    z DataclassProxy.__instancecheck__)r1   c                 C   s   t t| jS r2   )r$   copyrm   r5   r3   r3   r6   __copy__  s    zDataclassProxy.__copy__)memor1   c                 C   s   t t| j|S r2   )r$   ry   deepcopyrm   )r5   r|   r3   r3   r6   __deepcopy__  s    zDataclassProxy.__deepcopy__)r@   rA   rB   	__slots__r   r7   r   ro   rC   rr   rn   rE   rx   r{   r~   r3   r3   r3   r6   r$      s   )ri   rX   rY   rh   r1   c                    sF  | j tdttdd fddt| drz| jjW n tk
rX   | jY nX tdttdd fdd}t| d	 t| d| n,tdttddfd
d}t| d	| t| dtd| t| dd t| dt	|  | t| dt
 t| dtt t| dtt | jjjrB| jjsBt| dt dS )a  
    We need to replace the right method. If no `__post_init__` has been set in the stdlib dataclass
    it won't even exist (code is generated on the fly by `dataclasses`)
    By default, we run validation after `__init__` or `__post_init__` if defined
    r#   N)r5   r/   r0   r1   c                    s   j tjkr0 f| fdd| D  n`j tjkr| D ]\}} j|| qD f| fdd| D  n f|| d S )Nc                    s    i | ]\}}| j kr||qS r3   r%   .0kr=   rz   r3   r6   
<dictcomp>%  s     
  zR_add_pydantic_validation_attributes.<locals>.handle_extra_init.<locals>.<dictcomp>c                    s    i | ]\}}| j kr||qS r3   r   r   rz   r3   r6   r   *  s     
  )Zextrar   ignoreitemsZallow__dict__
setdefault)r5   r/   r0   r   r=   )rX   rR   rz   r6   handle_extra_init"  s    $$z>_add_pydantic_validation_attributes.<locals>.handle_extra_initr'   c                    s^    j dkr| f|| | jjr@|   t| dr@| j||  j dkrZ| f|| d S )NZbefore_validationr)   Zafter_validation)Zpost_init_call	__class__r(   r,   hasattrr)   r4   )rX   	post_initr3   r6   new_post_init5  s    


z:_add_pydantic_validation_attributes.<locals>.new_post_initr7   c              	      s    | f|| | j jr |   t| dri }t| j j D ]R\}}|jtj	kr>z|| ||j
< W q> tk
r   ||j
|j||j
< Y q>X q>| jf | d S )Nr)   )r   r(   r,   r   	enumerater%   valuesZ_field_typerf   Z_FIELD_INITVARrp   
IndexErrorgetdefaultr)   )r5   r/   r0   Zinitvars_and_valuesif)r   r3   r6   new_initG  s    
z5_add_pydantic_validation_attributes.<locals>.new_initr(   r*   Fr+   r,   r?   r;   rn   )r7   r   r   r   r'   __wrapped__AttributeErrorru   r   rJ   _dataclass_validate_valuesrG   _validate_dataclass_get_validatorsr+   
__config__Zvalidate_assignmentr&   rW   &_dataclass_validate_assignment_setattr)ri   rX   rY   rh   r   r   r3   )rX   r   rR   r   r6   rg     s.    
rg   r    r8   c                 c   s   | j V  d S r2   )r?   r:   r3   r3   r6   r   k  s    r   r<   c              
   C   s   t | dv t|| r.|  |W  5 Q R  S t|ttfrP| | W  5 Q R  S t|trp| f |W  5 Q R  S t| jdW 5 Q R X d S )NT)
class_name)rI   rw   r,   listtupledictr   r@   r>   r3   r3   r6   r   o  s    

r   r   )ri   rX   rh   r1   c           
      C   s   i }t | D ]t}t}d }|jt jk	r.|j}n|jt jk	rB|j}nt}t|tr\|}d| _	nt
f ||d|j}|j|f||j< qt| }t| jf|| j|ddid|}	|d k	r|n| jpd|	_|	S )NT)r   default_factoryZ__resolve_forward_refs__F)r   rA   Z__validators__Z__cls_kwargs__r_   )rf   Zfieldsr   r   MISSINGr   r   rw   r   r-   r   Zmetadatatyperp   r   r   r@   rA   rc   )
ri   rX   rh   Zfield_definitionsfieldr   r   Z
field_infoZ
validatorsZmodelr3   r3   r6   rJ   |  s6    
)rO      )objr   r1   c                 C   s   t tt| |d tS r2   )rw   rq   r   r   r   r   r3   r3   r6   _is_field_cached_property  s    r   c                 C   s   dS )NFr3   r   r3   r3   r6   r     s    )r5   r1   c                    s   t  drd S t  ddr4 fdd j D }n fdd j D }t j| jd\}}}|rl| j| t dd d S )	Nr*   r-   Fc                    s*   i | ]"\}}t |tst |s||qS r3   )rw   r   r   r   rz   r3   r6   r     s
   
 
 z._dataclass_validate_values.<locals>.<dictcomp>c                    s    i | ]\}}t  |s||qS r3   )r   r   rz   r3   r6   r     s     
  r:   T)	rq   r   r   r   r+   r   updaterF   rn   )r5   Z
input_datad_Zvalidation_errorr3   rz   r6   r     s    

r   )r5   rp   rl   r1   c                 C   sl   | j rZt| j}||d  | jj|d }|rZ|j|||| jd\}}|rZt	|g| jt
| || d S )N)locr9   )r*   r   r   popr+   Z
__fields__r   Zvalidater   r   rF   rn   )r5   rp   rl   r   Zknown_fieldZerror_r3   r3   r6   r     s    
r   )r]   r1   c                 C   s2   t | o0t| d o0t| jtt| di S )a  
    Whether a class is a stdlib dataclass
    (useful to discriminated a pydantic dataclass that is actually a wrapper around a stdlib dataclass)

    we check that
    - `_cls` is a dataclass
    - `_cls` is not a processed pydantic dataclass (with a basemodel attached)
    - `_cls` is not a pydantic dataclass inheriting directly from a stdlib dataclass
    e.g.
    ```
    @dataclasses.dataclass
    class A:
        x: int

    @pydantic.dataclasses.dataclass
    class B(A):
        y: int
    ```
    In this case, when we first check `B`, we make an extra check and look at the annotations ('y'),
    which won't be a superset of all the dataclass fields (only the stdlib fields i.e. 'x')
    r+   rD   )rf   Zis_dataclassr   ra   r%   
issupersetrq   )r]   r3   r3   r6   rK     s
    

)ri   rX   r1   c                 c   s   t t| |ddE dH  dS )z
    Create a pydantic.dataclass from a builtin dataclass to add type validation
    and yield the validators
    It retrieves the parameters of the dataclass and forwards them to the newly created dataclass
    T)rX   rZ   N)r   rH   )ri   rX   r3   r3   r6   rL     s    )N)Grc   ry   rf   rd   
contextlibr   	functoolsr   r   ImportErrortypingr   r   r   r   r	   r
   r   r   r   r   r   Ztyping_extensionsr   Zpydantic.v1.class_validatorsr   Zpydantic.v1.configr   r   r   r   Zpydantic.v1.error_wrappersr   Zpydantic.v1.errorsr   Zpydantic.v1.fieldsr   r   r   r   Zpydantic.v1.mainr   r   Zpydantic.v1.utilsr   r   Zpydantic.v1.typingr    r!   r"   r\   r#   __all__rM   re   r   rE   rF   rH   rI   r$   rC   rg   r   r   rJ   r   r   r   rK   rL   r3   r3   r3   r6   <module>   sn  !4 
A&	V'