o
    pfF                     @   sT  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	y+   Y nw 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rddl(m-Z- ddl
m.Z.m/Z/ edddZ0eed df Z1G dd dZ2g dZ3edZ4ej5dkr;eej6e$fdeddddddddddd
de7d e7d!e7d"e7d#e7d$e7d%eeee8 df d&ee7 d'ee7 d(e7d)eee4 gd*f fd+d,Z9eej6e$fdeddddddddddd
d-ee4 de7d e7d!e7d"e7d#e7d$e7d%eeee8 df d&ee7 d'ee7 d(e7d)d*fd.d,Z9n}eej6e$fdedddddddddd/	de7d e7d!e7d"e7d#e7d$e7d%eeee8 df d&ee7 d'ee7 d)eee4 gd*f fd0d,Z9eej6e$fdedddddddddd/	d-ee4 de7d e7d!e7d"e7d#e7d$e7d%eeee8 df d&ee7 d'ee7 d)d*fd1d,Z9eej6e$fd	dUddddddddddd
d-eee4  de7d e7d!e7d"e7d#e7d$e7d%eeee8 df d&ee7 d'ee7 d(e7d)eeee4 gd*f d*f fd2d,Z9ed3ed d4e7d)eed ddf fd5d6Z:G d7d dZ;d8ed d%ee d&e7d9e<d)df
d:d;Z=dVd=d>Z>d3ed d?ed)dfd@dAZ?edfd8ed d%ee d9ee< d)edB fdCdDZ@ej5dEkrqdFddGe<d)e7fdHdIZAndFddGe<d)e7fdJdIZAdWdLdMZBdKddNe<d4ed)dfdOdPZCd-ee d)e7fdQdRZDd8ed d%ee d)d<fdSdTZEdS )XaX  
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)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< dededd	fddZede
d  ddfddZede
d deddf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      d S N selfr0   r1   r5   r5   P/home/ertert/spirit/venv/lib/python3.10/site-packages/pydantic/v1/dataclasses.py__init__P      zDataclass.__init__clsr!   c                 C   r3   r4   r5   r;   r5   r5   r8   __get_validators__S      zDataclass.__get_validators__r#   vc                 C   r3   r4   r5   r;   r?   r5   r5   r8   __validate__W   r>   zDataclass.__validate__)__name__
__module____qualname__r   r	   strr   __annotations__r   boolr   r    objectr9   classmethodr=   rA   r5   r5   r5   r8   r$   B   s   
  )	dataclassset_validation$create_pydantic_model_from_dataclassis_builtin_dataclassmake_dataclass_validator_T   
   )field_specifiersTF.
initrepreqorderunsafe_hashfrozenconfigvalidate_on_init	use_proxykw_onlyrU   rV   rW   rX   rY   rZ   r[   r\   r]   r^   r2   DataclassClassOrWrapperc        
   
      C   r3   r4   r5   rT   r5   r5   r8   rJ   h      rJ   _clsc       
         C   r3   r4   r5   )ra   rU   rV   rW   rX   rY   rZ   r[   r\   r]   r^   r5   r5   r8   rJ   y   s   	rU   rV   rW   rX   rY   rZ   r[   r\   r]   c        	   	      C   r3   r4   r5   rb   r5   r5   r8   rJ      s   c       	   
      C   r3   r4   r5   )
ra   rU   rV   rW   rX   rY   rZ   r[   r\   r]   r5   r5   r8   rJ      r`   c       
            sH   t |dtt ddf 	f
dd}| du 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;   r2   r_   c              
      s   d urnt | o| jd tu ptt| tt| jd k}|r+d}t| }d}n&| jp/d}tjdkrCt	j
|  d}nt	j
|  d}d}	d u rW|n	}t| || |jjdi | j| i |S )	Nr    FrP   )rU   rV   rW   rX   rY   rZ   r^   )rU   rV   rW   rX   rY   rZ   Tr5   )rM   	__bases__rH   setdirr&   __doc__sysversion_infodataclassesrJ   #_add_pydantic_validation_attributesr-   __try_update_forward_refs__rB   )r;   should_use_proxy
dc_cls_docdc_clsdefault_validate_on_initshould_validate_on_init
rW   rZ   rU   r^   rX   rV   
the_configrY   r]   r\   r5   r8   wrap   s:   *

zdataclass.<locals>.wrapN)r   r   r   )ra   rU   rV   rW   rX   rY   rZ   r[   r\   r]   r^   rt   r5   rr   r8   rJ      s
   ,%r;   valuec                 c   s*    | j }z|| _ | V  W || _ d S || _ w r4   )r*   )r;   ru   original_run_validationr5   r5   r8   rK      s   rK   c                   @   s   e Zd ZdZded ddfddZded	edefd
dZdedefddZ	dededdfddZ
dedefddZdddZdedd fddZdS )r&   __dataclass__ro   r$   r2   Nc                 C   s   t | d| d S )Nrw   )rH   __setattr__)r7   ro   r5   r5   r8   r9         zDataclassProxy.__init__r0   r1   c                 O   s@   t | jd | j|i |W  d    S 1 sw   Y  d S )NT)rK   rw   r6   r5   r5   r8   __call__  s   $zDataclassProxy.__call__namec                 C   s   t | j|S r4   )getattrrw   )r7   r{   r5   r5   r8   __getattr__     zDataclassProxy.__getattr___DataclassProxy__name_DataclassProxy__valuec                 C   s   t | j||S r4   )setattrrw   )r7   r   r   r5   r5   r8   rx     s   zDataclassProxy.__setattr__instancec                 C   s   t || jS r4   )
isinstancerw   )r7   r   r5   r5   r8   __instancecheck__  r~   z DataclassProxy.__instancecheck__c                 C   s   t t| jS r4   )r&   copyrw   r7   r5   r5   r8   __copy__  s   zDataclassProxy.__copy__memoc                 C   s   t t| j|S r4   )r&   r   deepcopyrw   )r7   r   r5   r5   r8   __deepcopy__  ry   zDataclassProxy.__deepcopy__)r2   r&   )rB   rC   rD   	__slots__r   r9   r   rz   rE   r}   rx   rG   r   r   r   r5   r5   r5   r8   r&      s    
ro   rn   c              	      sZ  | j tdddtdtddf fddt| d	rPz| jjW n ty.   | jY nw tdddtdtddf fd
d}t| d t| d	| ntdddtdtddf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r| jjst| dt dS dS 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
    r7   r$   r0   r1   r2   Nc                    s   j tjkr g|R i  fdd| D  d S j tjkrH| D ]\}} j|| q& g|R i  fdd| D  d S  g|R i | d S )Nc                        i | ]\}}| j v r||qS r5   r'   .0kr?   r   r5   r8   
<dictcomp>%       zR_add_pydantic_validation_attributes.<locals>.handle_extra_init.<locals>.<dictcomp>c                    r   r5   r   r   r   r5   r8   r   *  r   )extrar   ignoreitemsallow__dict__
setdefault)r7   r0   r1   r   r?   )r[   rU   r   r8   handle_extra_init"  s   ,,z>_add_pydantic_validation_attributes.<locals>.handle_extra_initr)   c                    sr    j dkr| g|R i | | jjr%|   t| dr%| j|i |  j dkr7| g|R i | d S d S )Nbefore_validationr+   after_validation)post_init_call	__class__r*   r.   hasattrr+   r6   )r[   	post_initr5   r8   new_post_init5  s   


z:_add_pydantic_validation_attributes.<locals>.new_post_initr9   c              	      s    | g|R i | | j jr|   t| drUi }t| j j D ](\}}|jtj	u rJz	|| ||j
< W q" tyI   ||j
|j||j
< Y q"w q"| jdi | d S d S )Nr+   r5   )r   r*   r.   r   	enumerater'   values_field_typerj   _FIELD_INITVARr{   
IndexErrorgetdefaultr+   )r7   r0   r1   initvars_and_valuesif)r   r5   r8   new_initG  s   
z5_add_pydantic_validation_attributes.<locals>.new_initr*   r,   Fr-   r.   rA   r=   rx   )r9   r   r   r   r)   __wrapped__AttributeErrorr   r   rL   _dataclass_validate_valuesrI   _validate_dataclass_get_validatorsr-   
__config__validate_assignmentr(   rZ   &_dataclass_validate_assignment_setattr)ro   r[   r\   rn   r   r   r5   )r[   r   rU   r   r8   rk     s2   "

" rk   r!   c                 c   s    | j V  d S r4   )rA   r<   r5   r5   r8   r   k  s   r   r?   c                 C   s   t | d> t|| r|  |W  d    S t|ttfr*| | W  d    S t|tr=| di |W  d    S t| jd1 sFw   Y  d S )NT)
class_namer5   )rK   r   r.   listtupledictr   rB   r@   r5   r5   r8   r   o  s   

	r   r    c           
      C   s   i }t | D ]:}t}d }|jt jur|j}n|jt jur!|j}nt}t|tr.|}d| _	nt
d||d|j}|j|f||j< qt| }t| jf|| j|ddid|}	|d ur`||	_|	S | jpdd|	_|	S )NT)r   default_factory__resolve_forward_refs__F)r   rC   __validators____cls_kwargs__rc   r5   )rj   fieldsr   r   MISSINGr   r   r   r   r/   r   metadatatyper{   r   r   rB   rC   rg   )
ro   r[   rn   field_definitionsfieldr   r   
field_info
validatorsmodelr5   r5   r8   rL   |  s:   
rL   )rQ      objr   c                 C   s   t tt| |d tS r4   )r   r|   r   r   r   r   r5   r5   r8   _is_field_cached_property  s   r   c                 C   s   dS )NFr5   r   r5   r5   r8   r     r:   r7   c                    s   t  drd S t  ddr fdd j D }n fdd j D }t j| jd\}}}|r6| j| t dd d S )	Nr,   r/   Fc                    s*   i | ]\}}t |tst |s||qS r5   )r   r   r   r   r   r5   r8   r     s    z._dataclass_validate_values.<locals>.<dictcomp>c                    s    i | ]\}}t  |s||qS r5   )r   r   r   r5   r8   r     r   r<   T)	r|   r   r   r   r-   r   updaterH   rx   )r7   
input_datad_validation_errorr5   r   r8   r     s   

r   r{   c                 C   sl   | j r-t| j}||d  | jj|d }|r-|j|||| jd\}}|r-t	|g| jt
| || d S )N)locr;   )r,   r   r   popr-   
__fields__r   validater   r   rH   rx   )r7   r{   ru   r   known_fielderror_r5   r5   r8   r     s   
r   c                 C   s2   t | ot| d ot| 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-   rF   )rj   is_dataclassr   re   r'   
issupersetr|   )ra   r5   r5   r8   rM     s
   

rM   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)r[   r]   N)r   rJ   )ro   r[   r5   r5   r8   rN     s   rN   r4   )r;   r_   r2   r!   )r7   r$   r2   N)Frg   r   rj   rh   
contextlibr   	functoolsr   r   ImportErrortypingr   r   r   r   r	   r
   r   r   r   r   r   typing_extensionsr   class_validatorsr   r[   r   r   r   r   error_wrappersr   errorsr   r   r   r   r   r   mainr   r   utilsr   r    r!   r"   r#   r_   r$   __all__rO   ri   r   rG   rH   rJ   rK   r&   rE   rk   r   r   rL   r   r   r   rM   rN   r5   r5   r5   r8   <module>   s   !4	
	
	
	

	
A*	

V
'
"