U
    Zf;e                     @   s8  d Z ddlmZmZ ddlZddlZddlZddlZddlZddl	m
Z
mZ ddlZdZerdddlZejrteefZneefZG dd deZdd	 Zd
d ZG dd dee
eZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZ G dd deZ!G dd deZ"G dd de"Z#G d d! d!e"Z$G d"d# d#eZ%G d$d% d%eZ&G d&d' d'eZ'G d(d) d)eZ(G d*d+ d+e(Z)G d,d- d-e(Z*G d.d/ d/e(Z+G d0d1 d1e+Z,G d2d3 d3e(Z-G d4d5 d5eZ.G d6d7 d7eZ/G d8d9 d9eZ0G d:d; d;e0Z1G d<d= d=e0Z2dS )>z
Defines classes to represent each Stone type in Python. These classes should
be used to validate Python objects and normalize them for a given type.

The data types defined here should not be specific to an RPC or serialization
format.
    )absolute_importunicode_literalsN)ABCMetaabstractmethodFc                       s:   e Zd ZdZd fdd	Zdd Zdd Zd	d
 Z  ZS )ValidationErrorz=Raised when a value doesn't pass validation by its validator.Nc                    s0   t t| | || _g | _|r,| j| dS )z
        Args:
            message (str): Error message detailing validation failure.
            parent (str): Adds the parent as the closest reference point for
                the error. Use :meth:`add_parent` to add more.
        N)superr   __init__message_parentsappend)selfr	   parent	__class__ O/tmp/pip-unpacked-wheel-vqb3mfeu/stone/backends/python_rsrc/stone_validators.pyr   #   s
    zValidationError.__init__c                 C   s   | j | dS )z
        Args:
            parent (str): Adds the parent to the top of the tree of references
                that lead to the validator that failed.
        N)r
   r   )r   r   r   r   r   
add_parent0   s    zValidationError.add_parentc                 C   s0   | j r&dd| j ddd | jS | jS dS )z
        Returns:
            str: A descriptive message of the validation error that may also
                include the path to the validator that failed.
        z{}: {}.N)r
   formatjoinr	   r   r   r   r   __str__8   s     zValidationError.__str__c                 C   s   dt |  S )NzValidationError(%r))six	text_typer   r   r   r   __repr__C   s    zValidationError.__repr__)N)	__name__
__module____qualname____doc__r   r   r   r   __classcell__r   r   r   r   r       s
   r   c                 C   s   d| j | jf S )Nz%s.%s)r   r   )tr   r   r   type_name_with_moduleH   s    r"   c                 C   sl   t | trdS t | tjrdS t | tjr.dS t | ttfr@dS t | tjrPdS | dkr\dS t	t
| S dS )zReturn a descriptive type name that isn't Python specific. For example,
    an int value will return 'integer' rather than 'int'.booleanintegerfloatliststringNnull)
isinstanceboolnumbersIntegralRealtupler&   r   string_typesr"   type)vr   r   r   generic_type_nameM   s    
r2   c                   @   s0   e Zd ZdZdZedd Zdd Zdd Zd	S )
	ValidatorzDAll primitive and composite data types should be a subclass of this.)Z_redactc                 C   s   dS )zValidates that val is of this data type.

        Returns: A normalized value if validation succeeds.
        Raises: ValidationError
        Nr   r   valr   r   r   validateg   s    zValidator.validatec                 C   s   dS )NFr   r   r   r   r   has_defaulto   s    zValidator.has_defaultc                 C   s   t dd S NzNo default available.)AssertionErrorr   r   r   r   get_defaultr   s    zValidator.get_defaultN)	r   r   r   r   	__slots__r   r6   r7   r:   r   r   r   r   r3   c   s   
r3   c                   @   s   e Zd ZdZdZdS )	Primitivez&A basic type that is defined by Stone.r   Nr   r   r   r   r;   r   r   r   r   r<   v   s   r<   c                   @   s   e Zd ZdZdd ZdS )Booleanr   c                 C   s   t |tstd| |S )Nz%r is not a valid boolean)r)   r*   r   r4   r   r   r   r6   ~   s    
zBoolean.validateN)r   r   r   r;   r6   r   r   r   r   r>   {   s   r>   c                   @   s6   e Zd ZdZdZdZdZd
ddZdd Zdd	 Z	dS )Integerz
    Do not use this class directly. Extend it and specify a 'default_minimum' and
    'default_maximum' value as class variables for a more restrictive integer range.
    minimummaximumNc                 C   s   |dk	r@t |tjstd|| jks8td|| jf || _n| j| _|dk	rt |tjsdtd|| jkstd|| jf || _n| j| _dS )
        A more restrictive minimum or maximum value can be specified than the
        range inherent to the defined type.
        Nz$min_value must be an integral numberzGmin_value cannot be less than the minimum value for this type (%d < %d)z$max_value must be an integral numberzJmax_value cannot be greater than the maximum value for this type (%d < %d))r)   r+   r,   r9   default_minimumrA   default_maximumrB   r   Z	min_valueZ	max_valuer   r   r   r      s,    zInteger.__init__c                 C   sR   t |tjstdt| n0| j|  kr6| jksNn td|| j| jf |S )Nzexpected integer, got %sz%d is not within range [%d, %d])r)   r+   r,   r   r2   rA   rB   r4   r   r   r   r6      s    zInteger.validatec                 C   s   d| j j S Nz%s()r   r   r   r   r   r   r      s    zInteger.__repr__)NN
r   r   r   r   r;   rD   rE   r   r6   r   r   r   r   r   r?      s   
	r?   c                   @   s   e Zd ZdZdZdZdS )Int32r   i   iNr   r   r   r;   rD   rE   r   r   r   r   rJ      s   rJ   c                   @   s   e Zd ZdZdZdZdS )UInt32r   r   l    NrK   r   r   r   r   rL      s   rL   c                   @   s   e Zd ZdZdZdZdS )Int64r   l         l    NrK   r   r   r   r   rM      s   rM   c                   @   s   e Zd ZdZdZdZdS )UInt64r   r   l    NrK   r   r   r   r   rN      s   rN   c                   @   s6   e Zd ZdZdZdZdZd
ddZdd Zdd	 Z	dS )r-   z
    Do not use this class directly. Extend it and optionally set a 'default_minimum'
    and 'default_maximum' value to enforce a range that's a subset of the Python float
    implementation. Python floats are doubles.
    r@   Nc                 C   s  |dk	r~t |tjstdt |tsPzt|}W n tk
rN   tdY nX | jdk	rv|| jk rvtd|| jf || _n| j| _|dk	rt |tjstdt |tszt|}W n tk
r   tdY nX | jdk	r|| jkrtd|| jf || _	n| j| _	dS )rC   Nzmin_value must be a real numberz"min_value is too small for a floatzGmin_value cannot be less than the minimum value for this type (%f < %f)zmax_value must be a real numberz"max_value is too large for a floatzJmax_value cannot be greater than the maximum value for this type (%f < %f))
r)   r+   r-   r9   r%   OverflowErrorrD   rA   rE   rB   rF   r   r   r   r      s<    


zReal.__init__c                 C   s   t |tjstdt| t |tsPzt|}W n tk
rN   tdY nX t|sdt	|rptd| | j
d k	r|| j
k rtd|| j
f | jd k	r|| jkrtd|| jf |S )Nzexpected real number, got %sztoo large for floatz%f values are not supportedz%f is not greater than %fz%f is not less than %f)r)   r+   r-   r   r2   r%   rO   mathisnanisinfrA   rB   r4   r   r   r   r6      s(    
zReal.validatec                 C   s   d| j j S rG   rH   r   r   r   r   r     s    zReal.__repr__)NNrI   r   r   r   r   r-      s   
$r-   c                   @   s(   e Zd ZdZddd  Zddd  ZdS )Float32r   ge18
   &   ge18@NrK   r   r   r   r   rS     s   rS   c                   @   s   e Zd ZdZdS )Float64r   N)r   r   r   r;   r   r   r   r   rV     s   rV   c                   @   s&   e Zd ZdZdZdddZdd ZdS )	StringzRepresents a unicode string.)
min_length
max_lengthpattern
pattern_reNc              
   C   s   |d k	r,t |tjstd|dks,td|d k	rXt |tjsHtd|dksXtd|rp|rp||ksptd|d k	rt |tjstd|| _|| _|| _d | _	|rzt
d| d	 | _	W n: t
jk
r } ztd
||jd W 5 d }~X Y nX d S )N%min_length must be an integral numberr   min_length must be >= 0%max_length must be an integral numbermax_length must be > 0 max_length must be >= min_lengthzpattern must be a stringz\A(?:z)\ZzRegex {!r} failed: {})r)   r+   r,   r9   r   r/   rX   rY   rZ   r[   recompileerrorr   args)r   rX   rY   rZ   er   r   r   r   '  s8     zString.__init__c                 C   s   t |tjs td|t|f tjs\t |tr\z|d}W n tk
rZ   tdY nX | j	dk	rt
|| j	krtd|| j	t
|f | jdk	rt
|| jk rtd|| jt
|f | jr| j|std|| jf |S )z
        A unicode string of the correct length and pattern will pass validation.
        In PY2, we enforce that a str type must be valid utf-8, and a unicode
        string will be returned.
        z$'%s' expected to be a string, got %sutf-8z'%s' was not valid utf-8Nz*'%s' must be at most %d characters, got %dz+'%s' must be at least %d characters, got %dz'%s' did not match pattern '%s')r)   r   r/   r   r2   PY3strdecodeUnicodeDecodeErrorrY   lenrX   rZ   r[   matchr4   r   r   r   r6   B  s,    
zString.validate)NNNr   r   r   r   r;   r   r6   r   r   r   r   rW   #  s   
rW   c                   @   s"   e Zd ZdZdddZdd ZdS )Bytes)rX   rY   Nc                 C   s   |d k	r,t |tjstd|dks,td|d k	rXt |tjsHtd|dksXtd|d k	rx|d k	rx||ksxtd|| _|| _d S )Nr\   r   r]   r^   r_   r`   )r)   r+   r,   r9   rX   rY   )r   rX   rY   r   r   r   r   a  s    zBytes.__init__c                 C   s   t |tstdt| nb| jd k	rNt|| jkrNtd|| jt|f n0| jd k	r~t|| jk r~td|| jt|f |S )Nzexpected bytes type, got %sz''%s' must have at most %d bytes, got %dz$'%s' has fewer than %d bytes, got %d)r)   _binary_typesr   r2   rY   rk   rX   r4   r   r   r   r6   p  s    
zBytes.validate)NN)r   r   r   r;   r   r6   r   r   r   r   rn   ^  s   
rn   c                   @   s$   e Zd ZdZdZdd Zdd ZdS )	TimestampzNote that while a format is specified, it isn't used in validation
    since a native Python datetime object is preferred. The format, however,
    can and should be used by serializers.)r   c                 C   s   t |tjstd|| _dS )zzfmt must be composed of format codes that the C standard (1989)
        supports, most notably in its strftime() function.zformat must be a stringN)r)   r   r   r9   r   )r   fmtr   r   r   r     s    zTimestamp.__init__c                 C   sH   t |tjstdt| n&|jd k	rD|j| dkrDtd|S )Nzexpected timestamp, got %sr   z>timestamp should have either a UTC timezone or none set at all)r)   datetimer   r2   tzinfo	utcoffsettotal_secondsr4   r   r   r   r6     s    
zTimestamp.validateNrm   r   r   r   r   rp   }  s   rp   c                   @   s   e Zd ZdZdZdS )	CompositezLValidator for a type that builds on other primitive and composite
    types.r   Nr=   r   r   r   r   rv     s   rv   c                   @   s&   e Zd ZdZdZdddZdd ZdS )	Listz<Assumes list contents are homogeneous with respect to types.)item_validator	min_items	max_itemsNc                 C   s   || _ |dk	r2t|tjs"td|dks2td|dk	r^t|tjsNtd|dks^td|dk	r~|dk	r~||ks~td|| _|| _dS )z6Every list item will be validated with item_validator.Nz$min_items must be an integral numberr   zmin_items must be >= 0z$max_items must be an integral numberzmax_items must be > 0zmax_items must be >= min_items)rx   r)   r+   r,   r9   ry   rz   )r   rx   ry   rz   r   r   r   r     s    zList.__init__c                    s   t |ttfstd| nV jd k	rHt| jkrHtd| jf n* jd k	rrt| jk rrtd| jf  fdd|D S )Nz%r is not a valid listz%r has more than %s itemsz%r has fewer than %s itemsc                    s   g | ]} j |qS r   )rx   r6   ).0itemr   r   r   
<listcomp>  s     z!List.validate.<locals>.<listcomp>)r)   r.   r&   r   rz   rk   ry   r4   r   r   r   r6     s    zList.validate)NNrm   r   r   r   r   rw     s   
rw   c                   @   s$   e Zd ZdZdZdd Zdd ZdS )MapzBAssumes map keys and values are homogeneous with respect to types.key_validatorvalue_validatorc                 C   s   || _ || _dS )z
        Every Map key/value pair will be validated with item_validator.
        key validators must be a subclass of a String validator
        Nr   )r   r   r   r   r   r   r     s    zMap.__init__c                    s,   t |tstd|  fdd| D S )Nz%r is not a valid dictc                    s&   i | ]\}} j | j|qS r   )r   r6   r   )r{   keyvaluer   r   r   
<dictcomp>  s   
z Map.validate.<locals>.<dictcomp>)r)   dictr   itemsr4   r   r   r   r6     s
    

zMap.validateNrm   r   r   r   r   r~     s   r~   c                       sX   e Zd ZdZ fddZdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Z  ZS )Struct
definitionc                    s   t t|   || _dS )a  
        Args:
            definition (class): A generated class representing a Stone struct
                from a spec. Must have a _fields_ attribute with the following
                structure:

                _fields_ = [(field_name, validator), ...]

                where
                    field_name: Name of the field (str).
                    validator: Validator object.
        N)r   r   r   r   r   r   r   r   r   r     s    zStruct.__init__c                 C   s   |  | | | |S )z}
        For a val to pass validation, val must be of the correct type and have
        all required fields present.
        )validate_type_onlyvalidate_fields_onlyr4   r   r   r   r6     s    

zStruct.validatec                 C   s   |  | | || |S )z
        For a val to pass validation, val must be of the correct type and have
        all required permissioned fields present. Should only be called
        for callers with extra permissions.
        )r6   %validate_fields_only_with_permissions)r   r5   caller_permissionsr   r   r   validate_with_permissions  s    
z Struct.validate_with_permissionsc                 C   s(   | j jD ]}t||std| qdS )ao  
        To pass field validation, no required field should be missing.

        This method assumes that the contents of each field have already been
        validated on assignment, so it's merely a presence check.

        FIXME(kelkabany): Since the definition object does not maintain a list
        of which fields are required, all fields are scanned.
        missing required field '%s'N)r   Z_all_field_names_hasattrr   )r   r5   
field_namer   r   r   r     s
    

zStruct.validate_fields_onlyc                 C   sP   |  | |jD ]:}d|}t| j|t D ]}t||s.td| q.qdS )a"  
        To pass field validation, no required field should be missing.
        This method assumes that the contents of each field have already been
        validated on assignment, so it's merely a presence check.
        Should only be called for callers with extra permissions.
        z_all_{}_field_names_r   N)r   permissionsr   getattrr   setr   r   )r   r5   r   Zextra_permissionZall_field_namesr   r   r   r   r     s    



z,Struct.validate_fields_only_with_permissionsc                 C   s*   t || js&tdt| jt|f dS )z
        Use this when you only want to validate that the type of an object
        is correct, but not yet validate each field.
        zexpected type %s, got %sN)r)   r   r   r"   r2   r4   r   r   r   r     s    	zStruct.validate_type_onlyc                 C   s
   | j j S N)r   _has_required_fieldsr   r   r   r   r7   &  s    zStruct.has_defaultc                 C   s   | j jrtd|   S r8   )r   r   r9   r   r   r   r   r:   )  s    zStruct.get_default)r   r   r   r;   r   r6   r   r   r   r   r7   r:   r    r   r   r   r   r     s   	
r   c                       s$   e Zd ZdZdZ fddZ  ZS )
StructTreezValidator for structs with enumerated subtypes.

    NOTE: validate_fields_only() validates the fields known to this base
    struct, but does not do any validation specific to the subtype.
    r   c                    s   t t| | d S r   )r   r   r   r   r   r   r   r   8  s    zStructTree.__init__)r   r   r   r   r;   r   r    r   r   r   r   r   .  s   r   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	Unionr   c                 C   s
   || _ dS )a  
        Args:
            definition (class): A generated class representing a Stone union
                from a spec. Must have a _tagmap attribute with the following
                structure:

                _tagmap = {field_name: validator, ...}

                where
                    field_name (str): Tag name.
                    validator (Validator): Tag value validator.
        Nr   r   r   r   r   r   ?  s    zUnion.__init__c                 C   s*   |  | t|dr|jdkr&td|S )z
        For a val to pass validation, it must have a _tag set. This assumes
        that the object validated that _tag is a valid tag, and that any
        associated value has also been validated.
        _tagNz
no tag set)r   r   r   r   r4   r   r   r   r6   N  s    
zUnion.validatec                 C   s.   t | jt|s*tdt| jt|f dS )a  
        Use this when you only want to validate that the type of an object
        is correct, but not yet validate each field.

        We check whether val is a Python parent class of the definition. This
        is because Union subtyping works in the opposite direction of Python
        inheritance. For example, if a union U2 extends U1 in Python, this
        validator will accept U1 in places where U2 is expected.
        z#expected type %s or subtype, got %sN)
issubclassr   r0   r   r"   r2   r4   r   r   r   r   Y  s    
zUnion.validate_type_onlyN)r   r   r   r;   r   r6   r   r   r   r   r   r   <  s   r   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	Voidr   c                 C   s   |d k	rt dt| d S )Nzexpected NoneType, got %s)r   r2   r4   r   r   r   r6   o  s    zVoid.validatec                 C   s   dS NTr   r   r   r   r   r7   t  s    zVoid.has_defaultc                 C   s   d S r   r   r   r   r   r   r:   w  s    zVoid.get_defaultN)r   r   r   r;   r6   r7   r:   r   r   r   r   r   l  s   r   c                       s@   e Zd ZdZ fddZdd Zdd Zdd	 Zd
d Z  Z	S )Nullable)	validatorc                    sR   t t|   t|ttfs$tdt|tr6tdt|trHtd|| _d S )Nz3validator must be for a primitive or composite typeznullables cannot be stackedzvoid cannot be made nullable)	r   r   r   r)   r<   rv   r9   r   r   )r   r   r   r   r   r   ~  s    zNullable.__init__c                 C   s   |d krd S | j |S d S r   )r   r6   r4   r   r   r   r6     s    zNullable.validatec                 C   s   |dkrdS | j |S dS )z2Use this only if Nullable is wrapping a Composite.N)r   r   r4   r   r   r   r     s    zNullable.validate_type_onlyc                 C   s   dS r   r   r   r   r   r   r7     s    zNullable.has_defaultc                 C   s   d S r   r   r   r   r   r   r:     s    zNullable.get_default)
r   r   r   r;   r   r6   r   r7   r:   r    r   r   r   r   r   {  s   
r   c                   @   s,   e Zd ZdZdd Zedd Zdd ZdS )	Redactorregexc                 C   s
   || _ dS )zM
        Args:
            regex: What parts of the field to redact.
        Nr   )r   r   r   r   r   r     s    zRedactor.__init__c                 C   s   dS )znRedacts information from annotated field.
        Returns: A redacted version of the string provided.
        Nr   r4   r   r   r   apply  s    zRedactor.applyc                 C   s6   | j s
d S zt| j |W S  tk
r0   Y d S X d S r   )r   ra   search	TypeErrorr4   r   r   r   _get_matches  s    zRedactor._get_matchesN)r   r   r   r;   r   r   r   r   r   r   r   r   r     s
   
r   c                   @   s   e Zd ZdZdd ZdS )HashRedactorr   c              	   C   s   |  |}t|tst|tr&t|n|}zt|d d }W n t	t
gk
rb   d }Y nX |rd| }|rd||S |S |S )Nrf    ***z{} ({}))r   r)   intr%   rh   hashlibmd5encode	hexdigestAttributeError
ValueErrorr   groupsr   )r   r5   matchesZval_to_hashhashedZblottedr   r   r   r     s    
 
zHashRedactor.applyNr   r   r   r;   r   r   r   r   r   r     s   r   c                   @   s   e Zd ZdZdd ZdS )BlotRedactorr   c                 C   s    |  |}|rd| S dS )Nr   z********)r   r   r   )r   r5   r   r   r   r   r     s    
zBlotRedactor.applyNr   r   r   r   r   r     s   r   )3r   
__future__r   r   rr   r   rP   r+   ra   abcr   r   r   Z_MYPYtypingrg   bytes
memoryviewro   buffer	Exceptionr   r"   r2   with_metaclassobjectr3   r<   r>   r?   rJ   rL   rM   rN   r-   rS   rV   rW   rn   rp   rv   rw   r~   r   r   r   r   r   r   r   r   r   r   r   r   <module>   sT   
(	/H;!^0!