
    #ZjM                        U d Z ddlZddlZddlmZmZmZ ddlmZ ddlm	Z
 ej        dk    rdZdZn	 ddlmZ dd	lmZ n# eef$ r dZdZY nw xY w	 ddlmZ dd	lmZ n# eef$ r dZdZY nw xY w G d
 d          Z G d d          Z G d d          Z G d d          Zd(dddZ G d de          Z G d d          Z G d d          Zd)dZd Zd Z d Z!d)dZ"i Z#e$e%d <   d! Z&d" Z'd# Z(d$ Z)d% Z*d& Z+d' Z,dS )*zLightweight type validation system replacing Pydantic.

Provides Schema base class, dynamic schema creation, and type validation
for config values against function signatures.
    N)AnyOptionalget_type_hints   )Ctx)
check_type)      )	BaseModel)ValidationErrorc                       e Zd ZdZdS )
StrictBoolz.Only accepts actual bool values (not int 0/1).N__name__
__module____qualname____doc__     a/Users/jameslopez/projects/MentorCore/.venv/lib/python3.11/site-packages/confection/validation.pyr   r   .   s        88Dr   r   c                       e Zd ZdZdS )PositiveIntz/Only accepts positive integers (> 0, not bool).Nr   r   r   r   r   r   4   s        99Dr   r   c                       e Zd ZdZdS )StrictFloatz+Only accepts actual float values (not int).Nr   r   r   r   r   r   :   s        55Dr   r   c                   *    e Zd ZdZdZddddZd ZdS )		FieldInfoz!Information about a schema field.defaultalias
annotation.Nr   c                0    || _         || _        d | _        d S Nr   )selfr   r   s      r   __init__zFieldInfo.__init__H   s    
#r   c                     | j         du S )N.r   r$   s    r   is_requiredzFieldInfo.is_requiredM   s    |s""r   .)r   r   r   r   	__slots__r%   r)   r   r   r   r   r   C   sN        ++2I$T $ $ $ $ $
# # # # #r   r   .r!   c                $    t          | |          S )zCreate a field definition.r   r   )r   r-   s     r   Fieldr.   Q   s    WE2222r   c                   (     e Zd ZdZ fdZd Z xZS )r   z$Raised when schema validation fails.c                     || _         d                    d |D                       }t                                          |           d S )Nz; c              3   B   K   | ]}|                     d d          V  dS )msg N)get).0es     r   	<genexpr>z+ValidationError.__init__.<locals>.<genexpr>^   s0      >>aub))>>>>>>r   )_errorsjoinsuperr%   )r$   
error_listmsgs	__class__s      r   r%   zValidationError.__init__\   sH    !yy>>:>>>>>r   c                     | j         S r#   )r8   r(   s    r   errorszValidationError.errorsa   s
    |r   )r   r   r   r   r%   r?   __classcell__r=   s   @r   r   r   Y   sM        ..    
      r   r   c                       e Zd ZdZd ZdS )_ValidatedResultz0Attribute-accessible result from model_validate.c                 :    | j                             |           d S r#   )__dict__update)r$   datas     r   r%   z_ValidatedResult.__init__k   s    T"""""r   N)r   r   r   r   r%   r   r   r   rC   rC   h   s)        ::# # # # #r   rC   c                        e Zd ZU dZdddZeed<   i Zeed<    fdZd Z	e
d	             Ze
d
dd            Zd Z xZS )SchemazFBase class for config validation schemas. Replaces pydantic.BaseModel.allowTextraarbitrary_types_allowedmodel_configmodel_fieldsc           	      r    t                      j        di | i }i }t          | j                  D ](}t	          |di           }|                    |           )|                                D ]\  }}|dv s|                    d          rd}d }	| j        D ]w}
||
j        v rl|
j        |         }t          |t                    r|j        }|j        }	n9t          |t          t          t          t           f          st#          |          s|} nxt          ||	          }||_        |||<   || _        d S )N__annotations__)rN   rO   _.r-   r   )r:   __init_subclass__reversed__mro__getattrrF   items
startswithrE   
isinstancer   r   r   typeclassmethodstaticmethodpropertycallabler    rO   )clskwargsfields	all_hintsbasebase_annotationsnamer    r   r   klassvalfieldr=   s                r   rS   zSchema.__init_subclass__u   sv   !!++F+++	S[)) 	/ 	/D&t->CC-.... ) 1 1 	! 	!D*7774??3;O;O7GE  5>))..C!#y11 *"%+ #	'dKxH  *  (}} *&)GE * gU;;;E)E F4LL!r   c                     | j         j                                        D ]K\  }}||v rt          | |||                    !|                                st          | ||j                   Ld S r#   )r=   rO   rW   setattrr)   r   )r$   r`   re   rh   s       r   r%   zSchema.__init__   s{    >6<<>> 	3 	3KD%v~~dF4L1111&&(( 3dEM222		3 	3r   c                    | j                             d          }t          || j        | j         |          }|rt	          |          t          |          }| j                                        D ]E\  }}|}|j        |j        }n|r ||          }||vr|                                s
|j	        ||<   Ft          |          S )z$Validate a dict against this schema.alias_generator)rN   r4   _validate_schemarO   r   dictrW   r   r)   r   rC   )r_   rG   	alias_genr?   result_datare   rh   data_keys           r   model_validatezSchema.model_validate   s     $(():;;	!$(8#:JIVV 	*!&)))4jj+1133 	6 	6KD%H{& ; +$9T??{**53D3D3F3F*(-H%,,,r   N)configc                n   ddl m} |ddd}t          |          }i }t          j        |          j                                        D ]}|                    |j        |j	                  }|t          j
        j        u rt          }|j        t          j
        j        u rd}n|j        }|j        t          j
        j        k    r||         }|j        t          j
        j        k    rt#          |          }	||	_	        |	||j        <   t%          |j        fd	|id
 |                                D             S )a'  Build a Schema subclass from a function's signature.

        Each parameter becomes a field.  The annotation is used as the type
        (defaulting to ``Any`` when missing) and the default value is
        preserved (parameters without defaults become required fields).

        ``*args`` parameters are wrapped in ``Sequence[annotation]`` and
        stored under the ``VARIABLE_POSITIONAL_ARGS`` field name.

        Forward-reference annotations are resolved via
        ``typing.get_type_hints`` against the function's module namespace.
        r   )SequenceNforbidTrK   .r'   
__config__c                 (    i | ]\  }}||j         |fS r   r    )r5   re   fs      r   
<dictcomp>z(Schema.from_function.<locals>.<dictcomp>   s%    EEE74talA&EEEr   )typingru   resolve_type_hintsinspect	signature
parametersvaluesr4   re   r    	Parameteremptyr   r   kindVAR_POSITIONALVAR_KEYWORDr   create_schemar   rW   )
r_   funcrs   _Seqresolvedra   paramr    r   rh   s
             r   from_functionzSchema.from_function   sQ   & 	,+++++>'DIIF%d++&t,,7>>@@ 	' 	'E!ej%2BCCJW.444 
} 1 777-zW.===!*-
zW.:::g...E)E!&F5:M
 

 FEfllnnEEE
 
 	
r   c                     i }| j         j        D ]T}t          | |          rBt          | |          }t	          |t
                    r|                                ||<   O|||<   U|S )zConvert instance to dict.)r=   rO   hasattrrV   rY   rI   
model_dump)r$   resultre   rg   s       r   r   zSchema.model_dump   sr    N/ 	' 	'DtT"" 'dD))c6** '#&>>#3#3F4LL#&F4Lr   )r   r   r   r   rN   rn   rQ   rO   rS   r%   r[   rr   r   r   r@   rA   s   @r   rI   rI   o   s         PP#*tLLL$LLLL$" " " " ">3 3 3 - - [-$ 
 	-
 -
 -
 -
 [-
^
 
 
 
 
 
 
r   rI   c                    |ddi}i }i }i }|                                 D ]\  }}t          |t                    r>t          |          dk    r+|\  }}	t          |	t                    st	          |	          }	nt          d| d          ||	_        |	||<   |||<   |	                                s
|	j        ||<   ||d}
|
	                    |           t          | t          f|
          }|r|                    d	          nd}|r@t          |          r1|                                 D ]\  }}|j         ||          |_        ||_        |S )
zkDynamically create a Schema subclass.

    Each field value should be a (annotation, FieldInfo) tuple.
    NrL   rJ      r'   zField z& must be (annotation, FieldInfo) tuple)rQ   rN   rl   )rW   rY   tuplelenr   
ValueErrorr    r)   r   rF   rZ   rI   r4   r^   r   rO   )__namerw   ra   	processedannotationsdefaultsre   	field_defr    
field_info	namespacer_   ro   rh   s                 r   r   r      s   
 w'
IKH!<<>> 0 0ii'' 	TC	NNa,?,?%."J
j)44 ;&z:::
RdRRRSSS *
$	$&D%%'' 	0'/HTN '" I X
vy)
,
,C5?I
0111TI .Xi(( .$??,, 	. 	.KD%{"'ioo CJr   c                     	 t          | dd          }|rt          j                            |          nd}|rt	          |          nd}t          | |          S # t          t          t          t          f$ r i cY S w xY w)z|Resolve type hints for a function, handling forward references.

    Falls back to raw annotations if resolution fails.
    r   N)globalns)
rV   sysmodulesr4   varsr   	NameErrorAttributeError	TypeErrorRecursionError)r   mod_namemoduler   s       r   r}   r}     s    

4t44.6@***D#)34<<<tdX6666~y.A   
 			s   AA A<;A<c                     | t           u s	| t          u rdS | t          u rdS | t          u s	| t          u rdS | t
          u s	| t          u rdS dS )z+Get an error type string for an annotation.int_parsingstring_typefloat_parsing	bool_typevalue_error)intr   strfloatr   boolr   ry   s    r   _error_type_forr   /  se    SJ+55}	s		}	u		
k 9 9	t		zZ77{=r   c                     t                      }t          | ||          rdS |j        rt          |j        d                   S | d| S )zqValidate value against a type annotation.

    Returns None if valid, or an error message string if invalid.
    )ctxNr   z does not match )r   _tc2_check_typer?   r   )valuer    r   s      r   validate_typer   <  s[    
 %%Cujc222 t
z "3:a=!!!33z333r   c                    g }|                     dd          }i }t                      }|                                D ]@\  }}	|	j        |	j        }
n|r ||          }
n|}
|                    |
           ||	f||
<   A|dk    r#| D ] }||vr|                    |fddd           !|                                D ]\  }
\  }}	|
| v rL| |
         }t          ||	j                  }|r,|                    |
f|t          |	j                  d           X|		                                r|                    |
fdd	d           |S )
zcValidate a data dict against schema fields.

    Returns list of error dicts (empty if valid).
    rL   rJ   Nrv   zExtra inputs are not permittedextra_forbidden)locr2   rZ   zField requiredmissing)
r4   setrW   r   addappendr   r    r   r)   )rG   ra   rs   rl   r?   
extra_modekey_to_field
known_keysre   rh   rq   keyr   errs                 r   rm   rm   L  s   
 FGW--J LJ||~~ 	/ 	/e;"{HH 	&t,,HHHx   "&X X 	 	C*$$ #v? 1    $0#5#5#7#7  -4tNEu'788C  ({" /0@ A A       	MM$;+%    Mr   _pydantic_cachec                      g } t           |                     t                      t          |                     t                     | rt          |           S t          fS )zReturn the pydantic ValidationError class(es) to catch.

    Tries both pydantic.v1 and pydantic so we catch the right exception
    regardless of which API the caller's model was built with.
    )_PydanticV1ValidationErrorr   _PydanticV2ValidationErrorr   	Exception)r?   s    r   _get_pydantic_validation_errorr     sY     F!-0111!-0111 V}} <r   c                     t          | t                    sdS t          | t                    rdS t          t          | t                    rdS t
          t          | t
                    rdS dS )zCheck if cls is a pydantic BaseModel class (v1 or v2) without hard-depending
    on pydantic. Returns False if pydantic is not installed.FNT)rY   rZ   
issubclassrI   _PydanticV1BaseModel_PydanticV2BaseModelr_   s    r   _is_pydantic_modelr     sm     c4   u#v u'Js<P,Q,Q't'Js<P,Q,Q't5r   c                     t          | d          r|                                 S t          | d          r|                                 S | S )z,Convert a pydantic model instance to a dict.r   rn   )r   r   rn   )objs    r   _pydantic_instance_to_dictr     sI    sL!!  ~~sF xxzzJr   c                    i }t          | d          r| j                                        D ]\  }}|j        }|                                rd}n|j        }|j        }t          |t                    rt          |          rt          |          }|durt          |d          rt          |          }t          ||          }||_        |||<   nt          | d          r| j                                        D ]\  }}|j        }t          |dd          rt           |         }|j        rd}n|j        }|j        |k    r|j        nd}t          |t                    rt          |          rt          |          }|durt          |d          rt          |          }t          ||          }||_        |||<   |S )	zEExtract field definitions from a pydantic BaseModel class (v1 or v2).rO   .r   r-   
__fields__
allow_noneFN)r   rO   rW   r    r)   r   r   rY   rZ   r   ensure_schemar   r   r   outer_type_rV   r   required)pydantic_clsra   re   	pyd_fieldr    r   r   rh   s           r   _extract_pydantic_fieldsr     s    F|^,, +!  ,8>>@@ 	! 	!OD)"-J$$&& ,#+OE*d++ 70B:0N0N 7*:66
c!!gg|&D&D!4W==gU;;;E)E F4LL	!" 
|	,	, !+6<<>> 	! 	!OD)".J y,66 2%j1
! ,#+'0$'>'>IOODE *d++ 70B:0N0N 7*:66
c!!gg|&D&D!4W==gU;;;E)E F4LLMr   c                    ddi}t          | d          rs| j        }t          |dd          }t          |d          r|j        }t	          |t
                    r|nt          |          |d<   t          |d          r
|j        |d<   n>t          | d          r.t	          | j        t                    rt          | j                  }|S )z@Extract model config from a pydantic BaseModel class (v1 or v2).rL   rJ   rw   r   rM   rN   )	r   rw   rV   r   rY   r   rM   rN   rn   )r   rs   cfgrL   s       r   _extract_pydantic_configr     s    wF|\** 1%Wg..5'"" 	 KE#-eS#9#9I%%s5zzw3122 	L030KF,-	~	.	. 1:!44 4 1 l/00Mr   c                    t          | t                    rt          | t                    r| S t	          |           s| S | t
          v rt
          |          S t          |           }t          |           }| t          t          |           t          fi           }||_	        ||_
        t          fd            }||_        |t
          | <   |S )uf  Ensure *schema_cls* satisfies the Schema interface.

    If it already is a Schema subclass, return it unchanged.
    If it is a pydantic BaseModel (v1 or v2), build a thin Schema wrapper
    that exposes the same ``model_fields`` / ``model_config`` and delegates
    ``model_validate`` to the original pydantic class so that pydantic
    validators, strict types, constrained types etc. keep working.

    This allows downstream libraries (spaCy, thinc, …) to keep passing
    pydantic schemas to ``registry.resolve()`` / ``registry.fill()`` even
    though confection itself no longer depends on pydantic.
    c                    t                      }	 t          d          r                    |           n.t          d          r                    |           n di | n/# |$ r'}t	          |                                          d d }~ww xY wt          |          }| j                                        D ]7\  }}|j	        |j	        n|}||vr|
                                s
|j        ||<   8t          |          S )Nrr   	parse_objr   )r   r   rr   r   r   r?   rn   rO   rW   r   r)   r   rC   )	r_   rG   pyd_validation_errr6   rp   re   rh   rq   pyd_clss	           r   _pydantic_model_validatez/ensure_schema.<locals>._pydantic_model_validate$  s2    <==
	w 011  &&t,,,,+..  !!$''''$! 	 	 	!

 	
 4jj+1133 	6 	6KD%&+k&=u{{4H{**53D3D3F3F*(-H%,,,s   AA& &B+"BB)rY   rZ   r   rI   r   r   r   r   pydantic_cls_namerO   rN   r[   rr   )
schema_clsra   rs   wrapperr   r   s        @r   r   r     s     *d## 
:v(F(F j))  _$$z**%j11F%j11F G$Z006)R@@G!G!G - - - - [-0 6G")OJNr   c                 $    t          | dd          S )Nr   PydanticSchema)rV   r   s    r   r   r   C  s    3
$4555r   r*   r#   )-r   r~   r   r|   r   r   r   typecheckerr   r   r   version_infor   r   pydantic.v1r   r   ImportErrorModuleNotFoundErrorpydanticr   r   r   r   r   r   r.   r   rC   rI   r   r}   r   r   rm   r   rn   rQ   r   r   r   r   r   r   r   r   r   r   <module>r      s      



 0 0 0 0 0 0 0 0 0 0       6 6 6 6 6 6
 w!%	*	
 	
 	
 	
 	
 	
	
 	
 	
 	
 	
 	
 	
 ,- * * *#%)"""*	&            	() & & &!%&	 	 	 	 	 	 	 		 	 	 	 	 	 	 		 	 	 	 	 	 	 	# # # # # # # #3 3 3 3 3 3	 	 	 	 	i 	 	 	# # # # # # # #y y y y y y y yx) ) ) )^  *
 
 

4 
4 
4 9 9 9 9|      &    1 1 1h  .> > >B6 6 6 6 6s#   A   AAA A-,A-